private void movieDeletedListener(DatabaseTable obj)
        {
            // This ensures we are thread safe. Makes sure this method is run by
            // the thread that created this panel.
            if (InvokeRequired) {
                Delegate method = new DatabaseManager.ObjectAffectedDelegate(movieDeletedListener);
                object[] parameters = new object[] { obj };
                this.Invoke(method, parameters);
                return;
            }

            // if this is not a movie object, break
            if (obj.GetType() != typeof(DBMovieInfo))
                return;

            // remove movie from list
            DBMovieInfo movie = (DBMovieInfo)obj;
            lock (lockList) {
                if (listItems.ContainsKey(movie)) {
                    listItems[movie].Selected = false;
                    updateMoviePanel();
                    updateFilePanel();

                    movieListBox.Items.Remove(listItems[movie]);
                    listItems.Remove(movie);
                }
            }
        }
        private void movieInsertedListener(DatabaseTable obj)
        {
            // if this is not a movie object, break
            if (obj.GetType() != typeof(DBMovieInfo))
                return;

            // This ensures we are thread safe. Makes sure this method is run by
            // the thread that created this panel.
            if (InvokeRequired) {
                if (!FindForm().Visible) return;
                Delegate method = new DatabaseManager.ObjectAffectedDelegate(movieInsertedListener);
                object[] parameters = new object[] { obj };
                this.Invoke(method, parameters);
                return;
            }

            // add movie to the list
            addMovie((DBMovieInfo)obj);

            bool reassigning = false;
            foreach (DBLocalMedia currFile in processingFiles) {
                if (((DBMovieInfo)obj).LocalMedia.Contains(currFile))
                    reassigning = true;
                else {
                    reassigning = false;
                    break;
                }
            }
            lock (lockList) {
                if (reassigning)
                    listItems[(DBMovieInfo)obj].Selected = true;
            }
        }
        // if a dblocalmedia object is updated and it happens to belong to the currently
        // selected movie, and we are on the file details tab, we need to update.
        private void localMediaUpdatedListener(DatabaseTable obj)
        {
            if (!fileDetailsSubPane.Visible)
                return;

            DBLocalMedia file = obj as DBLocalMedia;
            if (file == null) return;

            // This ensures we are thread safe. Makes sure this method is run by
            // the thread that created this panel.
            if (InvokeRequired) {
                Delegate method = new DatabaseManager.ObjectAffectedDelegate(localMediaUpdatedListener);
                object[] parameters = new object[] { obj };
                this.Invoke(method, parameters);
                return;
            }

            if (file.AttachedMovies.Count > 0) {
                foreach (DBMovieInfo currMovie in file.AttachedMovies) {
                    if (CurrentMovie == currMovie) {
                        updateFilePanel();
                        return;
                    }
                }
            }
        }