/gnome-commander-1.2.8.15/src/gnome-cmd-search-dialog.cc
C++ | 993 lines | 667 code | 209 blank | 117 comment | 81 complexity | b7e797435b9682f840e5f09c420c4b5b MD5 | raw file
Possible License(s): GPL-2.0
- /*
- GNOME Commander - A GNOME based file manager
- Copyright (C) 2001-2006 Marcus Bjurman
- Copyright (C) 2007-2011 Piotr Eljasiak
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include <config.h>
- #include <sys/types.h>
- #include <regex.h>
- #include "gnome-cmd-includes.h"
- #include "gnome-cmd-data.h"
- #include "gnome-cmd-search-dialog.h"
- #include "gnome-cmd-dir.h"
- #include "gnome-cmd-file-list.h"
- #include "gnome-cmd-file-selector.h"
- #include "gnome-cmd-main-win.h"
- #include "filter.h"
- #include "utils.h"
- using namespace std;
- #if 0
- static char *msgs[] = {N_("Search _recursively:"),
- N_("_Unlimited depth"),
- N_("Current _directory only"),
- N_("_Limited depth"),
- // N_("Search local directories only"),
- N_("Files _not containing text")};
- #endif
- static GnomeCmdDialogClass *parent_class = NULL;
- #define PBAR_MAX 50
- #define SEARCH_JUMP_SIZE 4096U
- #define SEARCH_BUFFER_SIZE (SEARCH_JUMP_SIZE * 10U)
- struct ProtectedData
- {
- GList *files;
- gchar *msg;
- GMutex *mutex;
- };
- struct SearchData
- {
- const gchar *name_pattern; // the pattern that file names should match to end up in the file list
- const gchar *content_pattern; // the pattern that the content of a file should match to end up in the file list
- const gchar *dir; // the current dir of the search routine
- Filter *name_filter;
- regex_t *content_regex;
- gboolean content_search; // should we do content search?
- gint matches; // the number of matching files
- gint context_id; // the context id of the status bar
- GnomeCmdSearchDialog *dialog;
- gboolean recurse; // should we recurse or just search in the selected directory?
- gboolean case_sens;
- GList *match_dirs; // the directories which we found matching files in
- GnomeCmdDir *start_dir; // the directory to start searching from
- GThread *thread;
- ProtectedData pdata;
- gint update_gui_timeout_id;
- gboolean search_done;
- gboolean stopped; // stops the search routine if set to TRUE. This is done by the stop_button
- gboolean dialog_destroyed; // set when the search dialog is destroyed, also stops the search of course
- gchar *search_mem; // memory to search in the content of a file
- };
- struct SearchFileData
- {
- gchar *uri_str;
- GnomeVFSHandle *handle;
- gint offset;
- guint len;
- };
- struct GnomeCmdSearchDialogPrivate
- {
- SearchData *data; // holds data needed by the search routines
- GnomeCmdCon *con;
- GtkWidget *pattern_combo;
- GtkWidget *dir_browser;
- GtkWidget *dir_entry;
- GtkWidget *find_text_combo;
- GtkWidget *find_text_check;
- GnomeCmdFileList *result_list;
- GtkWidget *statusbar;
- GtkWidget *help_button;
- GtkWidget *close_button;
- GtkWidget *goto_button;
- GtkWidget *stop_button;
- GtkWidget *search_button;
- GtkWidget *recurse_check;
- GtkWidget *case_check;
- GtkWidget *pbar;
- };
- /**
- * Puts a string in the statusbar.
- *
- */
- inline void set_statusmsg (SearchData *data, gchar *msg)
- {
- if (msg)
- gtk_statusbar_push (GTK_STATUSBAR (data->dialog->priv->statusbar), data->context_id, msg);
- }
- inline void search_file_data_free (SearchFileData *searchfile_data)
- {
- if (searchfile_data->handle)
- gnome_vfs_close (searchfile_data->handle);
- g_free (searchfile_data->uri_str);
- g_free (searchfile_data);
- }
- /**
- * Loads a file in chunks and returns the content.
- */
- static SearchFileData *read_search_file (SearchData *data, SearchFileData *searchfile_data, GnomeCmdFile *f)
- {
- g_return_val_if_fail (f != NULL, NULL);
- g_return_val_if_fail (f->info != NULL, NULL);
- GnomeVFSResult result;
- if (!searchfile_data)
- {
- searchfile_data = g_new0 (SearchFileData, 1);
- searchfile_data->uri_str = gnome_cmd_file_get_uri_str (f);
- result = gnome_vfs_open (&searchfile_data->handle, searchfile_data->uri_str, GNOME_VFS_OPEN_READ);
- if (result != GNOME_VFS_OK)
- {
- warn_print (_("Failed to open file %s: %s\n"), searchfile_data->uri_str, gnome_vfs_result_to_string (result));
- search_file_data_free (searchfile_data);
- return NULL;
- }
- }
- // If the stop button was pressed let's abort here
- if (data->stopped)
- {
- search_file_data_free (searchfile_data);
- return NULL;
- }
- if (searchfile_data->len)
- {
- if ((searchfile_data->offset + searchfile_data->len) >= f->info->size)
- { // end, all has been read
- search_file_data_free (searchfile_data);
- return NULL;
- }
- else
- { // jump a big step backward to give the regex a chance
- searchfile_data->offset += searchfile_data->len - SEARCH_JUMP_SIZE;
- if (f->info->size < (searchfile_data->offset + (SEARCH_BUFFER_SIZE - 1)))
- searchfile_data->len = f->info->size - searchfile_data->offset;
- else
- searchfile_data->len = SEARCH_BUFFER_SIZE - 1;
- }
- }
- else
- { // first time call of this function
- if (f->info->size < (SEARCH_BUFFER_SIZE - 1))
- searchfile_data->len = f->info->size;
- else
- searchfile_data->len = SEARCH_BUFFER_SIZE - 1;
- }
- GnomeVFSFileSize ret;
- result = gnome_vfs_seek (searchfile_data->handle, GNOME_VFS_SEEK_START, searchfile_data->offset);
- if (result != GNOME_VFS_OK)
- {
- warn_print (_("Failed to seek in file %s: %s\n"), searchfile_data->uri_str, gnome_vfs_result_to_string (result));
- search_file_data_free (searchfile_data);
- return NULL;
- }
- result = gnome_vfs_read (searchfile_data->handle, data->search_mem, searchfile_data->len, &ret);
- if (result != GNOME_VFS_OK)
- {
- warn_print (_("Failed to read from file %s: %s\n"), searchfile_data->uri_str, gnome_vfs_result_to_string (result));
- search_file_data_free (searchfile_data);
- return NULL;
- }
- data->search_mem[searchfile_data->len] = '\0';
- return searchfile_data;
- }
- /**
- * Determines if the content of a file matches an regexp
- *
- */
- inline gboolean content_matches (GnomeCmdFile *f, SearchData *data)
- {
- gint ret = REG_NOMATCH;
- if (f->info->size > 0)
- {
- regmatch_t match;
- SearchFileData *search_file = NULL;
- while ((search_file = read_search_file (data, search_file, f)))
- {
- ret = regexec (data->content_regex, data->search_mem, 1, &match, 0);
- // stop on first match
- if (ret != REG_NOMATCH)
- break;
- }
- }
- return ret != REG_NOMATCH;
- }
- /**
- * Determines if the name of a file matches an regexp
- *
- */
- inline gboolean name_matches (gchar *name, SearchData *data)
- {
- return data->name_filter->match(name);
- }
- /**
- * Searches a given directory for files that matches the criteria given by data.
- *
- */
- static void search_dir_r (GnomeCmdDir *dir, SearchData *data)
- {
- if (!dir)
- return;
- // update the search status data
- if (!data->dialog_destroyed)
- {
- g_mutex_lock (data->pdata.mutex);
- gchar *path = gnome_cmd_file_get_path (GNOME_CMD_FILE (dir));
- g_free (data->pdata.msg);
- data->pdata.msg = g_strdup_printf (_("Searching in: %s"), path);
- g_free (path);
- g_mutex_unlock (data->pdata.mutex);
- }
- // If the stop button was pressed let's abort here
- if (data->stopped)
- return;
- GList *files;
- gnome_cmd_dir_list_files (dir, FALSE);
- gnome_cmd_dir_get_files (dir, &files);
- // Let's iterate through all files
- for (GList *tmp=files; tmp; tmp=tmp->next)
- {
- // If the stop button was pressed let's abort here
- if (data->stopped)
- return;
- GnomeCmdFile *f = (GnomeCmdFile *) tmp->data;
- // If the current file is a directory lets continue our recursion
- if (GNOME_CMD_IS_DIR (f) && data->recurse)
- {
- // we don't want to go backwards or follow symlinks
- if (!f->is_dotdot && strcmp (f->info->name, ".") != 0 &&
- !GNOME_VFS_FILE_INFO_SYMLINK (f->info))
- {
- GnomeCmdDir *new_dir = GNOME_CMD_DIR (f);
- if (new_dir)
- {
- gnome_cmd_dir_ref (new_dir);
- search_dir_r (new_dir, data);
- gnome_cmd_dir_unref (new_dir);
- }
- }
- }
- // if the file is a regular one it might match the search criteria
- else
- if (f->info->type == GNOME_VFS_FILE_TYPE_REGULAR)
- {
- // if the name doesn't match lets go to the next file
- if (!name_matches (f->info->name, data))
- continue;
- // if the user wants to we should do some content matching here
- if (data->content_search && !content_matches (f, data))
- continue;
- // the file matched the search criteria, lets add it to the list
- g_mutex_lock (data->pdata.mutex);
- data->pdata.files = g_list_append (data->pdata.files, gnome_cmd_file_ref (f));
- g_mutex_unlock (data->pdata.mutex);
- // also ref each directory that has a matching file
- if (g_list_index (data->match_dirs, dir) == -1)
- {
- gnome_cmd_dir_ref (dir);
- data->match_dirs = g_list_append (data->match_dirs, dir);
- }
- // count the match
- data->matches++;
- }
- }
- }
- static gpointer perform_search_operation (SearchData *data)
- {
- // Unref all directories which contained matching files from last search
- if (data->match_dirs)
- {
- g_list_foreach (data->match_dirs, (GFunc) gnome_cmd_dir_unref, NULL);
- g_list_free (data->match_dirs);
- data->match_dirs = NULL;
- }
- search_dir_r (data->start_dir, data);
- // free regexps
- delete data->name_filter;
- data->name_filter = NULL;
- if (data->content_search)
- {
- regfree (data->content_regex);
- g_free (data->content_regex);
- data->content_regex = NULL;
- }
- gnome_cmd_dir_unref (data->start_dir);
- data->start_dir = NULL;
- data->dir = NULL;
- data->search_done = TRUE;
- return NULL;
- }
- static gboolean update_search_status_widgets (SearchData *data)
- {
- if (data->pdata.mutex)
- g_mutex_lock (data->pdata.mutex);
- // Add all files found since last update to the list
- for (GList *files = data->pdata.files; files; files = files->next)
- data->dialog->priv->result_list->append_file(GNOME_CMD_FILE (files->data));
- if (data->pdata.files)
- {
- gnome_cmd_file_list_free (data->pdata.files);
- data->pdata.files = NULL;
- }
- // Update status bar with the latest message
- set_statusmsg (data, data->pdata.msg);
- // Update the progress bar
- progress_bar_update (data->dialog->priv->pbar, PBAR_MAX);
- if (data->pdata.mutex)
- g_mutex_unlock (data->pdata.mutex);
- if (data->search_done)
- {
- if (!data->dialog_destroyed)
- {
- gchar *msg;
- if (data->stopped)
- msg = g_strdup_printf (
- ngettext("Found %d match - search aborted",
- "Found %d matches - search aborted",
- data->matches),
- data->matches);
- else
- msg = g_strdup_printf (
- ngettext(
- "Found %d match",
- "Found %d matches",
- data->matches),
- data->matches);
- set_statusmsg (data, msg);
- g_free (msg);
- gtk_widget_set_sensitive (data->dialog->priv->goto_button, data->matches > 0);
- gtk_widget_set_sensitive (data->dialog->priv->search_button, TRUE);
- gtk_widget_set_sensitive (data->dialog->priv->stop_button, FALSE);
- // set focus to result list
- gtk_widget_grab_focus (GTK_WIDGET (data->dialog->priv->result_list));
- gtk_widget_hide (data->dialog->priv->pbar);
- }
- // Returning FALSE here stops the timeout callbacks
- return FALSE;
- }
- return TRUE;
- }
- /*
- * This function gets called then the search-dialog is about the be destroyed.
- * The function waits for the last search-thread to finish and then frees the
- * data structure that has been shared between the search threads and the
- * main thread.
- */
- static gboolean join_thread_func (SearchData *data)
- {
- if (data->thread)
- g_thread_join (data->thread);
- if (data->pdata.mutex)
- g_mutex_free (data->pdata.mutex);
- g_free (data->search_mem);
- g_free (data);
- return FALSE;
- }
- static void on_dialog_destroy (GnomeCmdSearchDialog *dialog, gpointer user_data)
- {
- SearchData *data = dialog->priv->data;
- if (data)
- {
- if (!data->search_done)
- g_source_remove (data->update_gui_timeout_id);
- // Stop and wait for search thread to exit
- data->stopped = TRUE;
- data->dialog_destroyed = TRUE;
- g_timeout_add (1, (GSourceFunc) join_thread_func, data);
- // Unref all directories which contained matching files from last search
- if (data->pdata.mutex)
- {
- g_mutex_lock (data->pdata.mutex);
- if (data->match_dirs)
- {
- g_list_foreach (data->match_dirs, (GFunc) gnome_cmd_dir_unref, NULL);
- g_list_free (data->match_dirs);
- data->match_dirs = NULL;
- }
- g_mutex_unlock (data->pdata.mutex);
- }
- }
- }
- static void on_dialog_size_allocate (GtkWidget *widget, GtkAllocation *allocation, GnomeCmdSearchDialog *dialog)
- {
- gnome_cmd_data.search_defaults.width = allocation->width;
- gnome_cmd_data.search_defaults.height = allocation->height;
- }
- static gboolean start_generic_search (GnomeCmdSearchDialog *dialog)
- {
- SearchData *data = dialog->priv->data;
- if (data->thread)
- {
- g_thread_join (data->thread);
- data->thread = NULL;
- }
- data->dialog = dialog;
- data->name_pattern = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->priv->pattern_combo));
- data->content_pattern = gtk_combo_box_get_active_text (GTK_COMBO_BOX (dialog->priv->find_text_combo));
- data->dir = gtk_entry_get_text (GTK_ENTRY (dialog->priv->dir_entry));
- data->context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (data->dialog->priv->statusbar), "info");
- data->content_search = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->find_text_check));
- data->content_regex = NULL;
- data->matches = 0;
- data->match_dirs = NULL;
- data->stopped = FALSE;
- data->dialog_destroyed = FALSE;
- data->recurse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->recurse_check));
- data->case_sens = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->case_check));
- // Save default settings
- gnome_cmd_data.search_defaults.case_sens = data->case_sens;
- gnome_cmd_data.search_defaults.recursive = data->recurse;
- gnome_cmd_data.search_defaults.name_patterns.add(data->name_pattern);
- gnome_cmd_data.search_defaults.directories.add(data->dir);
- if (data->content_search)
- {
- gnome_cmd_data.search_defaults.content_patterns.add(data->content_pattern);
- gnome_cmd_data.intviewer_defaults.text_patterns.add(data->content_pattern);
- }
- dialog->priv->result_list->remove_all_files();
- // create an re for file name matching
- GtkWidget *regex_radio = lookup_widget (GTK_WIDGET (dialog), "regex_radio");
- data->name_filter = new Filter(data->name_pattern, data->case_sens,
- gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (regex_radio)) ? Filter::TYPE_REGEX
- : Filter::TYPE_FNMATCH);
- // if we're going to search through file content create an re for that too
- if (data->content_search)
- {
- data->content_regex = g_new0 (regex_t, 1);
- regcomp (data->content_regex, data->content_pattern, data->case_sens ? 0 : REG_ICASE);
- }
- if (!data->search_mem)
- data->search_mem = (gchar *) g_malloc (SEARCH_BUFFER_SIZE);
- // start the search
- GnomeCmdPath *path = gnome_cmd_con_create_path (dialog->priv->con, data->dir);
- data->start_dir = gnome_cmd_dir_new (dialog->priv->con, path);
- gnome_cmd_dir_ref (data->start_dir);
- data->search_done = FALSE;
- if (!data->pdata.mutex)
- data->pdata.mutex = g_mutex_new ();
- data->thread = g_thread_create ((GThreadFunc) perform_search_operation, data, TRUE, NULL);
- gtk_widget_show (data->dialog->priv->pbar);
- data->update_gui_timeout_id = g_timeout_add (gnome_cmd_data.gui_update_rate, (GSourceFunc) update_search_status_widgets, data);
- return FALSE;
- }
- /**
- * The user has clicked on the search button
- *
- */
- static void on_search (GtkButton *button, GnomeCmdSearchDialog *dialog)
- {
- g_timeout_add (1, (GSourceFunc) start_generic_search, dialog);
- gtk_widget_set_sensitive (dialog->priv->goto_button, FALSE);
- gtk_widget_set_sensitive (dialog->priv->stop_button, TRUE);
- gtk_widget_set_sensitive (dialog->priv->search_button, FALSE);
- }
- /**
- * The user has clicked on the help button
- *
- */
- static void on_help (GtkButton *button, GnomeCmdSearchDialog *dialog)
- {
- gnome_cmd_help_display ("gnome-commander.xml", "gnome-commander-search");
- }
- /**
- * The user has clicked on the close button
- *
- */
- static void on_close (GtkButton *button, GnomeCmdSearchDialog *dialog)
- {
- gtk_widget_destroy (GTK_WIDGET (dialog));
- }
- /**
- * The user has clicked on the stop button
- *
- */
- static void on_stop (GtkButton *button, GnomeCmdSearchDialog *dialog)
- {
- g_return_if_fail (dialog != NULL);
- g_return_if_fail (dialog->priv != NULL);
- g_return_if_fail (dialog->priv->data != NULL);
- dialog->priv->data->stopped = TRUE;
- gtk_widget_set_sensitive (dialog->priv->stop_button, FALSE);
- }
- // The user has clicked on the "go to" button
- static void on_goto (GtkButton *button, GnomeCmdSearchDialog *dialog)
- {
- GnomeCmdFile *f = dialog->priv->result_list->get_selected_file();
- if (!f)
- return;
- gchar *fpath = gnome_cmd_file_get_path (f);
- gchar *dpath = g_path_get_dirname (fpath);
- GnomeCmdFileSelector *fs = gnome_cmd_main_win_get_fs (main_win, ACTIVE);
- fs->goto_directory(dpath);
- fs->file_list()->focus_file(gnome_cmd_file_get_name (f), TRUE);
- g_free (fpath);
- g_free (dpath);
- gtk_widget_destroy (GTK_WIDGET (dialog));
- }
- inline gboolean handle_list_keypress (GnomeCmdFileList *fl, GdkEventKey *event, GnomeCmdSearchDialog *dialog)
- {
- switch (event->keyval)
- {
- case GDK_F3:
- gnome_cmd_file_list_view (fl, -1);
- return TRUE;
- case GDK_F4:
- gnome_cmd_file_list_edit (fl);
- return TRUE;
- }
- return FALSE;
- }
- static gboolean on_list_keypressed (GtkWidget *result_list, GdkEventKey *event, gpointer dialog)
- {
- if (GNOME_CMD_FILE_LIST (result_list)->key_pressed(event) ||
- handle_list_keypress (GNOME_CMD_FILE_LIST (result_list), event, GNOME_CMD_SEARCH_DIALOG (dialog)))
- {
- stop_kp (GTK_OBJECT (result_list));
- return TRUE;
- }
- return FALSE;
- }
- // The user has clicked on the "search by content" checkbutton.
- static void find_text_toggled (GtkToggleButton *togglebutton, GnomeCmdSearchDialog *dialog)
- {
- if (gtk_toggle_button_get_active (togglebutton))
- {
- gtk_widget_set_sensitive (dialog->priv->find_text_combo, TRUE);
- gtk_widget_grab_focus (dialog->priv->find_text_combo);
- }
- else
- gtk_widget_set_sensitive (dialog->priv->find_text_combo, FALSE);
- }
- /*******************************
- * Gtk class implementation
- *******************************/
- static void destroy (GtkObject *object)
- {
- GnomeCmdSearchDialog *dialog = GNOME_CMD_SEARCH_DIALOG (object);
- g_free (dialog->priv);
- dialog->priv = NULL;
- if (GTK_OBJECT_CLASS (parent_class)->destroy)
- (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
- }
- static void map (GtkWidget *widget)
- {
- if (GTK_WIDGET_CLASS (parent_class)->map != NULL)
- GTK_WIDGET_CLASS (parent_class)->map (widget);
- }
- static void class_init (GnomeCmdSearchDialogClass *klass)
- {
- GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- parent_class = (GnomeCmdDialogClass *) gtk_type_class (gnome_cmd_dialog_get_type ());
- object_class->destroy = destroy;
- widget_class->map = ::map;
- }
- /*
- * create a label with keyboard shortcut and a widget to activate if shortcut is pressed.
- */
- inline GtkWidget *create_label_with_mnemonic (GtkWidget *parent, const gchar *text, GtkWidget *for_widget)
- {
- GtkWidget *label = gtk_label_new_with_mnemonic (text);
- if (for_widget)
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), for_widget);
- gtk_widget_ref (label);
- gtk_object_set_data_full (GTK_OBJECT (parent), "label", label, (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_show (label);
- gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
- return label;
- }
- /*
- * create a check_box_button with keyboard shortcut
- */
- inline GtkWidget *create_check_with_mnemonic (GtkWidget *parent, gchar *text, gchar *name)
- {
- GtkWidget *btn = gtk_check_button_new_with_mnemonic (text);
- gtk_widget_ref (btn);
- gtk_object_set_data_full (GTK_OBJECT (parent), name, btn, (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_show (btn);
- return btn;
- }
- /*
- * create a GtkRadioButton with keyboard shortcut
- */
- inline GtkWidget *create_radio_with_mnemonic (GtkWidget *parent, GSList *group, gchar *text, gchar *name)
- {
- GtkWidget *radio = gtk_radio_button_new_with_mnemonic (group, text);
- gtk_widget_ref (radio);
- gtk_object_set_data_full (GTK_OBJECT (parent), name, radio, (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_show (radio);
- return radio;
- }
- /*
- * create a gtk_combo_box_entry_new_text. gtk_combo is deprecated.
- */
- inline GtkWidget *create_combo_box_entry (GtkWidget *parent)
- {
- GtkWidget *combo = gtk_combo_box_entry_new_text ();
- gtk_widget_ref (combo);
- gtk_object_set_data_full (GTK_OBJECT (parent), "combo", combo, (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_show (combo);
- return combo;
- }
- /*
- * callback function for 'g_list_foreach' to add default value to dropdownbox
- */
- static void combo_box_insert_text (gpointer data, gpointer user_data)
- {
- gtk_combo_box_append_text (GTK_COMBO_BOX (user_data), (gchar *) data);
- }
- static void init (GnomeCmdSearchDialog *dialog)
- {
- GnomeCmdData::SearchConfig &defaults = gnome_cmd_data.search_defaults;
- GtkWidget *window;
- GtkWidget *vbox;
- GtkWidget *hbox;
- GtkWidget *table;
- GtkWidget *label;
- GtkWidget *sw;
- GtkWidget *radio;
- GtkWidget *pbar;
- dialog->priv = g_new0 (GnomeCmdSearchDialogPrivate, 1);
- dialog->priv->data = g_new0 (SearchData, 1);
- window = GTK_WIDGET (dialog);
- gtk_object_set_data (GTK_OBJECT (window), "window", window);
- gtk_window_set_title (GTK_WINDOW (window), _("Search..."));
- gnome_cmd_dialog_set_resizable (GNOME_CMD_DIALOG (dialog), TRUE);
- gtk_window_set_default_size (GTK_WINDOW (window), defaults.width, defaults.height);
- vbox = create_vbox (window, FALSE, 0);
- gnome_cmd_dialog_add_expanding_category (GNOME_CMD_DIALOG (dialog), vbox);
- table = create_table (window, 5, 2);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
- // Search for
- dialog->priv->pattern_combo = create_combo_box_entry (window);
- label = create_label_with_mnemonic (window, _("Search _for: "), dialog->priv->pattern_combo);
- table_add (table, label, 0, 0, GTK_FILL);
- table_add (table, dialog->priv->pattern_combo, 1, 0, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL));
- if (!defaults.name_patterns.empty())
- g_list_foreach (defaults.name_patterns.ents, combo_box_insert_text, dialog->priv->pattern_combo);
- gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->pattern_combo), 0);
- gnome_cmd_dialog_editable_enters (GNOME_CMD_DIALOG (dialog), GTK_EDITABLE (gtk_bin_get_child (GTK_BIN (dialog->priv->pattern_combo))));
- // Search in
- dialog->priv->dir_browser = create_file_entry (window, "dir_browser", "");
- label = create_label_with_mnemonic (window, _("Search _in: "), dialog->priv->dir_browser);
- table_add (table, label, 0, 1, GTK_FILL);
- table_add (table, dialog->priv->dir_browser, 1, 1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL));
- if (!defaults.directories.empty())
- gtk_combo_set_popdown_strings (
- GTK_COMBO (gnome_file_entry_gnome_entry (GNOME_FILE_ENTRY (dialog->priv->dir_browser))),
- defaults.directories.ents);
- dialog->priv->dir_entry = gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (dialog->priv->dir_browser));
- hbox = create_hbox (window, FALSE, 0);
- // Recurse check
- dialog->priv->recurse_check = create_check_with_mnemonic (window, _("Search _recursively"), "recurse_check");
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->recurse_check), defaults.recursive);
- gtk_box_pack_start (GTK_BOX (hbox), dialog->priv->recurse_check, FALSE, FALSE, 0);
- // File name matching
- radio = create_radio_with_mnemonic (window, NULL, _("Rege_x syntax"), "regex_radio");
- gtk_box_pack_end (GTK_BOX (hbox), radio, FALSE, FALSE, 12);
- if (gnome_cmd_data.filter_type == Filter::TYPE_REGEX)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
- radio = create_radio_with_mnemonic (window, get_radio_group (radio), _("She_ll syntax"), "shell_radio");
- gtk_box_pack_end (GTK_BOX (hbox), radio, FALSE, FALSE, 12);
- if (gnome_cmd_data.filter_type == Filter::TYPE_FNMATCH)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
- table_add (table, hbox, 1, 2, GTK_FILL);
- // Find text
- dialog->priv->find_text_check = create_check_with_mnemonic (window, _("Find _text: "), "find_text");
- table_add (table, dialog->priv->find_text_check, 0, 3, GTK_FILL);
- dialog->priv->find_text_combo = create_combo_box_entry (window);
- table_add (table, dialog->priv->find_text_combo, 1, 3, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL));
- gtk_widget_set_sensitive (dialog->priv->find_text_combo, FALSE);
- if (!defaults.content_patterns.empty())
- g_list_foreach (defaults.content_patterns.ents, combo_box_insert_text, dialog->priv->find_text_combo);
- gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->find_text_combo), 0);
- gnome_cmd_dialog_editable_enters (GNOME_CMD_DIALOG (dialog), GTK_EDITABLE (gtk_bin_get_child (GTK_BIN (dialog->priv->find_text_combo))));
- // Case check
- dialog->priv->case_check = create_check_with_mnemonic (window, _("Case sensiti_ve"), "case_check");
- gtk_table_attach (GTK_TABLE (table), dialog->priv->case_check, 1, 2, 4, 5,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->case_check), defaults.case_sens);
- dialog->priv->help_button = gnome_cmd_dialog_add_button (GNOME_CMD_DIALOG (dialog), GTK_STOCK_HELP, GTK_SIGNAL_FUNC (on_help), dialog);
- dialog->priv->close_button = gnome_cmd_dialog_add_button (GNOME_CMD_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_SIGNAL_FUNC (on_close), dialog);
- dialog->priv->goto_button = gnome_cmd_dialog_add_button (GNOME_CMD_DIALOG (dialog), _("_Go to"), GTK_SIGNAL_FUNC (on_goto), dialog);
- dialog->priv->stop_button = gnome_cmd_dialog_add_button (GNOME_CMD_DIALOG (dialog), GTK_STOCK_STOP, GTK_SIGNAL_FUNC (on_stop), dialog);
- dialog->priv->search_button = gnome_cmd_dialog_add_button (GNOME_CMD_DIALOG (dialog), GTK_STOCK_FIND, GTK_SIGNAL_FUNC (on_search), dialog);
- gtk_widget_set_sensitive (dialog->priv->stop_button, FALSE);
- gtk_widget_set_sensitive (dialog->priv->goto_button, FALSE);
- sw = gtk_scrolled_window_new (NULL, NULL);
- gtk_widget_ref (sw);
- gtk_object_set_data_full (GTK_OBJECT (window), "sw", sw, (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_show (sw);
- gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- dialog->priv->result_list = new GnomeCmdFileList;
- gtk_widget_ref (GTK_WIDGET (dialog->priv->result_list));
- gtk_object_set_data_full (GTK_OBJECT (window), "result_list", GTK_WIDGET (dialog->priv->result_list), (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_set_size_request (GTK_WIDGET (dialog->priv->result_list), -1, 200);
- gtk_widget_show (GTK_WIDGET (dialog->priv->result_list));
- gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (dialog->priv->result_list));
- gtk_container_set_border_width (GTK_CONTAINER (dialog->priv->result_list), 4);
- dialog->priv->statusbar = gtk_statusbar_new ();
- gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (dialog->priv->statusbar), FALSE);
- gtk_widget_ref (dialog->priv->statusbar);
- gtk_object_set_data_full (GTK_OBJECT (window), "statusbar", dialog->priv->statusbar,
- (GtkDestroyNotify) gtk_widget_unref);
- gtk_widget_show (dialog->priv->statusbar);
- gtk_box_pack_start (GTK_BOX (vbox), dialog->priv->statusbar, FALSE, TRUE, 0);
- pbar = create_progress_bar (window);
- gtk_widget_hide (pbar);
- gtk_progress_set_show_text (GTK_PROGRESS (pbar), FALSE);
- gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), TRUE);
- gtk_progress_configure (GTK_PROGRESS (pbar), 0, 0, PBAR_MAX);
- gtk_box_pack_start (GTK_BOX (dialog->priv->statusbar), pbar, FALSE, TRUE, 0);
- dialog->priv->pbar = pbar;
- g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK (on_dialog_destroy), NULL);
- g_signal_connect (G_OBJECT (dialog), "size-allocate", G_CALLBACK (on_dialog_size_allocate), NULL);
- g_signal_connect (G_OBJECT (dialog->priv->result_list), "key-press-event", G_CALLBACK (on_list_keypressed), dialog);
- gtk_signal_connect (GTK_OBJECT (dialog->priv->find_text_check), "toggled", GTK_SIGNAL_FUNC (find_text_toggled), dialog);
- gtk_window_set_keep_above (GTK_WINDOW (dialog), FALSE);
- gtk_widget_grab_focus (dialog->priv->pattern_combo);
- dialog->priv->result_list->update_style();
- }
- /***********************************
- * Public functions
- ***********************************/
- GtkType gnome_cmd_search_dialog_get_type ()
- {
- static GtkType dlg_type = 0;
- if (dlg_type == 0)
- {
- GtkTypeInfo dlg_info =
- {
- "GnomeCmdSearchDialog",
- sizeof (GnomeCmdSearchDialog),
- sizeof (GnomeCmdSearchDialogClass),
- (GtkClassInitFunc) class_init,
- (GtkObjectInitFunc) init,
- /* reserved_1 */ NULL,
- /* reserved_2 */ NULL,
- (GtkClassInitFunc) NULL
- };
- dlg_type = gtk_type_unique (gnome_cmd_dialog_get_type (), &dlg_info);
- }
- return dlg_type;
- }
- GtkWidget *gnome_cmd_search_dialog_new (GnomeCmdDir *default_dir)
- {
- gchar *new_path;
- GnomeCmdSearchDialog *dialog = (GnomeCmdSearchDialog *) gtk_type_new (gnome_cmd_search_dialog_get_type ());
- gchar *path = gnome_cmd_dir_is_local (default_dir) ? gnome_cmd_file_get_real_path (GNOME_CMD_FILE (default_dir)) : gnome_cmd_file_get_path (GNOME_CMD_FILE (default_dir));
- if (path[strlen(path)-1] != '/')
- {
- new_path = g_strdup_printf ("%s/", path);
- g_free (path);
- }
- else
- new_path = path;
- gtk_entry_set_text (GTK_ENTRY (dialog->priv->dir_entry), new_path);
- g_free (new_path);
- dialog->priv->con = gnome_cmd_dir_get_connection (default_dir);
- return GTK_WIDGET (dialog);
- }