summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@src.gnome.org>2005-12-12 16:59:19 +0000
committerAlexander Larsson <alexl@src.gnome.org>2005-12-12 16:59:19 +0000
commit671e4bdaa4d07b039015bedfcb5d42026e5d099e (patch)
tree7e983d1089740a57bc6e8848219aa3032c4e9056 /src
parentf03608b0904ed20850e7ba49d397a7d41330a298 (diff)
downloadnautilus-671e4bdaa4d07b039015bedfcb5d42026e5d099e.tar.gz
--- Merged the nautilus-search2 branch ---
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/file-manager/fm-actions.h2
-rw-r--r--src/file-manager/fm-directory-view.c508
-rw-r--r--src/file-manager/fm-directory-view.h23
-rw-r--r--src/file-manager/fm-error-reporting.c35
-rw-r--r--src/file-manager/fm-error-reporting.h1
-rw-r--r--src/file-manager/fm-icon-view.c75
-rw-r--r--src/file-manager/fm-list-model.c381
-rw-r--r--src/file-manager/fm-list-model.h22
-rw-r--r--src/file-manager/fm-list-view.c112
-rw-r--r--src/file-manager/fm-properties-window.c9
-rw-r--r--src/file-manager/nautilus-directory-view-ui.xml2
-rw-r--r--src/nautilus-actions.h1
-rw-r--r--src/nautilus-history-sidebar.c2
-rw-r--r--src/nautilus-location-bar.c17
-rw-r--r--src/nautilus-location-entry.c54
-rw-r--r--src/nautilus-location-entry.h2
-rw-r--r--src/nautilus-navigation-window-menus.c16
-rw-r--r--src/nautilus-navigation-window-ui.xml4
-rw-r--r--src/nautilus-navigation-window.c257
-rw-r--r--src/nautilus-navigation-window.h4
-rw-r--r--src/nautilus-query-editor.c1141
-rw-r--r--src/nautilus-query-editor.h70
-rw-r--r--src/nautilus-search-bar.c218
-rw-r--r--src/nautilus-search-bar.h61
-rw-r--r--src/nautilus-spatial-window-ui.xml1
-rw-r--r--src/nautilus-spatial-window.c108
-rw-r--r--src/nautilus-window-manage-views.c63
-rw-r--r--src/nautilus-window-menus.c3
-rw-r--r--src/nautilus-window-private.h5
-rw-r--r--src/nautilus-window.c36
-rw-r--r--src/nautilus-window.h9
32 files changed, 2826 insertions, 420 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3e19e7b5a..4a2c4c83e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -99,6 +99,10 @@ nautilus_SOURCES = \
nautilus-places-sidebar.h \
nautilus-property-browser.c \
nautilus-property-browser.h \
+ nautilus-query-editor.c \
+ nautilus-query-editor.h \
+ nautilus-search-bar.c \
+ nautilus-search-bar.h \
nautilus-self-check-functions.c \
nautilus-self-check-functions.h \
nautilus-shell.c \
diff --git a/src/file-manager/fm-actions.h b/src/file-manager/fm-actions.h
index a9128537b..761591ed9 100644
--- a/src/file-manager/fm-actions.h
+++ b/src/file-manager/fm-actions.h
@@ -36,6 +36,8 @@
#define FM_ACTION_SELF_PROPERTIES "SelfProperties"
#define FM_ACTION_NO_TEMPLATES "No Templates"
#define FM_ACTION_EMPTY_TRASH "Empty Trash"
+#define FM_ACTION_SAVE_SEARCH "Save Search"
+#define FM_ACTION_SAVE_SEARCH_AS "Save Search As"
#define FM_ACTION_CUT "Cut"
#define FM_ACTION_LOCATION_CUT "LocationCut"
#define FM_ACTION_COPY "Copy"
diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c
index 8b97f5b83..b612491a8 100644
--- a/src/file-manager/fm-directory-view.c
+++ b/src/file-manager/fm-directory-view.c
@@ -57,7 +57,9 @@
#include <gtk/gtkselection.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkstock.h>
+#include <gtk/gtktable.h>
#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkfilechooserbutton.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtktoggleaction.h>
#include <gtk/gtkentry.h>
@@ -78,10 +80,12 @@
#include <libnautilus-private/nautilus-clipboard-monitor.h>
#include <libnautilus-private/nautilus-desktop-icon-file.h>
#include <libnautilus-private/nautilus-desktop-directory.h>
+#include <libnautilus-private/nautilus-search-directory.h>
#include <libnautilus-private/nautilus-directory-background.h>
#include <libnautilus-private/nautilus-directory.h>
#include <libnautilus-private/nautilus-dnd.h>
#include <libnautilus-private/nautilus-file-attributes.h>
+#include <libnautilus-private/nautilus-file-changes-queue.h>
#include <libnautilus-private/nautilus-file-dnd.h>
#include <libnautilus-private/nautilus-file-operations.h>
#include <libnautilus-private/nautilus-file-utilities.h>
@@ -89,6 +93,7 @@
#include <libnautilus-private/nautilus-global-preferences.h>
#include <libnautilus-private/nautilus-icon-factory.h>
#include <libnautilus-private/nautilus-link.h>
+#include <libnautilus-private/nautilus-marshal.h>
#include <libnautilus-private/nautilus-metadata.h>
#include <libnautilus-private/nautilus-mime-actions.h>
#include <libnautilus-private/nautilus-module.h>
@@ -270,6 +275,8 @@ struct FMDirectoryViewDetails
GList *subdirectory_list;
+ gboolean allow_moves;
+
GdkPoint context_menu_position;
};
@@ -295,6 +302,11 @@ typedef struct {
gboolean cancelled;
} ActivateParameters;
+typedef struct {
+ NautilusFile *file;
+ NautilusDirectory *directory;
+} FileAndDirectory;
+
enum {
GNOME_COPIED_FILES,
UTF8_STRING
@@ -450,6 +462,79 @@ typedef struct {
} CreateTemplateParameters;
+
+static GList *
+file_and_directory_list_to_files (GList *fad_list)
+{
+ GList *res, *l;
+ FileAndDirectory *fad;
+
+ res = NULL;
+ for (l = fad_list; l != NULL; l = l->next) {
+ fad = l->data;
+ res = g_list_prepend (res, nautilus_file_ref (fad->file));
+ }
+ return g_list_reverse (res);
+}
+
+
+static GList *
+file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
+{
+ GList *res, *l;
+ FileAndDirectory *fad;
+
+ res = NULL;
+ for (l = files; l != NULL; l = l->next) {
+ fad = g_new0 (FileAndDirectory, 1);
+ fad->directory = nautilus_directory_ref (directory);
+ fad->file = nautilus_file_ref (l->data);
+ res = g_list_prepend (res, fad);
+ }
+ return g_list_reverse (res);
+}
+
+static void
+file_and_directory_free (FileAndDirectory *fad)
+{
+ nautilus_directory_unref (fad->directory);
+ nautilus_file_unref (fad->file);
+ g_free (fad);
+}
+
+
+static void
+file_and_directory_list_free (GList *list)
+{
+ GList *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ file_and_directory_free (l->data);
+ }
+}
+
+static gboolean
+file_and_directory_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ const FileAndDirectory *fad1, *fad2;
+ fad1 = v1;
+ fad2 = v2;
+
+ return (fad1->file == fad2->file &&
+ fad1->directory == fad2->directory);
+}
+
+static guint
+file_and_directory_hash (gconstpointer v)
+{
+ const FileAndDirectory *fad;
+
+ fad = v;
+ return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
+}
+
+
static ApplicationLaunchParameters *
application_launch_parameters_new (GnomeVFSMimeApplication *application,
NautilusFile *file,
@@ -1133,6 +1218,130 @@ action_show_hidden_files_callback (GtkAction *action,
}
static void
+action_save_search_callback (GtkAction *action,
+ gpointer callback_data)
+{
+ NautilusSearchDirectory *search;
+ FMDirectoryView *directory_view;
+
+ directory_view = FM_DIRECTORY_VIEW (callback_data);
+
+ if (directory_view->details->model &&
+ NAUTILUS_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
+ search = NAUTILUS_SEARCH_DIRECTORY (directory_view->details->model);
+ nautilus_search_directory_save_search (search);
+
+ /* Save search is disabled */
+ schedule_update_menus (directory_view);
+ }
+}
+
+static void
+query_name_entry_changed_cb (GtkWidget *entry, GtkWidget *button)
+{
+ const char *text;
+ gboolean sensitive;
+
+ text = gtk_entry_get_text (GTK_ENTRY (entry));
+
+ sensitive = (text != NULL) && (*text != 0);
+
+ gtk_widget_set_sensitive (button, sensitive);
+}
+
+
+static void
+action_save_search_as_callback (GtkAction *action,
+ gpointer callback_data)
+{
+ FMDirectoryView *directory_view;
+ NautilusSearchDirectory *search;
+ NautilusQuery *query;
+ GtkWidget *dialog, *table, *label, *entry, *chooser, *save_button;
+ const char *entry_text;
+ char *filename, *filename_utf8, *dirname, *path, *uri;
+
+ directory_view = FM_DIRECTORY_VIEW (callback_data);
+
+ if (directory_view->details->model &&
+ NAUTILUS_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
+ search = NAUTILUS_SEARCH_DIRECTORY (directory_view->details->model);
+
+ query = nautilus_search_directory_get_query (search);
+
+ dialog = gtk_dialog_new_with_buttons (_("Save search"),
+ fm_directory_view_get_containing_window (directory_view),
+ GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NULL);
+ save_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dialog)->vbox), table);
+ gtk_widget_show (table);
+
+ label = gtk_label_new (_("Query name:"));
+ gtk_table_attach_defaults (GTK_TABLE (table), label,
+ 0, 1, 0, 1);
+ gtk_widget_show (label);
+ entry = gtk_entry_new ();
+ gtk_table_attach_defaults (GTK_TABLE (table), entry,
+ 1, 2, 0, 1);
+
+ gtk_widget_set_sensitive (save_button, FALSE);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (query_name_entry_changed_cb), save_button);
+
+ gtk_widget_show (entry);
+ label = gtk_label_new (_("Folder:"));
+ gtk_table_attach_defaults (GTK_TABLE (table), label,
+ 0, 1, 1, 2);
+ gtk_widget_show (label);
+
+ chooser = gtk_file_chooser_button_new (_("Select folder to save search in"),
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
+ gtk_table_attach_defaults (GTK_TABLE (table), chooser,
+ 1, 2, 1, 2);
+ gtk_widget_show (chooser);
+
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
+
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
+ g_get_home_dir ());
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (g_str_has_suffix (entry_text, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
+ filename_utf8 = g_strdup (entry_text);
+ } else {
+ filename_utf8 = g_strconcat (entry_text, NAUTILUS_SAVED_SEARCH_EXTENSION, NULL);
+ }
+
+ filename = g_filename_from_utf8 (filename_utf8, -1, NULL, NULL, NULL);
+ g_free (filename_utf8);
+
+ dirname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
+
+ path = g_build_filename (dirname, filename, NULL);
+ g_free (filename);
+ g_free (dirname);
+
+ uri = gnome_vfs_get_uri_from_local_path (path);
+ g_free (path);
+
+ nautilus_search_directory_save_to_file (search, uri);
+ nautilus_file_changes_queue_file_added (uri);
+ nautilus_file_changes_consume_changes (TRUE);
+ g_free (uri);
+ }
+
+ gtk_widget_destroy (dialog);
+ }
+}
+
+
+static void
action_empty_trash_callback (GtkAction *action,
gpointer callback_data)
{
@@ -1663,7 +1872,11 @@ fm_directory_view_init (FMDirectoryView *view)
view->details = g_new0 (FMDirectoryViewDetails, 1);
- view->details->non_ready_files = g_hash_table_new (NULL, NULL);
+ view->details->non_ready_files =
+ g_hash_table_new_full (file_and_directory_hash,
+ file_and_directory_equal,
+ (GDestroyNotify)file_and_directory_free,
+ NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
GTK_POLICY_AUTOMATIC,
@@ -2023,6 +2236,12 @@ fm_directory_view_send_selection_change (FMDirectoryView *view)
view->details->send_selection_change_to_shell = FALSE;
}
+gboolean
+fm_directory_view_get_allow_moves (FMDirectoryView *view)
+{
+ return view->details->allow_moves;
+}
+
static void
fm_directory_view_load_location (NautilusView *nautilus_view,
const char *location)
@@ -2032,6 +2251,12 @@ fm_directory_view_load_location (NautilusView *nautilus_view,
directory_view = FM_DIRECTORY_VIEW (nautilus_view);
+ if (eel_uri_is_search (location)) {
+ directory_view->details->allow_moves = FALSE;
+ } else {
+ directory_view->details->allow_moves = TRUE;
+ }
+
directory = nautilus_directory_get (location);
load_directory (directory_view, directory);
nautilus_directory_unref (directory);
@@ -2152,6 +2377,7 @@ debuting_uri_data_free (DebutingUriData *data)
static void
debuting_uri_add_file_callback (FMDirectoryView *view,
NautilusFile *new_file,
+ NautilusDirectory *directory,
DebutingUriData *data)
{
char *uri;
@@ -2159,7 +2385,7 @@ debuting_uri_add_file_callback (FMDirectoryView *view,
uri = nautilus_file_get_uri (new_file);
if (g_hash_table_remove (data->debuting_uris, uri)) {
- g_object_ref (new_file);
+ nautilus_file_ref (new_file);
data->added_files = g_list_prepend (data->added_files, new_file);
if (g_hash_table_size (data->debuting_uris) == 0) {
@@ -2190,7 +2416,7 @@ copy_move_done_data_free (CopyMoveDoneData *data)
}
static void
-pre_copy_move_add_file_callback (FMDirectoryView *view, NautilusFile *new_file, CopyMoveDoneData *data)
+pre_copy_move_add_file_callback (FMDirectoryView *view, NautilusFile *new_file, NautilusDirectory *directory, CopyMoveDoneData *data)
{
g_object_ref (new_file);
data->added_files = g_list_prepend (data->added_files, new_file);
@@ -2326,29 +2552,21 @@ copy_move_done_callback (GHashTable *debuting_uris, gpointer data)
}
static gboolean
-real_file_still_belongs (FMDirectoryView *view, NautilusFile *file)
+real_file_still_belongs (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
- GList *node;
-
- if (nautilus_directory_contains_file (view->details->model, file)) {
- return TRUE;
- }
-
- for (node = view->details->subdirectory_list; node != NULL; node = node->next) {
- if (nautilus_directory_contains_file (NAUTILUS_DIRECTORY (node->data),
- file)) {
- return TRUE;
- }
+ if (view->details->model != directory &&
+ g_list_find (view->details->subdirectory_list, directory) == NULL) {
+ return FALSE;
}
- return FALSE;
+ return nautilus_directory_contains_file (directory, file);
}
static gboolean
-still_should_show_file (FMDirectoryView *view, NautilusFile *file)
+still_should_show_file (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
return fm_directory_view_should_show_file (view, file)
- && EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, file_still_belongs, (view, file));
+ && EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, file_still_belongs, (view, file, directory));
}
static gboolean
@@ -2357,6 +2575,31 @@ ready_to_load (NautilusFile *file)
return nautilus_icon_factory_is_icon_ready_for_file (file);
}
+static int
+compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data)
+{
+ const FileAndDirectory *fad1, *fad2;
+ FMDirectoryView *view;
+
+ view = callback_data;
+ fad1 = a; fad2 = b;
+
+ if (fad1->directory < fad2->directory) {
+ return -1;
+ } else if (fad1->directory > fad2->directory) {
+ return 1;
+ } else {
+ return EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, compare_files,
+ (view, fad1->file, fad2->file));
+ }
+}
+static void
+sort_files (FMDirectoryView *view, GList **list)
+{
+ *list = g_list_sort_with_data (*list, compare_files_cover, view);
+
+}
+
/* Go through all the new added and changed files.
* Put any that are not ready to load in the non_ready_files hash table.
* Add all the rest to the old_added_files and old_changed_files lists.
@@ -2367,8 +2610,8 @@ process_new_files (FMDirectoryView *view)
{
GList *new_added_files, *new_changed_files, *old_added_files, *old_changed_files;
GHashTable *non_ready_files;
- GList *node;
- NautilusFile *file;
+ GList *node, *next;
+ FileAndDirectory *pending;
gboolean in_non_ready;
new_added_files = view->details->new_added_files;
@@ -2384,56 +2627,54 @@ process_new_files (FMDirectoryView *view)
/* Newly added files go into the old_added_files list if they're
* ready, and into the hash table if they're not.
*/
- for (node = new_added_files; node != NULL; node = node->next) {
- file = NAUTILUS_FILE (node->data);
- in_non_ready = g_hash_table_lookup (non_ready_files, file) != NULL;
- if (fm_directory_view_should_show_file (view, file)) {
- if (ready_to_load (file)) {
+ for (node = new_added_files; node != NULL; node = next) {
+ next = node->next;
+ pending = (FileAndDirectory *)node->data;
+ in_non_ready = g_hash_table_lookup (non_ready_files, pending) != NULL;
+ if (fm_directory_view_should_show_file (view, pending->file)) {
+ if (ready_to_load (pending->file)) {
if (in_non_ready) {
- g_hash_table_remove (non_ready_files, file);
- nautilus_file_unref (file);
+ g_hash_table_remove (non_ready_files, pending);
}
- nautilus_file_ref (file);
- old_added_files = g_list_prepend (old_added_files, file);
+ new_added_files = g_list_delete_link (new_added_files, node);
+ old_added_files = g_list_prepend (old_added_files, pending);
} else {
if (!in_non_ready) {
- nautilus_file_ref (file);
- g_hash_table_insert (non_ready_files, file, file);
+ new_added_files = g_list_delete_link (new_added_files, node);
+ g_hash_table_insert (non_ready_files, pending, pending);
}
}
}
}
- nautilus_file_list_free (new_added_files);
+ file_and_directory_list_free (new_added_files);
/* Newly changed files go into the old_added_files list if they're ready
* and were seen non-ready in the past, into the old_changed_files list
* if they are read and were not seen non-ready in the past, and into
* the hash table if they're not ready.
*/
- for (node = new_changed_files; node != NULL; node = node->next) {
- file = NAUTILUS_FILE (node->data);
- if (!still_should_show_file (view, file) || ready_to_load (file)) {
- if (g_hash_table_lookup (non_ready_files, file) != NULL) {
- g_hash_table_remove (non_ready_files, file);
- nautilus_file_unref (file);
- if (still_should_show_file (view, file)) {
- nautilus_file_ref (file);
- old_added_files = g_list_prepend (old_added_files, file);
+ for (node = new_changed_files; node != NULL; node = next) {
+ next = node->next;
+ pending = (FileAndDirectory *)node->data;
+ if (!still_should_show_file (view, pending->file, pending->directory) || ready_to_load (pending->file)) {
+ if (g_hash_table_lookup (non_ready_files, pending) != NULL) {
+ g_hash_table_remove (non_ready_files, pending);
+ if (still_should_show_file (view, pending->file, pending->directory)) {
+ new_changed_files = g_list_delete_link (new_changed_files, node);
+ old_added_files = g_list_prepend (old_added_files, pending);
}
- } else if (fm_directory_view_should_show_file(view, file)) {
- nautilus_file_ref (file);
- old_changed_files = g_list_prepend
- (old_changed_files, file);
+ } else if (fm_directory_view_should_show_file (view, pending->file)) {
+ new_changed_files = g_list_delete_link (new_changed_files, node);
+ old_changed_files = g_list_prepend (old_changed_files, pending);
}
}
}
- nautilus_file_list_free (new_changed_files);
+ file_and_directory_list_free (new_changed_files);
/* If any files were added to old_added_files, then resort it. */
if (old_added_files != view->details->old_added_files) {
view->details->old_added_files = old_added_files;
- EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, sort_files,
- (view, &view->details->old_added_files));
+ sort_files (view, &view->details->old_added_files);
}
/* Resort old_changed_files too, since file attributes
@@ -2441,8 +2682,7 @@ process_new_files (FMDirectoryView *view)
*/
if (old_changed_files != view->details->old_changed_files) {
view->details->old_changed_files = old_changed_files;
- EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, sort_files,
- (view, &view->details->old_changed_files));
+ sort_files (view, &view->details->old_changed_files);
}
}
@@ -2451,8 +2691,8 @@ static void
process_old_files (FMDirectoryView *view)
{
GList *files_added, *files_changed, *node;
- NautilusFile *file;
- GList *selection;
+ FileAndDirectory *pending;
+ GList *selection, *files;
gboolean send_selection_change;
files_added = view->details->old_added_files;
@@ -2464,37 +2704,34 @@ process_old_files (FMDirectoryView *view)
g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0);
for (node = files_added; node != NULL; node = node->next) {
- file = NAUTILUS_FILE (node->data);
+ pending = node->data;
g_signal_emit (view,
- signals[ADD_FILE], 0, file);
+ signals[ADD_FILE], 0, pending->file, pending->directory);
}
for (node = files_changed; node != NULL; node = node->next) {
- file = NAUTILUS_FILE (node->data);
-
+ pending = node->data;
g_signal_emit (view,
- signals[still_should_show_file (view, file)
+ signals[still_should_show_file (view, pending->file, pending->directory)
? FILE_CHANGED : REMOVE_FILE], 0,
- file);
+ pending->file, pending->directory);
}
g_signal_emit (view, signals[END_FILE_CHANGES], 0);
if (files_changed != NULL) {
selection = fm_directory_view_get_selection (view);
+ files = file_and_directory_list_to_files (files_changed);
send_selection_change = eel_g_lists_sort_and_check_for_intersection
- (&files_changed, &selection);
+ (&files, &selection);
+ nautilus_file_list_free (files);
nautilus_file_list_free (selection);
}
-
- nautilus_file_list_free (view->details->old_added_files);
+
+ file_and_directory_list_free (view->details->old_added_files);
view->details->old_added_files = NULL;
- /* We free files_changed here instead of view->details->old_changed_files
- * because the call to eel_g_lists_sort_and_check_for_intersection might
- * change the first element, and so we might lose files to free.
- */
- nautilus_file_list_free (files_changed);
+ file_and_directory_list_free (view->details->old_changed_files);
view->details->old_changed_files = NULL;
}
@@ -2675,6 +2912,7 @@ unschedule_display_of_pending_files (FMDirectoryView *view)
static void
queue_pending_files (FMDirectoryView *view,
+ NautilusDirectory *directory,
GList *files,
GList **pending_list)
{
@@ -2698,10 +2936,12 @@ queue_pending_files (FMDirectoryView *view,
}
}
- *pending_list = g_list_concat (nautilus_file_list_copy (files),
+
+
+ *pending_list = g_list_concat (file_and_directory_list_from_files (directory, files),
*pending_list);
- if (! view->details->loading || nautilus_directory_are_all_files_seen (view->details->model)) {
+ if (! view->details->loading || nautilus_directory_are_all_files_seen (directory)) {
schedule_timeout_display_of_pending_files (view, view->details->update_interval);
}
}
@@ -2786,7 +3026,7 @@ files_added_callback (NautilusDirectory *directory,
schedule_changes (view);
- queue_pending_files (view, files, &view->details->new_added_files);
+ queue_pending_files (view, directory, files, &view->details->new_added_files);
/* The number of items could have changed */
schedule_update_status (view);
@@ -2798,12 +3038,12 @@ files_changed_callback (NautilusDirectory *directory,
gpointer callback_data)
{
FMDirectoryView *view;
-
+
view = FM_DIRECTORY_VIEW (callback_data);
schedule_changes (view);
- queue_pending_files (view, files, &view->details->new_changed_files);
+ queue_pending_files (view, directory, files, &view->details->new_changed_files);
/* The free space or the number of items could have changed */
schedule_update_status (view);
@@ -2836,6 +3076,7 @@ done_loading_callback (NautilusDirectory *directory,
static void
load_error_callback (NautilusDirectory *directory,
GnomeVFSResult load_error_code,
+ const char *load_error_message,
gpointer callback_data)
{
FMDirectoryView *view;
@@ -2851,11 +3092,11 @@ load_error_callback (NautilusDirectory *directory,
* occurred, so they can handle it in the UI.
*/
g_signal_emit (view,
- signals[LOAD_ERROR], 0, load_error_code);
+ signals[LOAD_ERROR], 0, load_error_code, load_error_message);
}
static void
-real_load_error (FMDirectoryView *view, GnomeVFSResult result)
+real_load_error (FMDirectoryView *view, GnomeVFSResult result, const char *error_message)
{
g_assert (result != GNOME_VFS_OK);
@@ -2868,30 +3109,12 @@ real_load_error (FMDirectoryView *view, GnomeVFSResult result)
if (!view->details->reported_load_error) {
fm_report_error_loading_directory
(fm_directory_view_get_directory_as_file (view),
- result,
+ result, error_message,
fm_directory_view_get_containing_window (view));
}
view->details->reported_load_error = TRUE;
}
-/**
- * fm_directory_queue_notice_file_change
- *
- * Called by a subclass to put a file into the queue of files to update.
- * This is only necessary when the subclass is monitoring files other than
- * the ones in the directory for this location.
- */
-void
-fm_directory_view_queue_file_change (FMDirectoryView *view, NautilusFile *file)
-{
- GList singleton_list;
-
- singleton_list.data = file;
- singleton_list.next = NULL;
- singleton_list.prev = NULL;
- queue_pending_files (view, &singleton_list, &view->details->new_changed_files);
-}
-
void
fm_directory_view_add_subdirectory (FMDirectoryView *view,
NautilusDirectory*directory)
@@ -2908,7 +3131,7 @@ fm_directory_view_add_subdirectory (FMDirectoryView *view,
NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE |
NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME |
NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO;
-
+
nautilus_directory_file_monitor_add (directory,
&view->details->model,
view->details->show_hidden_files,
@@ -2929,7 +3152,7 @@ fm_directory_view_add_subdirectory (FMDirectoryView *view,
void
fm_directory_view_remove_subdirectory (FMDirectoryView *view,
- NautilusDirectory*directory)
+ NautilusDirectory*directory)
{
g_assert (g_list_find (view->details->subdirectory_list, directory));
@@ -3733,7 +3956,8 @@ typedef struct {
static void
-track_newly_added_uris (FMDirectoryView *view, NautilusFile *new_file, gpointer user_data)
+track_newly_added_uris (FMDirectoryView *view, NautilusFile *new_file,
+ NautilusDirectory *directory, gpointer user_data)
{
NewFolderData *data;
@@ -3752,7 +3976,7 @@ new_folder_done (const char *new_folder_uri, gpointer user_data)
NewFolderData *data;
data = (NewFolderData *)user_data;
-
+
directory_view = data->directory_view;
if (directory_view == NULL) {
@@ -3792,6 +4016,7 @@ new_folder_done (const char *new_folder_uri, gpointer user_data)
(GClosureNotify)g_free,
G_CONNECT_AFTER);
}
+ nautilus_file_unref (file);
fail:
g_hash_table_destroy (data->added_uris);
@@ -6416,6 +6641,14 @@ static const GtkActionEntry directory_view_entries[] = {
N_("Open File and Close window"), "<alt><shift>Down", /* label, accelerator */
NULL, /* tooltip */
G_CALLBACK (action_open_close_parent_callback) },
+ { "Save Search", NULL, /* name, stock id */
+ N_("Sa_ve Search"), NULL, /* label, accelerator */
+ N_("Save the edited search"), /* tooltip */
+ G_CALLBACK (action_save_search_callback) },
+ { "Save Search As", NULL, /* name, stock id */
+ N_("Sa_ve Search As..."), NULL, /* label, accelerator */
+ N_("Save the current search as a file"), /* tooltip */
+ G_CALLBACK (action_save_search_as_callback) },
/* Location-specific actions */
{ FM_ACTION_LOCATION_OPEN_ALTERNATE, NULL, /* name, stock id */
@@ -6947,6 +7180,9 @@ real_update_menus (FMDirectoryView *view)
gboolean vfolder_directory;
gboolean show_open_alternate;
gboolean can_open;
+ gboolean show_save_search;
+ gboolean save_search_sensitive;
+ gboolean show_save_search_as;
ActivationAction activation_action;
GtkAction *action;
@@ -7119,6 +7355,30 @@ real_update_menus (FMDirectoryView *view)
gtk_action_set_sensitive (action, !nautilus_trash_monitor_is_empty ());
gtk_action_set_visible (action, should_show_empty_trash (view));
+ show_save_search = FALSE;
+ save_search_sensitive = FALSE;
+ show_save_search_as = FALSE;
+ if (view->details->model &&
+ NAUTILUS_IS_SEARCH_DIRECTORY (view->details->model)) {
+ NautilusSearchDirectory *search;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (view->details->model);
+ if (nautilus_search_directory_is_saved_search (search)) {
+ show_save_search = TRUE;
+ save_search_sensitive = nautilus_search_directory_is_modified (search);
+ } else {
+ show_save_search_as = TRUE;
+ }
+ }
+ action = gtk_action_group_get_action (view->details->dir_action_group,
+ FM_ACTION_SAVE_SEARCH);
+ gtk_action_set_visible (action, show_save_search);
+ gtk_action_set_sensitive (action, save_search_sensitive);
+ action = gtk_action_group_get_action (view->details->dir_action_group,
+ FM_ACTION_SAVE_SEARCH_AS);
+ gtk_action_set_visible (action, show_save_search_as);
+
+
action = gtk_action_group_get_action (view->details->dir_action_group,
FM_ACTION_SELECT_ALL);
gtk_action_set_sensitive (action, !fm_directory_view_is_empty (view));
@@ -8334,9 +8594,8 @@ fm_directory_view_reveal_selection (FMDirectoryView *view)
}
static gboolean
-unref_key_and_remove (gpointer key, gpointer value, gpointer callback_data)
+remove_all (gpointer key, gpointer value, gpointer callback_data)
{
- nautilus_file_unref (key);
return TRUE;
}
@@ -8356,14 +8615,14 @@ fm_directory_view_stop (FMDirectoryView *view)
reset_update_interval (view);
/* Free extra undisplayed files */
- nautilus_file_list_free (view->details->new_added_files);
+ file_and_directory_list_free (view->details->new_added_files);
view->details->new_added_files = NULL;
- nautilus_file_list_free (view->details->new_changed_files);
+ file_and_directory_list_free (view->details->new_changed_files);
view->details->new_changed_files = NULL;
- g_hash_table_foreach_remove (view->details->non_ready_files, unref_key_and_remove, NULL);
- nautilus_file_list_free (view->details->old_added_files);
+ g_hash_table_foreach_remove (view->details->non_ready_files, remove_all, NULL);
+ file_and_directory_list_free (view->details->old_added_files);
view->details->old_added_files = NULL;
- nautilus_file_list_free (view->details->old_changed_files);
+ file_and_directory_list_free (view->details->old_changed_files);
view->details->old_changed_files = NULL;
eel_g_list_free_deep (view->details->pending_uris_selected);
view->details->pending_uris_selected = NULL;
@@ -8394,11 +8653,29 @@ fm_directory_view_is_empty (FMDirectoryView *view)
is_empty, (view));
}
+gboolean
+fm_directory_view_is_editable (FMDirectoryView *view)
+{
+ NautilusDirectory *directory;
+
+ directory = fm_directory_view_get_model (view);
+
+ if (directory != NULL) {
+ return nautilus_directory_is_editable (directory);
+ }
+
+ return TRUE;
+}
+
static gboolean
real_is_read_only (FMDirectoryView *view)
{
NautilusFile *file;
-
+
+ if (!fm_directory_view_is_editable (view)) {
+ return TRUE;
+ }
+
file = fm_directory_view_get_directory_as_file (view);
if (file != NULL) {
return !nautilus_file_can_write (file);
@@ -8453,7 +8730,7 @@ real_accepts_dragged_files (FMDirectoryView *view)
{
g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
- return TRUE;
+ return !fm_directory_view_is_read_only (view);
}
gboolean
@@ -9085,10 +9362,6 @@ fm_directory_view_handle_text_drop (FMDirectoryView *view,
}
-static void
-real_sort_files (FMDirectoryView *view, GList **files)
-{
-}
static GArray *
real_get_selected_icon_locations (FMDirectoryView *view)
@@ -9180,8 +9453,8 @@ fm_directory_view_class_init (FMDirectoryViewClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (FMDirectoryViewClass, add_file),
NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, NAUTILUS_TYPE_FILE);
+ nautilus_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY);
signals[BEGIN_FILE_CHANGES] =
g_signal_new ("begin_file_changes",
G_TYPE_FROM_CLASS (klass),
@@ -9236,24 +9509,24 @@ fm_directory_view_class_init (FMDirectoryViewClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (FMDirectoryViewClass, file_changed),
NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, NAUTILUS_TYPE_FILE);
+ nautilus_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY);
signals[LOAD_ERROR] =
g_signal_new ("load_error",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (FMDirectoryViewClass, load_error),
NULL, NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
+ nautilus_marshal_VOID__INT_STRING,
+ G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_STRING);
signals[REMOVE_FILE] =
g_signal_new ("remove_file",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (FMDirectoryViewClass, remove_file),
NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, NAUTILUS_TYPE_FILE);
+ nautilus_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY);
klass->accepts_dragged_files = real_accepts_dragged_files;
klass->file_limit_reached = real_file_limit_reached;
@@ -9262,7 +9535,6 @@ fm_directory_view_class_init (FMDirectoryViewClass *klass)
klass->get_selected_icon_locations = real_get_selected_icon_locations;
klass->is_read_only = real_is_read_only;
klass->load_error = real_load_error;
- klass->sort_files = real_sort_files;
klass->can_rename_file = can_rename_file;
klass->start_renaming_file = start_renaming_file;
klass->supports_creating_files = real_supports_creating_files;
diff --git a/src/file-manager/fm-directory-view.h b/src/file-manager/fm-directory-view.h
index 1b0d602fa..db08a6d84 100644
--- a/src/file-manager/fm-directory-view.h
+++ b/src/file-manager/fm-directory-view.h
@@ -76,16 +76,19 @@ struct FMDirectoryViewClass {
* It must be replaced by each subclass.
*/
void (* add_file) (FMDirectoryView *view,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
void (* remove_file) (FMDirectoryView *view,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
/* The 'file_changed' signal is emitted to signal a change in a file,
* including the file being removed.
* It must be replaced by each subclass.
*/
void (* file_changed) (FMDirectoryView *view,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
/* The 'end_file_changes' signal is emitted after a set of files
* are added to the view. It can be replaced by a subclass to do any
@@ -118,7 +121,8 @@ struct FMDirectoryViewClass {
* load failures like ACCESS_DENIED.
*/
void (* load_error) (FMDirectoryView *view,
- GnomeVFSResult result);
+ GnomeVFSResult result,
+ const char *error_message);
/* Function pointers that don't have corresponding signals */
@@ -213,8 +217,9 @@ struct FMDirectoryViewClass {
* to provide a sorting order to determine which files should be
* presented when only a partial list is provided.
*/
- void (* sort_files) (FMDirectoryView *view,
- GList **files);
+ int (* compare_files) (FMDirectoryView *view,
+ NautilusFile *a,
+ NautilusFile *b);
/* get_emblem_names_to_exclude is a function pointer that subclasses
* may override to specify a set of emblem names that should not
@@ -290,7 +295,8 @@ struct FMDirectoryViewClass {
gboolean select_all);
gboolean (* file_still_belongs) (FMDirectoryView *view,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
/* Preference change callbacks, overriden by icon and list views.
* Icon and list views respond by synchronizing to the new preference
@@ -382,6 +388,7 @@ NautilusDirectory *fm_directory_view_get_model (FMDirect
GtkWindow *fm_directory_view_get_containing_window (FMDirectoryView *view);
NautilusFile *fm_directory_view_get_directory_as_file (FMDirectoryView *view);
EelBackground * fm_directory_view_get_background (FMDirectoryView *view);
+gboolean fm_directory_view_get_allow_moves (FMDirectoryView *view);
void fm_directory_view_pop_up_background_context_menu (FMDirectoryView *view,
GdkEventButton *event);
void fm_directory_view_pop_up_selection_context_menu (FMDirectoryView *view,
@@ -420,4 +427,6 @@ void fm_directory_view_add_subdirectory (FMDirecto
void fm_directory_view_remove_subdirectory (FMDirectoryView *view,
NautilusDirectory*directory);
+gboolean fm_directory_view_is_editable (FMDirectoryView *view);
+
#endif /* FM_DIRECTORY_VIEW_H */
diff --git a/src/file-manager/fm-error-reporting.c b/src/file-manager/fm-error-reporting.c
index e2a1c7d16..789d591cb 100644
--- a/src/file-manager/fm-error-reporting.c
+++ b/src/file-manager/fm-error-reporting.c
@@ -41,31 +41,36 @@ static void cancel_rename (NautilusFile *file);
void
fm_report_error_loading_directory (NautilusFile *file,
GnomeVFSResult error,
+ const char *error_message,
GtkWindow *parent_window)
{
char *file_name;
char *message;
- if (error == GNOME_VFS_OK) {
+ if (error_message == NULL && error == GNOME_VFS_OK) {
return;
}
file_name = nautilus_file_get_display_name (file);
- switch (error) {
- case GNOME_VFS_ERROR_ACCESS_DENIED:
- message = g_strdup_printf (_("You do not have the permissions necessary to view the contents of \"%s\"."),
- file_name);
- break;
- case GNOME_VFS_ERROR_NOT_FOUND:
- message = g_strdup_printf (_("\"%s\" couldn't be found. Perhaps it has recently been deleted."),
- file_name);
- break;
- default:
- /* We should invent decent error messages for every case we actually experience. */
- g_warning ("Hit unhandled case %d (%s) in fm_report_error_loading_directory",
- error, gnome_vfs_result_to_string (error));
- message = g_strdup_printf (_("Sorry, couldn't display all the contents of \"%s\"."), file_name);
+ if (!error_message) {
+ switch (error) {
+ case GNOME_VFS_ERROR_ACCESS_DENIED:
+ message = g_strdup_printf (_("You do not have the permissions necessary to view the contents of \"%s\"."),
+ file_name);
+ break;
+ case GNOME_VFS_ERROR_NOT_FOUND:
+ message = g_strdup_printf (_("\"%s\" couldn't be found. Perhaps it has recently been deleted."),
+ file_name);
+ break;
+ default:
+ /* We should invent decent error messages for every case we actually experience. */
+ g_warning ("Hit unhandled case %d (%s) in fm_report_error_loading_directory",
+ error, gnome_vfs_result_to_string (error));
+ message = g_strdup_printf (_("Sorry, couldn't display all the contents of \"%s\"."), file_name);
+ }
+ } else {
+ message = g_strdup (error_message);
}
eel_show_error_dialog (_("The folder contents could not be displayed."), message, parent_window);
diff --git a/src/file-manager/fm-error-reporting.h b/src/file-manager/fm-error-reporting.h
index a1b44bf66..a4665a3fb 100644
--- a/src/file-manager/fm-error-reporting.h
+++ b/src/file-manager/fm-error-reporting.h
@@ -32,6 +32,7 @@
void fm_report_error_loading_directory (NautilusFile *file,
GnomeVFSResult error_code,
+ const char *error_message,
GtkWindow *parent_window);
void fm_report_error_renaming_file (NautilusFile *file,
const char *new_name,
diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c
index 5c849c0d2..8ad26b810 100644
--- a/src/file-manager/fm-icon-view.c
+++ b/src/file-manager/fm-icon-view.c
@@ -508,8 +508,10 @@ should_show_file_on_screen (FMDirectoryView *view, NautilusFile *file)
}
static void
-fm_icon_view_remove_file (FMDirectoryView *view, NautilusFile *file)
+fm_icon_view_remove_file (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
+ g_assert (directory == fm_directory_view_get_model (view));
+
if (nautilus_icon_container_remove (get_icon_container (FM_ICON_VIEW (view)),
NAUTILUS_ICON_CONTAINER_ICON_DATA (file))) {
nautilus_file_unref (file);
@@ -517,10 +519,12 @@ fm_icon_view_remove_file (FMDirectoryView *view, NautilusFile *file)
}
static void
-fm_icon_view_add_file (FMDirectoryView *view, NautilusFile *file)
+fm_icon_view_add_file (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
FMIconView *icon_view;
NautilusIconContainer *icon_container;
+
+ g_assert (directory == fm_directory_view_get_model (view));
icon_view = FM_ICON_VIEW (view);
icon_container = get_icon_container (icon_view);
@@ -549,10 +553,12 @@ fm_icon_view_flush_added_files (FMDirectoryView *view)
}
static void
-fm_icon_view_file_changed (FMDirectoryView *view, NautilusFile *file)
+fm_icon_view_file_changed (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
FMIconView *icon_view;
+ g_assert (directory == fm_directory_view_get_model (view));
+
g_return_if_fail (view != NULL);
icon_view = FM_ICON_VIEW (view);
@@ -564,7 +570,7 @@ fm_icon_view_file_changed (FMDirectoryView *view, NautilusFile *file)
}
if (!should_show_file_on_screen (view, file)) {
- fm_icon_view_remove_file (view, file);
+ fm_icon_view_remove_file (view, file, directory);
} else {
nautilus_icon_container_request_update
@@ -1055,6 +1061,9 @@ fm_icon_view_begin_loading (FMDirectoryView *view)
file = fm_directory_view_get_directory_as_file (view);
icon_container = GTK_WIDGET (get_icon_container (icon_view));
+ nautilus_icon_container_set_allow_moves (NAUTILUS_ICON_CONTAINER (icon_container),
+ fm_directory_view_get_allow_moves (view));
+
/* kill any sound preview process that is ongoing */
preview_audio (icon_view, NULL, FALSE);
@@ -1533,6 +1542,7 @@ fm_icon_view_update_menus (FMDirectoryView *view)
int selection_count;
GtkAction *action;
NautilusIconContainer *icon_container;
+ gboolean editable;
icon_view = FM_ICON_VIEW (view);
@@ -1559,8 +1569,13 @@ fm_icon_view_update_menus (FMDirectoryView *view)
gtk_action_set_sensitive (action,
icon_container != NULL
&& nautilus_icon_container_is_stretched (icon_container));
-
+
nautilus_file_list_free (selection);
+
+ editable = fm_directory_view_is_editable (view);
+ action = gtk_action_group_get_action (icon_view->details->icon_action_group,
+ FM_ACTION_MANUAL_LAYOUT);
+ gtk_action_set_sensitive (action, editable);
}
static void
@@ -2004,6 +2019,15 @@ fm_icon_view_compare_files (FMIconView *icon_view,
icon_view->details->sort_reversed);
}
+static int
+compare_files (FMDirectoryView *icon_view,
+ NautilusFile *a,
+ NautilusFile *b)
+{
+ return fm_icon_view_compare_files ((FMIconView *)icon_view, a, b);
+}
+
+
void
fm_icon_view_filter_by_screen (FMIconView *icon_view,
gboolean filter)
@@ -2019,6 +2043,7 @@ fm_icon_view_screen_changed (GtkWidget *widget,
FMDirectoryView *view;
GList *files, *l;
NautilusFile *file;
+ NautilusDirectory *directory;
NautilusIconContainer *icon_container;
if (GTK_WIDGET_CLASS (fm_icon_view_parent_class)->screen_changed) {
@@ -2028,14 +2053,15 @@ fm_icon_view_screen_changed (GtkWidget *widget,
view = FM_DIRECTORY_VIEW (widget);
if (FM_ICON_VIEW (view)->details->filter_by_screen) {
icon_container = get_icon_container (FM_ICON_VIEW (view));
-
- files = nautilus_directory_get_file_list (fm_directory_view_get_model (view));
+
+ directory = fm_directory_view_get_model (view);
+ files = nautilus_directory_get_file_list (directory);
for (l = files; l != NULL; l = l->next) {
file = l->data;
if (!should_show_file_on_screen (view, file)) {
- fm_icon_view_remove_file (view, file);
+ fm_icon_view_remove_file (view, file, directory);
} else {
if (nautilus_icon_container_add (icon_container,
NAUTILUS_ICON_CONTAINER_ICON_DATA (file),
@@ -2050,27 +2076,6 @@ fm_icon_view_screen_changed (GtkWidget *widget,
}
}
-
-static int
-compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data)
-{
- return fm_icon_view_compare_files (callback_data,
- NAUTILUS_FILE (a),
- NAUTILUS_FILE (b));
-}
-
-static void
-fm_icon_view_sort_files (FMDirectoryView *view, GList **files)
-{
- FMIconView *icon_view;
-
- icon_view = FM_ICON_VIEW (view);
- if (!fm_icon_view_using_auto_layout (icon_view)) {
- return;
- }
- *files = g_list_sort_with_data (*files, compare_files_cover, icon_view);
-}
-
static void
selection_changed_callback (NautilusIconContainer *container,
FMIconView *icon_view)
@@ -2568,7 +2573,9 @@ icon_view_scroll_to_file (NautilusView *view,
icon_view = FM_ICON_VIEW (view);
if (uri != NULL) {
- file = nautilus_file_get (uri);
+ /* Only if existing, since we don't want to add the file to
+ the directory if it has been removed since then */
+ file = nautilus_file_get_existing (uri);
if (file != NULL) {
nautilus_icon_container_scroll_to_icon (get_icon_container (icon_view),
NAUTILUS_ICON_CONTAINER_ICON_DATA (file));
@@ -2613,7 +2620,7 @@ fm_icon_view_class_init (FMIconViewClass *klass)
fm_directory_view_class->reveal_selection = fm_icon_view_reveal_selection;
fm_directory_view_class->select_all = fm_icon_view_select_all;
fm_directory_view_class->set_selection = fm_icon_view_set_selection;
- fm_directory_view_class->sort_files = fm_icon_view_sort_files;
+ fm_directory_view_class->compare_files = compare_files;
fm_directory_view_class->zoom_to_level = fm_icon_view_zoom_to_level;
fm_directory_view_class->get_zoom_level = fm_icon_view_get_zoom_level;
fm_directory_view_class->click_policy_changed = fm_icon_view_click_policy_changed;
@@ -2731,9 +2738,15 @@ fm_icon_view_supports_uri (const char *uri,
if (file_type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
return TRUE;
}
+ if (strcmp (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0){
+ return TRUE;
+ }
if (g_str_has_prefix (uri, "trash:")) {
return TRUE;
}
+ if (g_str_has_prefix (uri, EEL_SEARCH_URI)) {
+ return TRUE;
+ }
return FALSE;
}
diff --git a/src/file-manager/fm-list-model.c b/src/file-manager/fm-list-model.c
index 06d162af0..7b6e2f25d 100644
--- a/src/file-manager/fm-list-model.c
+++ b/src/file-manager/fm-list-model.c
@@ -52,15 +52,12 @@ static int fm_list_model_file_entry_compare_func (gconstpointer a,
gconstpointer b,
gpointer user_data);
-static int fm_list_model_compare_func (gconstpointer a,
- gconstpointer b,
- gpointer user_data);
-
static GObjectClass *parent_class;
struct FMListModelDetails {
GSequence *files;
- GHashTable *reverse_map; /* map from files to GSequencePtr's */
+ GHashTable *directory_reverse_map; /* map from directory to GSequencePtr's */
+ GHashTable *top_reverse_map; /* map from files in top dir to GSequencePtr's */
int stamp;
@@ -86,6 +83,7 @@ typedef struct FileEntry FileEntry;
struct FileEntry {
NautilusFile *file;
+ GHashTable *reverse_map; /* map from files to GSequencePtr's */
NautilusDirectory *subdirectory;
FileEntry *parent;
GSequence *files;
@@ -105,6 +103,10 @@ static void
file_entry_free (FileEntry *file_entry)
{
nautilus_file_unref (file_entry->file);
+ if (file_entry->reverse_map) {
+ g_hash_table_destroy (file_entry->reverse_map);
+ file_entry->reverse_map = NULL;
+ }
if (file_entry->subdirectory != NULL) {
nautilus_directory_unref (file_entry->subdirectory);
}
@@ -160,6 +162,16 @@ fm_list_model_get_column_type (GtkTreeModel *tree_model, int index)
}
}
+static void
+fm_list_model_ptr_to_iter (FMListModel *model, GSequencePtr ptr, GtkTreeIter *iter)
+{
+ g_assert (!g_sequence_ptr_is_end (ptr));
+ if (iter != NULL) {
+ iter->stamp = model->details->stamp;
+ iter->user_data = ptr;
+ }
+}
+
static gboolean
fm_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
{
@@ -185,10 +197,7 @@ fm_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath
files = file_entry->files;
}
- iter->stamp = model->details->stamp;
- iter->user_data = ptr;
-
- g_assert (!g_sequence_ptr_is_end (iter->user_data));
+ fm_list_model_ptr_to_iter (model, ptr, iter);
return TRUE;
}
@@ -494,24 +503,118 @@ fm_list_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeI
return TRUE;
}
-gboolean
-fm_list_model_get_tree_iter_from_file (FMListModel *model, NautilusFile *file, GtkTreeIter *iter)
+static GSequencePtr
+lookup_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
+{
+ FileEntry *file_entry;
+ GSequencePtr ptr, parent_ptr;
+
+ parent_ptr = NULL;
+ if (directory) {
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ directory);
+ }
+
+ if (parent_ptr) {
+ file_entry = g_sequence_ptr_get_data (parent_ptr);
+ ptr = g_hash_table_lookup (file_entry->reverse_map, file);
+ } else {
+ ptr = g_hash_table_lookup (model->details->top_reverse_map, file);
+ }
+
+ if (ptr) {
+ g_assert (((FileEntry *)g_sequence_ptr_get_data (ptr))->file == file);
+ }
+
+ return ptr;
+}
+
+
+struct GetIters {
+ FMListModel *model;
+ NautilusFile *file;
+ GList *iters;
+};
+
+static void
+dir_to_iters (struct GetIters *data,
+ GHashTable *reverse_map)
{
GSequencePtr ptr;
+
+ ptr = g_hash_table_lookup (reverse_map, data->file);
+ if (ptr) {
+ GtkTreeIter *iter;
+ iter = g_new0 (GtkTreeIter, 1);
+ fm_list_model_ptr_to_iter (data->model, ptr, iter);
+ data->iters = g_list_prepend (data->iters, iter);
+ }
+}
+
+static void
+file_to_iter_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ struct GetIters *data;
+ FileEntry *dir_file_entry;
+
+ data = user_data;
+ dir_file_entry = g_sequence_ptr_get_data ((GSequencePtr)value);
+ dir_to_iters (data, dir_file_entry->reverse_map);
+}
+
+GList *
+fm_list_model_get_all_iters_for_file (FMListModel *model, NautilusFile *file)
+{
+ struct GetIters data;
+
+ data.file = file;
+ data.model = model;
+ data.iters = NULL;
+
+ dir_to_iters (&data, model->details->top_reverse_map);
+ g_hash_table_foreach (model->details->directory_reverse_map,
+ file_to_iter_cb, &data);
+
+ return g_list_reverse (data.iters);
+}
+
+gboolean
+fm_list_model_get_first_iter_for_file (FMListModel *model,
+ NautilusFile *file,
+ GtkTreeIter *iter)
+{
+ GList *list;
+ gboolean res;
+
+ res = FALSE;
+
+ list = fm_list_model_get_all_iters_for_file (model, file);
+ if (list != NULL) {
+ res = TRUE;
+ *iter = *(GtkTreeIter *)list->data;
+ }
+ eel_g_list_free_deep (list);
+
+ return res;
+}
+
- ptr = g_hash_table_lookup (model->details->reverse_map, file);
+gboolean
+fm_list_model_get_tree_iter_from_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory,
+ GtkTreeIter *iter)
+{
+ GSequencePtr ptr;
+ ptr = lookup_file (model, file, directory);
if (!ptr) {
return FALSE;
}
- g_assert (!g_sequence_ptr_is_end (ptr));
- g_assert (((FileEntry *)g_sequence_ptr_get_data (ptr))->file == file);
-
- if (iter != NULL) {
- iter->stamp = model->details->stamp;
- iter->user_data = ptr;
- }
+ fm_list_model_ptr_to_iter (model, ptr, iter);
return TRUE;
}
@@ -545,21 +648,13 @@ fm_list_model_file_entry_compare_func (gconstpointer a,
return result;
}
-static int
-fm_list_model_compare_func (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
+int
+fm_list_model_compare_func (FMListModel *model,
+ NautilusFile *file1,
+ NautilusFile *file2)
{
- NautilusFile *file1;
- NautilusFile *file2;
- FMListModel *model;
int result;
- model = (FMListModel *)user_data;
-
- file1 = (NautilusFile *)a;
- file2 = (NautilusFile *)b;
-
result = nautilus_file_compare_for_sort_by_attribute (file1, file2,
model->details->sort_attribute,
model->details->sort_directories_first,
@@ -641,12 +736,6 @@ fm_list_model_sort (FMListModel *model)
gtk_tree_path_free (path);
}
-void
-fm_list_model_sort_files (FMListModel *model, GList **files)
-{
- *files = g_list_sort_with_data (*files, fm_list_model_compare_func, model);
-}
-
static gboolean
fm_list_model_get_sort_column_id (GtkTreeSortable *sortable,
gint *sort_column_id,
@@ -716,7 +805,6 @@ each_path_get_data_binder (NautilusDragEachSelectedItemDataGet data_get,
char *uri;
GdkRectangle cell_area;
GtkTreeViewColumn *column;
- GtkTreeIter iter;
info = context;
@@ -728,31 +816,25 @@ each_path_get_data_binder (NautilusDragEachSelectedItemDataGet data_get,
row = l->data;
path = gtk_tree_row_reference_get_path (row);
-
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (info->model),
- &iter, path)) {
- gtk_tree_model_get (GTK_TREE_MODEL (info->model),
- &iter,
- FM_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- if (file) {
- gtk_tree_view_get_cell_area
- (info->model->details->drag_view,
- path,
- column,
- &cell_area);
+ file = fm_list_model_file_for_path (info->model, path);
+ if (file) {
+ gtk_tree_view_get_cell_area
+ (info->model->details->drag_view,
+ path,
+ column,
+ &cell_area);
- uri = nautilus_file_get_uri (file);
+ uri = nautilus_file_get_uri (file);
- (*data_get) (uri,
- 0,
- cell_area.y - info->model->details->drag_begin_y,
- cell_area.width, cell_area.height,
- data);
+ (*data_get) (uri,
+ 0,
+ cell_area.y - info->model->details->drag_begin_y,
+ cell_area.width, cell_area.height,
+ data);
- g_free (uri);
- }
+ g_free (uri);
+
+ nautilus_file_unref (file);
}
gtk_tree_path_free (path);
@@ -822,87 +904,65 @@ add_dummy_row (FMListModel *model, FileEntry *parent_entry)
}
gboolean
-fm_list_model_add_file (FMListModel *model, NautilusFile *file)
+fm_list_model_add_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
{
GtkTreeIter iter;
GtkTreePath *path;
FileEntry *file_entry;
- NautilusFile *parent_file;
GSequencePtr ptr, parent_ptr;
GSequence *files;
gboolean replace_dummy;
+ GHashTable *parent_hash;
- /* We may only add each file once, in one dir. */
- ptr = g_hash_table_lookup (model->details->reverse_map, file);
- if (ptr != NULL) {
- file_entry = g_sequence_ptr_get_data (ptr);
-
- parent_file = nautilus_file_get_parent (file);
- if (parent_file == NULL) {
- return FALSE;
- }
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- parent_file);
- nautilus_file_unref (parent_file);
- if (/* toplevel parent */
- (file_entry->parent == NULL && parent_ptr == NULL) ||
- /* same in-tree parent */
- (file_entry->parent != NULL && parent_ptr != NULL &&
- file_entry->parent->ptr == parent_ptr) ) {
- /* Don't add twice in same place */
- return FALSE;
- }
-
- /* file has a new parent, due to a move
- * this happens because a move results in a
- * CHANGE event and an ADD event, and
- * if the target directory of the move is
- * added to the FMDirectoryView
- * then we won't remove the changed file.
- */
- fm_list_model_remove_file (model, file);
-
- /* Now add it back again in the new place. */
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ directory);
+ if (parent_ptr) {
+ file_entry = g_sequence_ptr_get_data (parent_ptr);
+ ptr = g_hash_table_lookup (file_entry->reverse_map, file);
+ } else {
+ file_entry = NULL;
+ ptr = g_hash_table_lookup (model->details->top_reverse_map, file);
}
- nautilus_file_ref (file);
+ if (ptr != NULL) {
+ g_warning ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr);
+ return FALSE;
+ }
file_entry = g_new0 (FileEntry, 1);
- file_entry->file = file;
+ file_entry->file = nautilus_file_ref (file);
file_entry->parent = NULL;
file_entry->subdirectory = NULL;
file_entry->files = NULL;
files = model->details->files;
+ parent_hash = model->details->top_reverse_map;
replace_dummy = FALSE;
- parent_file = nautilus_file_get_parent (file);
- if (parent_file != NULL) {
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- parent_file);
- nautilus_file_unref (parent_file);
- if (parent_ptr != NULL) {
- file_entry->parent = g_sequence_ptr_get_data (parent_ptr);
- files = file_entry->parent->files;
- if (g_sequence_get_length (files) == 1) {
- GSequencePtr dummy_ptr = g_sequence_get_ptr_at_pos (files, 0);
- FileEntry *dummy_entry = g_sequence_ptr_get_data (dummy_ptr);
- if (dummy_entry->file == NULL) {
- /* replace the dummy loading entry */
- model->details->stamp++;
- g_sequence_remove (dummy_ptr);
-
- replace_dummy = TRUE;
- }
+ if (parent_ptr != NULL) {
+ file_entry->parent = g_sequence_ptr_get_data (parent_ptr);
+ parent_hash = file_entry->parent->reverse_map;
+ files = file_entry->parent->files;
+ if (g_sequence_get_length (files) == 1) {
+ GSequencePtr dummy_ptr = g_sequence_get_ptr_at_pos (files, 0);
+ FileEntry *dummy_entry = g_sequence_ptr_get_data (dummy_ptr);
+ if (dummy_entry->file == NULL) {
+ /* replace the dummy loading entry */
+ model->details->stamp++;
+ g_sequence_remove (dummy_ptr);
+
+ replace_dummy = TRUE;
}
}
}
+
file_entry->ptr = g_sequence_insert_sorted (files, file_entry,
fm_list_model_file_entry_compare_func, model);
- g_hash_table_insert (model->details->reverse_map, file, file_entry->ptr);
+ g_hash_table_insert (parent_hash, file, file_entry->ptr);
iter.stamp = model->details->stamp;
iter.user_data = file_entry->ptr;
@@ -928,23 +988,21 @@ fm_list_model_add_file (FMListModel *model, NautilusFile *file)
}
void
-fm_list_model_file_changed (FMListModel *model, NautilusFile *file)
+fm_list_model_file_changed (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
{
GtkTreeIter iter;
GtkTreePath *path;
GSequencePtr ptr;
- ptr = g_hash_table_lookup (model->details->reverse_map, file);
+ ptr = lookup_file (model, file, directory);
if (!ptr) {
return;
}
g_sequence_ptr_sort_changed (ptr, fm_list_model_file_entry_compare_func, model);
- if (!fm_list_model_get_tree_iter_from_file (model, file, &iter)) {
- return;
- }
-
+ fm_list_model_ptr_to_iter (model, ptr, &iter);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
@@ -979,7 +1037,8 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
child_file_entry = g_sequence_ptr_get_data (child_ptr);
if (child_file_entry->file != NULL) {
fm_list_model_remove_file (model,
- child_file_entry->file);
+ child_file_entry->file,
+ file_entry->subdirectory);
} else {
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
gtk_tree_path_append_index (path, 0);
@@ -995,7 +1054,11 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
}
- g_hash_table_remove (model->details->reverse_map, file_entry->file);
+ if (file_entry->parent != NULL) {
+ g_hash_table_remove (file_entry->parent->reverse_map, file_entry->file);
+ } else {
+ g_hash_table_remove (model->details->top_reverse_map, file_entry->file);
+ }
parent_file_entry = file_entry->parent;
if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 1 &&
@@ -1011,6 +1074,8 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
g_signal_emit (model,
list_model_signals[SUBDIRECTORY_UNLOADED], 0,
file_entry->subdirectory);
+ g_hash_table_remove (model->details->directory_reverse_map,
+ file_entry->subdirectory);
}
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
@@ -1032,11 +1097,12 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
}
void
-fm_list_model_remove_file (FMListModel *model, NautilusFile *file)
+fm_list_model_remove_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
{
GtkTreeIter iter;
- if (fm_list_model_get_tree_iter_from_file (model, file, &iter)) {
+ if (fm_list_model_get_tree_iter_from_file (model, file, directory, &iter)) {
fm_list_model_remove (model, &iter);
}
}
@@ -1090,6 +1156,7 @@ fm_list_model_load_subdirectory (FMListModel *model, GtkTreePath *path, Nautilus
{
GtkTreeIter iter;
FileEntry *file_entry;
+ NautilusDirectory *subdirectory;
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) {
return FALSE;
@@ -1101,9 +1168,23 @@ fm_list_model_load_subdirectory (FMListModel *model, GtkTreePath *path, Nautilus
return FALSE;
}
- file_entry->subdirectory = nautilus_directory_get_for_file (file_entry->file);
- nautilus_directory_ref (file_entry->subdirectory);
- *directory = file_entry->subdirectory;
+ subdirectory = nautilus_directory_get_for_file (file_entry->file);
+
+ if (g_hash_table_lookup (model->details->directory_reverse_map,
+ subdirectory) != NULL) {
+ nautilus_directory_unref (subdirectory);
+ g_warning ("Already in directory_reverse_map, failing\n");
+ return FALSE;
+ }
+
+ file_entry->subdirectory = subdirectory,
+ g_hash_table_insert (model->details->directory_reverse_map,
+ subdirectory, file_entry->ptr);
+ file_entry->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ /* Return a ref too */
+ nautilus_directory_ref (subdirectory);
+ *directory = subdirectory;
return TRUE;
}
@@ -1114,7 +1195,8 @@ fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
{
GSequencePtr child_ptr;
FileEntry *file_entry, *child_file_entry;
-
+ GtkTreeIter child_iter;
+
file_entry = g_sequence_ptr_get_data (iter->user_data);
if (file_entry->file == NULL ||
file_entry->subdirectory == NULL) {
@@ -1131,8 +1213,8 @@ fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
/* Don't delete the dummy node */
break;
} else {
- fm_list_model_remove_file (model,
- child_file_entry->file);
+ fm_list_model_ptr_to_iter (model, child_ptr, &child_iter);
+ fm_list_model_remove (model, &child_iter);
}
}
@@ -1142,8 +1224,14 @@ fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
file_entry->subdirectory);
/* actually unload */
+ g_hash_table_remove (model->details->directory_reverse_map,
+ file_entry->subdirectory);
nautilus_directory_unref (file_entry->subdirectory);
file_entry->subdirectory = NULL;
+
+ g_assert (g_hash_table_size (file_entry->reverse_map) == 0);
+ g_hash_table_destroy (file_entry->reverse_map);
+ file_entry->reverse_map = NULL;
}
@@ -1386,9 +1474,13 @@ fm_list_model_dispose (GObject *object)
model->details->files = NULL;
}
- if (model->details->reverse_map) {
- g_hash_table_destroy (model->details->reverse_map);
- model->details->reverse_map = NULL;
+ if (model->details->top_reverse_map) {
+ g_hash_table_destroy (model->details->top_reverse_map);
+ model->details->top_reverse_map = NULL;
+ }
+ if (model->details->directory_reverse_map) {
+ g_hash_table_destroy (model->details->directory_reverse_map);
+ model->details->directory_reverse_map = NULL;
}
EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
@@ -1412,7 +1504,8 @@ fm_list_model_init (FMListModel *model)
{
model->details = g_new0 (FMListModelDetails, 1);
model->details->files = g_sequence_new ((GDestroyNotify)file_entry_free);
- model->details->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+ model->details->top_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+ model->details->directory_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
model->details->stamp = g_random_int ();
model->details->sort_attribute = NULL;
model->details->columns = g_ptr_array_new ();
@@ -1526,7 +1619,7 @@ fm_list_model_get_type (void)
struct ChangeDummyData {
FMListModel *model;
- NautilusFile *file;
+ NautilusDirectory *directory;
};
static gboolean
@@ -1545,8 +1638,8 @@ change_dummy_row_callback (gpointer callback_data)
if (data->model != NULL) {
model = data->model;
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- data->file);
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ data->directory);
file_entry = g_sequence_ptr_get_data (parent_ptr);
file_entry->loaded = 1;
@@ -1569,7 +1662,7 @@ change_dummy_row_callback (gpointer callback_data)
}
eel_remove_weak_pointer (&data->model);
- nautilus_file_unref (data->file);
+ nautilus_directory_unref (data->directory);
g_free (data);
return FALSE;
@@ -1578,15 +1671,12 @@ change_dummy_row_callback (gpointer callback_data)
void
fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *directory)
{
- NautilusFile *parent_file;
GSequencePtr parent_ptr;
struct ChangeDummyData *data;
- parent_file = nautilus_directory_get_corresponding_file (directory);
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- parent_file);
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ directory);
if (parent_ptr == NULL) {
- nautilus_file_unref (parent_file);
return;
}
@@ -1596,10 +1686,9 @@ fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *
*/
data = g_new (struct ChangeDummyData, 1);
data->model = model;
- data->file = nautilus_file_ref (parent_file);
+ data->directory = directory;
+ nautilus_directory_ref (directory);
eel_add_weak_pointer (&data->model);
g_timeout_add (LOADING_TO_EMPTY_DELAY, change_dummy_row_callback, data);
-
- nautilus_file_unref (parent_file);
}
diff --git a/src/file-manager/fm-list-model.h b/src/file-manager/fm-list-model.h
index 6dcb9becf..809f24a8a 100644
--- a/src/file-manager/fm-list-model.h
+++ b/src/file-manager/fm-list-model.h
@@ -76,16 +76,25 @@ typedef struct {
GType fm_list_model_get_type (void);
gboolean fm_list_model_add_file (FMListModel *model,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
void fm_list_model_file_changed (FMListModel *model,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
gboolean fm_list_model_is_empty (FMListModel *model);
guint fm_list_model_get_length (FMListModel *model);
void fm_list_model_remove_file (FMListModel *model,
- NautilusFile *file);
+ NautilusFile *file,
+ NautilusDirectory *directory);
void fm_list_model_clear (FMListModel *model);
gboolean fm_list_model_get_tree_iter_from_file (FMListModel *model,
NautilusFile *file,
+ NautilusDirectory *directory,
+ GtkTreeIter *iter);
+GList * fm_list_model_get_all_iters_for_file (FMListModel *model,
+ NautilusFile *file);
+gboolean fm_list_model_get_first_iter_for_file (FMListModel *model,
+ NautilusFile *file,
GtkTreeIter *iter);
void fm_list_model_set_should_sort_directories_first (FMListModel *model,
gboolean sort_directories_first);
@@ -95,7 +104,7 @@ int fm_list_model_get_sort_column_id_from_attribute (FMListModel *model,
const char *attribute);
char *fm_list_model_get_attribute_from_sort_column_id (FMListModel *model,
int sort_column_id);
-void fm_list_model_sort_files (FMListModel *model,
+void fm_list_model_sort_files (FMListModel *model,
GList **files);
NautilusZoomLevel fm_list_model_get_zoom_level_from_column_id (int column);
@@ -114,6 +123,9 @@ void fm_list_model_set_drag_view (FMListModel *model,
void fm_list_model_get_drag_types (const GtkTargetEntry **entries,
int *num_entries);
+int fm_list_model_compare_func (FMListModel *model,
+ NautilusFile *file1,
+ NautilusFile *file2);
int fm_list_model_add_column (FMListModel *model,
@@ -122,6 +134,6 @@ int fm_list_model_get_column_number (FMListModel *model,
const char *column_name);
void fm_list_model_subdirectory_done_loading (FMListModel *model,
- NautilusDirectory *directory);
+ NautilusDirectory *directory);
#endif /* FM_LIST_MODEL_H */
diff --git a/src/file-manager/fm-list-view.c b/src/file-manager/fm-list-view.c
index de1244570..badff87e7 100644
--- a/src/file-manager/fm-list-view.c
+++ b/src/file-manager/fm-list-view.c
@@ -767,6 +767,7 @@ row_expanded_callback (GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *pa
struct UnloadDelayData {
NautilusFile *file;
+ NautilusDirectory *directory;
FMListView *view;
};
@@ -782,6 +783,7 @@ unload_file_timeout (gpointer data)
model = unload_data->view->details->model;
if (fm_list_model_get_tree_iter_from_file (model,
unload_data->file,
+ unload_data->directory,
&iter)) {
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
if (!gtk_tree_view_row_expanded (unload_data->view->details->tree_view,
@@ -794,8 +796,10 @@ unload_file_timeout (gpointer data)
eel_remove_weak_pointer (&unload_data->view);
-
- g_object_unref (unload_data->file);
+ if (unload_data->directory) {
+ nautilus_directory_unref (unload_data->directory);
+ }
+ nautilus_file_unref (unload_data->file);
g_free (unload_data);
return FALSE;
}
@@ -805,18 +809,29 @@ row_collapsed_callback (GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *p
{
FMListView *view;
NautilusFile *file;
+ NautilusDirectory *directory;
+ GtkTreeIter parent;
struct UnloadDelayData *unload_data;
+ GtkTreeModel *model;
view = FM_LIST_VIEW (callback_data);
+ model = GTK_TREE_MODEL (view->details->model);
- gtk_tree_model_get (GTK_TREE_MODEL (view->details->model),
- iter,
+ gtk_tree_model_get (model, iter,
FM_LIST_MODEL_FILE_COLUMN, &file,
-1);
+
+ directory = NULL;
+ if (gtk_tree_model_iter_parent (model, &parent, iter)) {
+ gtk_tree_model_get (model, &parent,
+ FM_LIST_MODEL_SUBDIRECTORY_COLUMN, &directory,
+ -1);
+ }
unload_data = g_new (struct UnloadDelayData, 1);
unload_data->view = view;
unload_data->file = file;
+ unload_data->directory = directory;
eel_add_weak_pointer (&unload_data->view);
@@ -994,23 +1009,10 @@ get_file_for_path_callback (NautilusTreeViewDragDest *dest,
gpointer user_data)
{
FMListView *view;
- GtkTreeIter iter;
- NautilusFile *file;
view = FM_LIST_VIEW (user_data);
- file = NULL;
-
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->model),
- &iter, path)) {
- gtk_tree_model_get (GTK_TREE_MODEL (view->details->model),
- &iter,
- FM_LIST_MODEL_FILE_COLUMN,
- &file,
- -1);
- }
-
- return file;
+ return fm_list_model_file_for_path (view->details->model, path);
}
/* Handles an URL received from Mozilla */
@@ -1332,12 +1334,12 @@ create_and_set_up_tree_view (FMListView *view)
}
static void
-fm_list_view_add_file (FMDirectoryView *view, NautilusFile *file)
+fm_list_view_add_file (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
FMListModel *model;
-
+
model = FM_LIST_VIEW (view)->details->model;
- fm_list_model_add_file (model, file);
+ fm_list_model_add_file (model, file, directory);
}
static GList *
@@ -1508,9 +1510,9 @@ fm_list_view_clear (FMDirectoryView *view)
}
static void
-fm_list_view_file_changed (FMDirectoryView *view, NautilusFile *file)
+fm_list_view_file_changed (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
- fm_list_model_file_changed (FM_LIST_VIEW (view)->details->model, file);
+ fm_list_model_file_changed (FM_LIST_VIEW (view)->details->model, file, directory);
}
static GtkWidget *
@@ -1532,7 +1534,6 @@ fm_list_view_get_selection_foreach_func (GtkTreeModel *model, GtkTreePath *path,
-1);
if (file != NULL) {
- nautilus_file_ref (file);
(* list) = g_list_prepend ((* list), file);
}
}
@@ -1631,7 +1632,7 @@ fm_list_view_end_file_changes (FMDirectoryView *view)
}
static void
-fm_list_view_remove_file (FMDirectoryView *view, NautilusFile *file)
+fm_list_view_remove_file (FMDirectoryView *view, NautilusFile *file, NautilusDirectory *directory)
{
GtkTreePath *path;
GtkTreePath *file_path;
@@ -1641,13 +1642,13 @@ fm_list_view_remove_file (FMDirectoryView *view, NautilusFile *file)
FMListView *list_view;
GtkTreeModel* tree_model;
GtkTreeSelection *selection;
-
+
path = NULL;
row_reference = NULL;
list_view = FM_LIST_VIEW (view);
tree_model = GTK_TREE_MODEL(list_view->details->model);
- if(fm_list_model_get_tree_iter_from_file (list_view->details->model, file, &iter)) {
+ if (fm_list_model_get_tree_iter_from_file (list_view->details->model, file, directory, &iter)) {
selection = gtk_tree_view_get_selection (list_view->details->tree_view);
file_path = gtk_tree_model_get_path (tree_model, &iter);
@@ -1672,7 +1673,7 @@ fm_list_view_remove_file (FMDirectoryView *view, NautilusFile *file)
gtk_tree_path_free (file_path);
- fm_list_model_remove_file (list_view->details->model, file);
+ fm_list_model_remove_file (list_view->details->model, file, directory);
if (gtk_tree_row_reference_valid (row_reference)) {
if (list_view->details->new_selection_path) {
@@ -1681,7 +1682,7 @@ fm_list_view_remove_file (FMDirectoryView *view, NautilusFile *file)
list_view->details->new_selection_path = gtk_tree_row_reference_get_path (row_reference);
}
- if(row_reference) {
+ if (row_reference) {
gtk_tree_row_reference_free (row_reference);
}
}
@@ -1695,7 +1696,7 @@ fm_list_view_set_selection (FMDirectoryView *view, GList *selection)
FMListView *list_view;
GtkTreeSelection *tree_selection;
GList *node;
- GtkTreeIter iter;
+ GList *iters, *l;
NautilusFile *file;
list_view = FM_LIST_VIEW (view);
@@ -1706,9 +1707,13 @@ fm_list_view_set_selection (FMDirectoryView *view, GList *selection)
gtk_tree_selection_unselect_all (tree_selection);
for (node = selection; node != NULL; node = node->next) {
file = node->data;
- if (fm_list_model_get_tree_iter_from_file (list_view->details->model, file, &iter)) {
- gtk_tree_selection_select_iter (tree_selection, &iter);
+ iters = fm_list_model_get_all_iters_for_file (list_view->details->model, file);
+
+ for (l = iters; l != NULL; l = l->next) {
+ gtk_tree_selection_select_iter (tree_selection,
+ (GtkTreeIter *)l->data);
}
+ eel_g_list_free_deep (iters);
}
g_signal_handlers_unblock_by_func (tree_selection, list_selection_changed_callback, view);
@@ -1739,15 +1744,13 @@ fm_list_view_reveal_selection (FMDirectoryView *view)
list_view = FM_LIST_VIEW (view);
file = selection->data;
- if (!fm_list_model_get_tree_iter_from_file (list_view->details->model, file, &iter)) {
- return;
- }
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
+ if (fm_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_view->details->model), &iter);
- gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0);
-
- gtk_tree_path_free (path);
- path = NULL;
+ gtk_tree_view_scroll_to_cell (list_view->details->tree_view, path, NULL, FALSE, 0.0, 0.0);
+
+ gtk_tree_path_free (path);
+ }
}
nautilus_file_list_free (selection);
@@ -2146,7 +2149,7 @@ fm_list_view_start_renaming_file (FMDirectoryView *view,
return;
}
- if (!fm_list_model_get_tree_iter_from_file (list_view->details->model, file, &iter)) {
+ if (!fm_list_model_get_first_iter_for_file (list_view->details->model, file, &iter)) {
return;
}
@@ -2295,14 +2298,13 @@ fm_list_view_sort_directories_first_changed (FMDirectoryView *view)
fm_directory_view_should_sort_directories_first (view));
}
-static void
-fm_list_view_sort_files (FMDirectoryView *view, GList **files)
+static int
+fm_list_view_compare_files (FMDirectoryView *view, NautilusFile *file1, NautilusFile *file2)
{
FMListView *list_view;
list_view = FM_LIST_VIEW (view);
-
- fm_list_model_sort_files (list_view->details->model, files);
+ return fm_list_model_compare_func (list_view->details->model, file1, file2);
}
static gboolean
@@ -2426,7 +2428,7 @@ fm_list_view_scroll_to_file (FMListView *view,
GtkTreePath *path;
GtkTreeIter iter;
- if (!fm_list_model_get_tree_iter_from_file (view->details->model, file, &iter)) {
+ if (!fm_list_model_get_first_iter_for_file (view->details->model, file, &iter)) {
return;
}
@@ -2446,9 +2448,13 @@ list_view_scroll_to_file (NautilusView *view,
NautilusFile *file;
if (uri != NULL) {
- file = nautilus_file_get (uri);
- fm_list_view_scroll_to_file (FM_LIST_VIEW (view), file);
- nautilus_file_unref (file);
+ /* Only if existing, since we don't want to add the file to
+ the directory if it has been removed since then */
+ file = nautilus_file_get_existing (uri);
+ if (file != NULL) {
+ fm_list_view_scroll_to_file (FM_LIST_VIEW (view), file);
+ nautilus_file_unref (file);
+ }
}
}
@@ -2484,7 +2490,7 @@ fm_list_view_class_init (FMListViewClass *class)
fm_directory_view_class->reveal_selection = fm_list_view_reveal_selection;
fm_directory_view_class->select_all = fm_list_view_select_all;
fm_directory_view_class->set_selection = fm_list_view_set_selection;
- fm_directory_view_class->sort_files = fm_list_view_sort_files;
+ fm_directory_view_class->compare_files = fm_list_view_compare_files;
fm_directory_view_class->sort_directories_first_changed = fm_list_view_sort_directories_first_changed;
fm_directory_view_class->start_renaming_file = fm_list_view_start_renaming_file;
fm_directory_view_class->get_zoom_level = fm_list_view_get_zoom_level;
@@ -2582,9 +2588,15 @@ fm_list_view_supports_uri (const char *uri,
if (file_type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
return TRUE;
}
+ if (strcmp (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0){
+ return TRUE;
+ }
if (g_str_has_prefix (uri, "trash:")) {
return TRUE;
}
+ if (g_str_has_prefix (uri, EEL_SEARCH_URI)) {
+ return TRUE;
+ }
return FALSE;
}
diff --git a/src/file-manager/fm-properties-window.c b/src/file-manager/fm-properties-window.c
index be93d0bf1..c53fe6f86 100644
--- a/src/file-manager/fm-properties-window.c
+++ b/src/file-manager/fm-properties-window.c
@@ -2908,9 +2908,11 @@ create_permissions_page (FMPropertiesWindow *window)
file_list = window->details->original_files;
- window->details->initial_permissions = get_initial_permissions (window->details->target_files);
+ window->details->initial_permissions = NULL;
if (all_can_get_permissions (file_list)) {
+ window->details->initial_permissions = get_initial_permissions (window->details->target_files);
+
if (!all_can_set_permissions (file_list)) {
add_prompt_and_separator (
GTK_VBOX (vbox),
@@ -3273,6 +3275,11 @@ create_open_with_page (FMPropertiesWindow *window)
char *mime_type;
uri = nautilus_file_get_uri (get_target_file (window));
+
+ if (uri == NULL) {
+ return;
+ }
+
mime_type = nautilus_file_get_mime_type (get_target_file (window));
vbox = eel_mime_application_chooser_new (uri, mime_type);
diff --git a/src/file-manager/nautilus-directory-view-ui.xml b/src/file-manager/nautilus-directory-view-ui.xml
index fcbe5cda3..3a1cdbdda 100644
--- a/src/file-manager/nautilus-directory-view-ui.xml
+++ b/src/file-manager/nautilus-directory-view-ui.xml
@@ -39,6 +39,8 @@
</placeholder>
<placeholder name="Global File Items Placeholder">
<menuitem name="Empty Trash" action="Empty Trash"/>
+ <menuitem name="Save Search" action="Save Search"/>
+ <menuitem name="Save Search As" action="Save Search As"/>
</placeholder>
</menu>
<menu action="Edit">
diff --git a/src/nautilus-actions.h b/src/nautilus-actions.h
index 77c92f265..e7296262e 100644
--- a/src/nautilus-actions.h
+++ b/src/nautilus-actions.h
@@ -42,5 +42,6 @@
#define NAUTILUS_ACTION_ZOOM_OUT "Zoom Out"
#define NAUTILUS_ACTION_ZOOM_NORMAL "Zoom Normal"
#define NAUTILUS_ACTION_CLOSE "Close"
+#define NAUTILUS_ACTION_SEARCH "Search"
#endif /* NAUTILUS_ACTIONS_H */
diff --git a/src/nautilus-history-sidebar.c b/src/nautilus-history-sidebar.c
index 3a23df8c0..7b34fe4f5 100644
--- a/src/nautilus-history-sidebar.c
+++ b/src/nautilus-history-sidebar.c
@@ -110,6 +110,7 @@ update_history (NautilusHistorySidebar *sidebar)
HISTORY_SIDEBAR_COLUMN_NAME, name,
HISTORY_SIDEBAR_COLUMN_BOOKMARK, bookmark,
-1);
+ g_object_unref (bookmark);
if (pixbuf != NULL) {
g_object_unref (pixbuf);
@@ -219,6 +220,7 @@ nautilus_history_sidebar_init (NautilusHistorySidebar *sidebar)
NAUTILUS_TYPE_BOOKMARK);
gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (store));
+ g_object_unref (store);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sidebar),
GTK_POLICY_AUTOMATIC,
diff --git a/src/nautilus-location-bar.c b/src/nautilus-location-bar.c
index 1887ad474..b400c2fff 100644
--- a/src/nautilus-location-bar.c
+++ b/src/nautilus-location-bar.c
@@ -497,12 +497,17 @@ nautilus_location_bar_set_location (NautilusNavigationBar *navigation_bar,
/* Note: This is called in reaction to external changes, and
* thus should not emit the LOCATION_CHANGED signal. */
-
- formatted_location = eel_format_uri_for_display (location);
- nautilus_entry_set_text (NAUTILUS_ENTRY (bar->details->entry),
- formatted_location);
- set_position_and_selection_to_end (GTK_EDITABLE (bar->details->entry));
- g_free (formatted_location);
+
+ if (eel_uri_is_search (location)) {
+ nautilus_location_entry_set_special_text (NAUTILUS_LOCATION_ENTRY (bar->details->entry),
+ "");
+ } else {
+ formatted_location = eel_format_uri_for_display (location);
+ nautilus_entry_set_text (NAUTILUS_ENTRY (bar->details->entry),
+ formatted_location);
+ set_position_and_selection_to_end (GTK_EDITABLE (bar->details->entry));
+ g_free (formatted_location);
+ }
/* free up the cached file info from the previous location */
g_free (bar->details->current_directory);
diff --git a/src/nautilus-location-entry.c b/src/nautilus-location-entry.c
index f294124f3..6ede24c10 100644
--- a/src/nautilus-location-entry.c
+++ b/src/nautilus-location-entry.c
@@ -60,6 +60,10 @@ struct NautilusLocationEntryDetails {
GList *file_info_list;
guint idle_id;
+
+ gboolean has_special_text;
+ gboolean setting_special_text;
+ gchar *special_text;
};
static void nautilus_location_entry_class_init (NautilusLocationEntryClass *class);
@@ -431,6 +435,7 @@ finalize (GObject *object)
entry = NAUTILUS_LOCATION_ENTRY (object);
+ g_free (entry->details->special_text);
g_free (entry->details);
EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
@@ -461,11 +466,42 @@ destroy (GtkObject *object)
}
static void
+nautilus_location_entry_text_changed (NautilusLocationEntry *entry,
+ GParamSpec *pspec)
+{
+ if (entry->details->setting_special_text) {
+ return;
+ }
+
+ entry->details->has_special_text = FALSE;
+}
+
+static gboolean
+nautilus_location_entry_focus_in (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ NautilusLocationEntry *entry = NAUTILUS_LOCATION_ENTRY (widget);
+
+ if (entry->details->has_special_text) {
+ entry->details->setting_special_text = TRUE;
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ entry->details->setting_special_text = FALSE;
+ }
+
+ return EEL_CALL_PARENT_WITH_RETURN_VALUE (GTK_WIDGET_CLASS, focus_in_event, (widget, event));
+}
+
+static void
nautilus_location_entry_class_init (NautilusLocationEntryClass *class)
{
+ GtkWidgetClass *widget_class;
GObjectClass *gobject_class;
GtkObjectClass *object_class;
+ widget_class = GTK_WIDGET_CLASS (class);
+
+ widget_class->focus_in_event = nautilus_location_entry_focus_in;
+
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = finalize;
@@ -483,6 +519,9 @@ nautilus_location_entry_init (NautilusLocationEntry *entry)
g_signal_connect (entry, "event_after",
G_CALLBACK (editable_event_after_callback), entry);
+ g_signal_connect (entry, "notify::text",
+ G_CALLBACK (nautilus_location_entry_text_changed), NULL);
+
}
GtkWidget *
@@ -494,3 +533,18 @@ nautilus_location_entry_new (void)
return entry;
}
+
+void
+nautilus_location_entry_set_special_text (NautilusLocationEntry *entry,
+ const char *special_text)
+{
+ entry->details->has_special_text = TRUE;
+
+ g_free (entry->details->special_text);
+ entry->details->special_text = g_strdup (special_text);
+
+ entry->details->setting_special_text = TRUE;
+ gtk_entry_set_text (GTK_ENTRY (entry), special_text);
+ entry->details->setting_special_text = FALSE;
+}
+
diff --git a/src/nautilus-location-entry.h b/src/nautilus-location-entry.h
index 596f18a33..2869e112a 100644
--- a/src/nautilus-location-entry.h
+++ b/src/nautilus-location-entry.h
@@ -50,5 +50,7 @@ typedef struct {
GType nautilus_location_entry_get_type (void);
GtkWidget* nautilus_location_entry_new (void);
+void nautilus_location_entry_set_special_text (NautilusLocationEntry *entry,
+ const char *special_text);
#endif /* NAUTILUS_LOCATION_ENTRY_H */
diff --git a/src/nautilus-navigation-window-menus.c b/src/nautilus-navigation-window-menus.c
index 6b9a1cfe2..63d14f9c4 100644
--- a/src/nautilus-navigation-window-menus.c
+++ b/src/nautilus-navigation-window-menus.c
@@ -60,6 +60,7 @@
#include <libnautilus-private/nautilus-ui-utilities.h>
#include <libnautilus-private/nautilus-icon-factory.h>
#include <libnautilus-private/nautilus-undo-manager.h>
+#include <libnautilus-private/nautilus-search-engine.h>
#define MENU_PATH_HISTORY_PLACEHOLDER "/MenuBar/Other Menus/Go/History Placeholder"
@@ -410,6 +411,17 @@ action_go_to_location_callback (GtkAction *action,
nautilus_window_prompt_for_location (window, NULL);
}
+static void
+action_search_callback (GtkAction *action,
+ gpointer user_data)
+{
+ NautilusNavigationWindow *window;
+
+ window = NAUTILUS_NAVIGATION_WINDOW (user_data);
+
+ nautilus_navigation_window_show_search (window);
+}
+
static const GtkActionEntry navigation_entries[] = {
{ "Go", NULL, N_("_Go") }, /* name, stock id, label */
{ "Bookmarks", NULL, N_("_Bookmarks") }, /* name, stock id, label */
@@ -431,6 +443,10 @@ static const GtkActionEntry navigation_entries[] = {
{ "Edit Bookmarks", NULL, N_("_Edit Bookmarks"), /* name, stock id, label */
"<control>b", N_("Display a window that allows editing the bookmarks in this menu"),
G_CALLBACK (action_edit_bookmarks_callback) },
+ { "Search", "gtk-find", N_("_Search"), /* name, stock id, label */
+ "<control>F", N_("Search for files"),
+ G_CALLBACK (action_search_callback) },
+
};
static const GtkToggleActionEntry navigation_toggle_entries[] = {
diff --git a/src/nautilus-navigation-window-ui.xml b/src/nautilus-navigation-window-ui.xml
index b15da7441..1da8913bc 100644
--- a/src/nautilus-navigation-window-ui.xml
+++ b/src/nautilus-navigation-window-ui.xml
@@ -31,6 +31,7 @@
<menuitem name="Go to Trash" action="Go to Trash"/>
<menuitem name="Go to Burn CD" action="Go to Burn CD"/>
<menuitem name="Go to Location" action="Go to Location"/>
+ <menuitem name="Search" action="Search"/>
<separator/>
<menuitem name="Clear History" action="Clear History"/>
<separator/>
@@ -54,7 +55,8 @@
<separator/>
<toolitem name="Home" action="Home"/>
<toolitem name="Computer" action="Go to Computer"/>
-
+ <separator/>
+ <toolitem name="Search" action="Search"/>
<placeholder name="Extra Buttons Placeholder">
<placeholder name="Extension Actions"/>
</placeholder>
diff --git a/src/nautilus-navigation-window.c b/src/nautilus-navigation-window.c
index b18886968..d5dc20881 100644
--- a/src/nautilus-navigation-window.c
+++ b/src/nautilus-navigation-window.c
@@ -38,6 +38,8 @@
#include "nautilus-signaller.h"
#include "nautilus-location-bar.h"
#include "nautilus-pathbar.h"
+#include "nautilus-query-editor.h"
+#include "nautilus-search-bar.h"
#include "nautilus-window-manage-views.h"
#include "nautilus-zoom-control.h"
#include <eel/eel-accessibility.h>
@@ -48,6 +50,7 @@
#include <eel/eel-gtk-macros.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string.h>
+#include <eel/eel-vfs-extensions.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdkx.h>
#include <gtk/gtkmain.h>
@@ -81,6 +84,7 @@
#include <libnautilus-private/nautilus-undo.h>
#include <libnautilus-private/nautilus-module.h>
#include <libnautilus-private/nautilus-sidebar-provider.h>
+#include <libnautilus-private/nautilus-search-directory.h>
#include <math.h>
#include <sys/time.h>
@@ -99,6 +103,12 @@
#define MENU_PATH_BOOKMARKS_PLACEHOLDER "/MenuBar/Other Menus/Bookmarks/Bookmarks Placeholder"
+typedef enum {
+ NAUTILUS_BAR_PATH,
+ NAUTILUS_BAR_NAVIGATION,
+ NAUTILUS_BAR_SEARCH
+} NautilusBarMode;
+
enum {
ARG_0,
ARG_APP_ID,
@@ -121,6 +131,14 @@ static void path_bar_location_changed_callback (GtkWidget *
NautilusNavigationWindow *window);
static void always_use_location_entry_changed (gpointer callback_data);
+static void nautilus_navigation_window_set_bar_mode (NautilusNavigationWindow *window,
+ NautilusBarMode mode);
+static void search_bar_activate_callback (NautilusSearchBar *bar,
+ NautilusWindow *window);
+static void search_bar_cancel_callback (GtkWidget *widget,
+ NautilusNavigationWindow *window);
+
+static void nautilus_navigation_window_show_location_bar_temporarily (NautilusNavigationWindow *window);
GNOME_CLASS_BOILERPLATE (NautilusNavigationWindow, nautilus_navigation_window,
NautilusWindow, NAUTILUS_TYPE_WINDOW)
@@ -133,7 +151,7 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window)
GtkWidget *location_bar;
GtkWidget *view_as_menu_vbox;
GtkToolItem *item;
- GtkWidget *hbox;
+ GtkWidget *hbox, *vbox, *eventbox, *extras_vbox;
window->details = g_new0 (NautilusNavigationWindowDetails, 1);
@@ -150,6 +168,25 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window)
0, 0);
gtk_widget_show (window->details->content_paned);
+ vbox = gtk_vbox_new (FALSE, 0);
+ nautilus_horizontal_splitter_pack2 (
+ NAUTILUS_HORIZONTAL_SPLITTER (window->details->content_paned),
+ vbox);
+ gtk_widget_show (vbox);
+
+ eventbox = gtk_event_box_new ();
+ gtk_widget_set_name (eventbox, "nautilus-extra-view-widget");
+ gtk_box_pack_start (GTK_BOX (vbox), eventbox, FALSE, FALSE, 0);
+ gtk_widget_show (eventbox);
+
+ extras_vbox = gtk_vbox_new (FALSE, 0);
+ NAUTILUS_WINDOW (window)->details->extra_location_widgets = extras_vbox;
+ gtk_container_add (GTK_CONTAINER (eventbox), extras_vbox);
+
+ window->details->content_box = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), window->details->content_box, TRUE, TRUE, 0);
+ gtk_widget_show (window->details->content_box);
+
nautilus_navigation_window_initialize_actions (window);
nautilus_navigation_window_initialize_menus (window);
@@ -207,6 +244,15 @@ nautilus_navigation_window_instance_init (NautilusNavigationWindow *window)
window->navigation_bar,
TRUE, TRUE, 0);
+ window->search_bar = nautilus_search_bar_new ();
+ g_signal_connect_object (window->search_bar, "activate",
+ G_CALLBACK (search_bar_activate_callback), window, 0);
+ g_signal_connect_object (window->search_bar, "cancel",
+ G_CALLBACK (search_bar_cancel_callback), window, 0);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ window->search_bar,
+ TRUE, TRUE, 0);
+
/* Option menu for content view types; it's empty here, filled in when a uri is set.
* Pack it into vbox so it doesn't grow vertically when location bar does.
*/
@@ -270,9 +316,9 @@ always_use_location_entry_changed (gpointer callback_data)
window = NAUTILUS_NAVIGATION_WINDOW (callback_data);
if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
- nautilus_navigation_window_hide_path_bar (window);
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_NAVIGATION);
} else {
- nautilus_navigation_window_show_path_bar (window);
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_PATH);
}
}
@@ -331,11 +377,23 @@ hide_temporary_bars (NautilusNavigationWindow *window)
window->details->temporary_location_bar = FALSE;
}
if (window->details->temporary_navigation_bar) {
- if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
- nautilus_navigation_window_show_path_bar (window);
+ if (NAUTILUS_WINDOW (window)->details->search_mode) {
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_SEARCH);
+ } else {
+ if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_PATH);
+ }
}
window->details->temporary_navigation_bar = FALSE;
}
+ if (window->details->temporary_search_bar) {
+ if (!eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_PATH);
+ } else {
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_NAVIGATION);
+ }
+ window->details->temporary_search_bar = FALSE;
+ }
}
static void
@@ -843,9 +901,8 @@ real_set_content_view_widget (NautilusWindow *nautilus_window,
connect_view (window, new_view);
- nautilus_horizontal_splitter_pack2 (
- NAUTILUS_HORIZONTAL_SPLITTER (window->details->content_paned),
- GTK_WIDGET (new_view));
+ gtk_container_add (GTK_CONTAINER (window->details->content_box),
+ GTK_WIDGET (new_view));
if (new_view != NULL && nautilus_view_supports_zooming (new_view)) {
gtk_widget_show (window->zoom_control);
@@ -871,15 +928,20 @@ real_set_throbber_active (NautilusWindow *window, gboolean active)
}
static void
-nautilus_navigation_window_show_location_bar_temporarily (NautilusNavigationWindow *window,
- gboolean in_search_mode)
+nautilus_navigation_window_show_location_bar_temporarily (NautilusNavigationWindow *window)
{
if (!nautilus_navigation_window_location_bar_showing (window)) {
nautilus_navigation_window_show_location_bar (window, FALSE);
window->details->temporary_location_bar = TRUE;
}
- if (nautilus_navigation_window_path_bar_showing (window)) {
- nautilus_navigation_window_hide_path_bar (window);
+}
+
+static void
+nautilus_navigation_window_show_navigation_bar_temporarily (NautilusNavigationWindow *window)
+{
+ if (nautilus_navigation_window_path_bar_showing (window)
+ || nautilus_navigation_window_search_bar_showing (window)) {
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_NAVIGATION);
window->details->temporary_navigation_bar = TRUE;
}
nautilus_navigation_bar_activate
@@ -889,13 +951,132 @@ nautilus_navigation_window_show_location_bar_temporarily (NautilusNavigationWind
static void
real_prompt_for_location (NautilusWindow *window, const char *initial)
{
- nautilus_navigation_window_show_location_bar_temporarily (NAUTILUS_NAVIGATION_WINDOW (window), FALSE);
-
+ nautilus_navigation_window_show_location_bar_temporarily (NAUTILUS_NAVIGATION_WINDOW (window));
+ nautilus_navigation_window_show_navigation_bar_temporarily (NAUTILUS_NAVIGATION_WINDOW (window));
+
if (initial) {
nautilus_navigation_bar_set_location (NAUTILUS_NAVIGATION_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->navigation_bar),
initial);
}
-
+}
+
+static void
+search_bar_activate_callback (NautilusSearchBar *bar,
+ NautilusWindow *window)
+{
+ char *uri, *home_uri;
+ NautilusDirectory *directory;
+ NautilusSearchDirectory *search_directory;
+ NautilusQuery *query;
+
+ uri = nautilus_search_directory_generate_new_uri ();
+ directory = nautilus_directory_get (uri);
+
+ g_assert (NAUTILUS_IS_SEARCH_DIRECTORY (directory));
+
+ search_directory = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ query = nautilus_search_bar_get_query (NAUTILUS_SEARCH_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->search_bar));
+ if (query != NULL) {
+ if (!nautilus_search_directory_is_indexed (search_directory)) {
+ home_uri = nautilus_get_home_directory_uri ();
+ nautilus_query_set_location (query, home_uri);
+ g_free (home_uri);
+ }
+ nautilus_search_directory_set_query (search_directory, query);
+ g_object_unref (query);
+ }
+
+ nautilus_window_go_to (window, uri);
+
+ nautilus_directory_unref (directory);
+ g_free (uri);
+}
+
+static void
+search_bar_cancel_callback (GtkWidget *widget,
+ NautilusNavigationWindow *window)
+{
+ hide_temporary_bars (window);
+}
+
+void
+nautilus_navigation_window_show_search (NautilusNavigationWindow *window)
+{
+ if (!nautilus_navigation_window_search_bar_showing (window)) {
+ nautilus_navigation_window_show_location_bar_temporarily (window);
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_SEARCH);
+ window->details->temporary_search_bar = TRUE;
+ nautilus_search_bar_clear (NAUTILUS_SEARCH_BAR (window->search_bar));
+ }
+
+ nautilus_search_bar_grab_focus (NAUTILUS_SEARCH_BAR (window->search_bar));
+}
+
+static void
+query_editor_changed_callback (NautilusSearchBar *bar,
+ NautilusQuery *query,
+ gboolean reload,
+ NautilusWindow *window)
+{
+ NautilusDirectory *directory;
+
+ directory = nautilus_directory_get_for_file (window->details->viewed_file);
+ g_assert (NAUTILUS_IS_SEARCH_DIRECTORY (directory));
+
+ nautilus_search_directory_set_query (NAUTILUS_SEARCH_DIRECTORY (directory),
+ query);
+ if (reload) {
+ nautilus_window_reload (window);
+ }
+
+ nautilus_directory_unref (directory);
+}
+
+static void
+real_set_search_mode (NautilusWindow *window, gboolean search_mode,
+ NautilusSearchDirectory *search_directory)
+{
+ NautilusNavigationWindow *nav_window;
+ GtkWidget *query_editor;
+ NautilusQuery *query;
+
+ nav_window = NAUTILUS_NAVIGATION_WINDOW (window);
+
+ if (!search_mode) {
+ nav_window->details->temporary_search_bar = TRUE;
+ hide_temporary_bars (nav_window);
+ return;
+ }
+
+ if (nautilus_search_directory_is_saved_search (search_directory)) {
+ query_editor = nautilus_query_editor_new (TRUE,
+ nautilus_search_directory_is_indexed (search_directory));
+ } else {
+ nautilus_navigation_window_show_location_bar_temporarily (nav_window);
+ nautilus_navigation_window_set_bar_mode (nav_window, NAUTILUS_BAR_SEARCH);
+ nav_window->details->temporary_search_bar = FALSE;
+
+ query_editor = nautilus_query_editor_new_with_bar (FALSE,
+ nautilus_search_directory_is_indexed (search_directory),
+ NAUTILUS_SEARCH_BAR (nav_window->search_bar));
+ }
+
+ g_signal_connect_object (query_editor, "changed",
+ G_CALLBACK (query_editor_changed_callback), window, 0);
+
+ query = nautilus_search_directory_get_query (search_directory);
+ if (query != NULL) {
+ nautilus_query_editor_set_query (NAUTILUS_QUERY_EDITOR (query_editor),
+ query);
+ g_object_unref (query);
+ }else {
+ nautilus_query_editor_set_default_query (NAUTILUS_QUERY_EDITOR (query_editor));
+ }
+
+ nautilus_window_add_extra_location_widget (window, query_editor);
+ gtk_widget_show (query_editor);
+ nautilus_query_editor_grab_focus (NAUTILUS_QUERY_EDITOR (query_editor));
}
void
@@ -1004,19 +1185,40 @@ nautilus_navigation_window_location_bar_showing (NautilusNavigationWindow *windo
return TRUE;
}
-void
-nautilus_navigation_window_hide_path_bar (NautilusNavigationWindow *window)
+gboolean
+nautilus_navigation_window_search_bar_showing (NautilusNavigationWindow *window)
{
- window->details->temporary_navigation_bar = FALSE;
- gtk_widget_hide (window->path_bar);
- gtk_widget_show (window->navigation_bar);
+ if (window->search_bar != NULL) {
+ return GTK_WIDGET_VISIBLE (window->search_bar);
+ }
+ /* If we're not visible yet we haven't changed visibility, so its TRUE */
+ return TRUE;
}
-void
-nautilus_navigation_window_show_path_bar (NautilusNavigationWindow *window)
+static void
+nautilus_navigation_window_set_bar_mode (NautilusNavigationWindow *window,
+ NautilusBarMode mode)
{
- gtk_widget_show (window->path_bar);
- gtk_widget_hide (window->navigation_bar);
+ switch (mode) {
+
+ case NAUTILUS_BAR_PATH:
+ gtk_widget_show (window->path_bar);
+ gtk_widget_hide (window->navigation_bar);
+ gtk_widget_hide (window->search_bar);
+ break;
+
+ case NAUTILUS_BAR_NAVIGATION:
+ gtk_widget_show (window->navigation_bar);
+ gtk_widget_hide (window->path_bar);
+ gtk_widget_hide (window->search_bar);
+ break;
+
+ case NAUTILUS_BAR_SEARCH:
+ gtk_widget_show (window->search_bar);
+ gtk_widget_hide (window->path_bar);
+ gtk_widget_hide (window->navigation_bar);
+ break;
+ }
}
gboolean
@@ -1196,9 +1398,9 @@ nautilus_navigation_window_show (GtkWidget *widget)
}
if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY)) {
- nautilus_navigation_window_hide_path_bar (window);
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_NAVIGATION);
} else {
- nautilus_navigation_window_show_path_bar (window);
+ nautilus_navigation_window_set_bar_mode (window, NAUTILUS_BAR_PATH);
}
if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_START_WITH_SIDEBAR)) {
@@ -1271,8 +1473,9 @@ nautilus_navigation_window_class_init (NautilusNavigationWindowClass *class)
NAUTILUS_WINDOW_CLASS (class)->set_content_view_widget = real_set_content_view_widget;
NAUTILUS_WINDOW_CLASS (class)->set_throbber_active = real_set_throbber_active;
NAUTILUS_WINDOW_CLASS (class)->prompt_for_location = real_prompt_for_location;
+ NAUTILUS_WINDOW_CLASS (class)->set_search_mode = real_set_search_mode;
NAUTILUS_WINDOW_CLASS (class)->set_title = real_set_title;
NAUTILUS_WINDOW_CLASS (class)->get_icon_name = real_get_icon_name;
- NAUTILUS_WINDOW_CLASS(class)->get_default_size = real_get_default_size;
+ NAUTILUS_WINDOW_CLASS (class)->get_default_size = real_get_default_size;
NAUTILUS_WINDOW_CLASS (class)->close = real_window_close;
}
diff --git a/src/nautilus-navigation-window.h b/src/nautilus-navigation-window.h
index afefcca77..aa4988d8a 100644
--- a/src/nautilus-navigation-window.h
+++ b/src/nautilus-navigation-window.h
@@ -60,6 +60,7 @@ struct _NautilusNavigationWindow {
GtkWidget *view_as_combo_box;
GtkWidget *navigation_bar;
GtkWidget *path_bar;
+ GtkWidget *search_bar;
/* Back/Forward chain, and history list.
* The data in these lists are NautilusBookmark pointers.
@@ -97,6 +98,8 @@ void nautilus_navigation_window_hide_path_bar (NautilusNavigationWind
void nautilus_navigation_window_show_path_bar (NautilusNavigationWindow *window);
gboolean nautilus_navigation_window_path_bar_showing (NautilusNavigationWindow *window);
+gboolean nautilus_navigation_window_search_bar_showing (NautilusNavigationWindow *window);
+
gboolean nautilus_navigation_window_location_bar_showing (NautilusNavigationWindow *window);
void nautilus_navigation_window_hide_toolbar (NautilusNavigationWindow *window);
void nautilus_navigation_window_show_toolbar (NautilusNavigationWindow *window);
@@ -114,5 +117,6 @@ gboolean nautilus_navigation_window_status_bar_showing (NautilusNavigationWind
void nautilus_navigation_window_back_or_forward (NautilusNavigationWindow *window,
gboolean back,
guint distance);
+void nautilus_navigation_window_show_search (NautilusNavigationWindow *window);
#endif
diff --git a/src/nautilus-query-editor.c b/src/nautilus-query-editor.c
new file mode 100644
index 000000000..cbc8dd728
--- /dev/null
+++ b/src/nautilus-query-editor.c
@@ -0,0 +1,1141 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ *
+ */
+
+#include <config.h>
+#include "nautilus-query-editor.h"
+
+#include <string.h>
+#include <libnautilus-private/nautilus-marshal.h>
+#include <glib/gi18n.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-glib-extensions.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkbindings.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkcombobox.h>
+#include "gtk/gtkliststore.h"
+#include <gtk/gtkfilechooserbutton.h>
+#include "gtk/gtkcelllayout.h"
+#include "gtk/gtkcellrenderertext.h"
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-mime-info.h>
+
+typedef enum {
+ NAUTILUS_QUERY_EDITOR_ROW_LOCATION,
+ NAUTILUS_QUERY_EDITOR_ROW_TYPE,
+
+ NAUTILUS_QUERY_EDITOR_ROW_LAST
+} NautilusQueryEditorRowType;
+
+typedef struct {
+ NautilusQueryEditorRowType type;
+ NautilusQueryEditor *editor;
+ GtkWidget *hbox;
+ GtkWidget *combo;
+
+ GtkWidget *type_widget;
+
+ void *data;
+} NautilusQueryEditorRow;
+
+
+typedef struct {
+ const char *name;
+ GtkWidget * (*create_widgets) (NautilusQueryEditorRow *row);
+ void (*add_to_query) (NautilusQueryEditorRow *row,
+ NautilusQuery *query);
+ void (*free_data) (NautilusQueryEditorRow *row);
+ void (*add_rows_from_query) (NautilusQueryEditor *editor,
+ NautilusQuery *query);
+} NautilusQueryEditorRowOps;
+
+struct NautilusQueryEditorDetails {
+ gboolean is_indexed;
+ GtkWidget *entry;
+ gboolean change_frozen;
+ guint typing_timeout_id;
+ gboolean is_visible;
+ GtkWidget *invisible_vbox;
+ GtkWidget *visible_vbox;
+
+ GList *rows;
+
+ NautilusSearchBar *bar;
+};
+
+enum {
+ CHANGED,
+ CANCEL,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void nautilus_query_editor_class_init (NautilusQueryEditorClass *class);
+static void nautilus_query_editor_init (NautilusQueryEditor *editor);
+
+static void entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor);
+static void entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor);
+static void nautilus_query_editor_changed_force (NautilusQueryEditor *editor,
+ gboolean force);
+static void nautilus_query_editor_changed (NautilusQueryEditor *editor);
+static NautilusQueryEditorRow * nautilus_query_editor_add_row (NautilusQueryEditor *editor,
+ NautilusQueryEditorRowType type);
+
+static GtkWidget *location_row_create_widgets (NautilusQueryEditorRow *row);
+static void location_row_add_to_query (NautilusQueryEditorRow *row,
+ NautilusQuery *query);
+static void location_row_free_data (NautilusQueryEditorRow *row);
+static void location_add_rows_from_query (NautilusQueryEditor *editor,
+ NautilusQuery *query);
+static GtkWidget *type_row_create_widgets (NautilusQueryEditorRow *row);
+static void type_row_add_to_query (NautilusQueryEditorRow *row,
+ NautilusQuery *query);
+static void type_row_free_data (NautilusQueryEditorRow *row);
+static void type_add_rows_from_query (NautilusQueryEditor *editor,
+ NautilusQuery *query);
+
+
+
+static NautilusQueryEditorRowOps row_type[] = {
+ { N_("Location"),
+ location_row_create_widgets,
+ location_row_add_to_query,
+ location_row_free_data,
+ location_add_rows_from_query
+ },
+ { N_("File Type"),
+ type_row_create_widgets,
+ type_row_add_to_query,
+ type_row_free_data,
+ type_add_rows_from_query
+ },
+};
+
+EEL_CLASS_BOILERPLATE (NautilusQueryEditor,
+ nautilus_query_editor,
+ GTK_TYPE_VBOX)
+
+static void
+nautilus_query_editor_finalize (GObject *object)
+{
+ NautilusQueryEditor *editor;
+
+ editor = NAUTILUS_QUERY_EDITOR (object);
+
+ g_free (editor->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+nautilus_query_editor_dispose (GObject *object)
+{
+ NautilusQueryEditor *editor;
+
+ editor = NAUTILUS_QUERY_EDITOR (object);
+
+
+ if (editor->details->bar != NULL) {
+ g_signal_handlers_disconnect_by_func (editor->details->entry,
+ entry_activate_cb,
+ editor);
+ g_signal_handlers_disconnect_by_func (editor->details->entry,
+ entry_changed_cb,
+ editor);
+
+ nautilus_search_bar_return_entry (editor->details->bar);
+ eel_remove_weak_pointer (&editor->details->bar);
+ }
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+nautilus_query_editor_class_init (NautilusQueryEditorClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkBindingSet *binding_set;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = nautilus_query_editor_finalize;
+ gobject_class->dispose = nautilus_query_editor_dispose;
+
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusQueryEditorClass, changed),
+ NULL, NULL,
+ nautilus_marshal_VOID__OBJECT_BOOLEAN,
+ G_TYPE_NONE, 2, NAUTILUS_TYPE_QUERY, G_TYPE_BOOLEAN);
+
+ signals[CANCEL] =
+ g_signal_new ("cancel",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
+ G_STRUCT_OFFSET (NautilusQueryEditorClass, cancel),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ binding_set = gtk_binding_set_by_class (class);
+ gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "cancel", 0);
+}
+
+static void
+entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor)
+{
+ if (editor->details->typing_timeout_id) {
+ g_source_remove (editor->details->typing_timeout_id);
+ editor->details->typing_timeout_id = 0;
+ }
+
+ nautilus_query_editor_changed_force (editor, TRUE);
+}
+
+static gboolean
+typing_timeout_cb (gpointer user_data)
+{
+ NautilusQueryEditor *editor;
+
+ editor = NAUTILUS_QUERY_EDITOR (user_data);
+
+ nautilus_query_editor_changed (editor);
+
+ editor->details->typing_timeout_id = 0;
+
+ return FALSE;
+}
+
+#define TYPING_TIMEOUT 750
+
+static void
+entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor)
+{
+ if (editor->details->change_frozen) {
+ return;
+ }
+
+ if (editor->details->typing_timeout_id) {
+ g_source_remove (editor->details->typing_timeout_id);
+ }
+
+ editor->details->typing_timeout_id =
+ g_timeout_add (TYPING_TIMEOUT,
+ typing_timeout_cb,
+ editor);
+}
+
+static void
+edit_clicked (GtkButton *button, NautilusQueryEditor *editor)
+{
+ nautilus_query_editor_set_visible (editor, TRUE);
+}
+
+/* Location */
+
+static GtkWidget *
+location_row_create_widgets (NautilusQueryEditorRow *row)
+{
+ GtkWidget *chooser;
+
+ chooser = gtk_file_chooser_button_new (_("Select folder search in"),
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
+ g_get_home_dir ());
+ gtk_widget_show (chooser);
+
+ g_signal_connect_swapped (chooser, "current-folder-changed",
+ G_CALLBACK (nautilus_query_editor_changed),
+ row->editor);
+
+ gtk_box_pack_start (GTK_BOX (row->hbox), chooser, FALSE, FALSE, 0);
+
+ return chooser;
+}
+
+static void
+location_row_add_to_query (NautilusQueryEditorRow *row,
+ NautilusQuery *query)
+{
+ char *folder, *uri;
+
+ folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (row->type_widget));
+ uri = gnome_vfs_get_uri_from_local_path (folder);
+ g_free (folder);
+
+ nautilus_query_set_location (query, uri);
+ g_free (uri);
+}
+
+static void
+location_row_free_data (NautilusQueryEditorRow *row)
+{
+}
+
+static void
+location_add_rows_from_query (NautilusQueryEditor *editor,
+ NautilusQuery *query)
+{
+ NautilusQueryEditorRow *row;
+ char *uri, *folder;
+
+ uri = nautilus_query_get_location (query);
+
+ if (uri == NULL) {
+ return;
+ }
+ folder = gnome_vfs_get_local_path_from_uri (uri);
+ g_free (uri);
+ if (folder == NULL) {
+ return;
+ }
+
+ row = nautilus_query_editor_add_row (editor,
+ NAUTILUS_QUERY_EDITOR_ROW_LOCATION);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (row->type_widget),
+ folder);
+
+ g_free (folder);
+}
+
+
+/* Type */
+
+static gboolean
+type_separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ char *text;
+ gboolean res;
+
+ gtk_tree_model_get (model, iter, 0, &text, -1);
+
+ res = strcmp (text, "---") == 0;
+
+ g_free (text);
+ return res;
+}
+
+struct {
+ char *name;
+ char *mimetypes[20];
+} mime_type_groups[] = {
+ { N_("Documents"),
+ { "application/rtf",
+ "application/msword",
+ "application/vnd.sun.xml.writer",
+ "application/vnd.sun.xml.writer.global",
+ "application/vnd.sun.xml.writer.template",
+ "application/vnd.oasis.opendocument.text",
+ "application/vnd.oasis.opendocument.text-template",
+ "application/x-abiword",
+ "application/x-applix-word",
+ "application/x-mswrite",
+ "application/docbook+xml",
+ "application/x-kword",
+ "application/x-kword-crypt",
+ "application/x-lyx",
+ NULL
+ }
+ },
+ { N_("Music"),
+ { "application/ogg",
+ "audio/ac3",
+ "audio/basic",
+ "audio/midi",
+ "audio/x-flac",
+ "audio/mp4",
+ "audio/mpeg",
+ "audio/x-mpeg",
+ "audio/x-ms-asx",
+ "audio/x-pn-realaudio",
+ NULL
+ }
+ },
+ { N_("Video"),
+ { "video/mp4",
+ "video/3gpp",
+ "video/mpeg",
+ "video/quicktime",
+ "video/vivo",
+ "video/x-avi",
+ "video/x-mng",
+ "video/x-ms-asf",
+ "video/x-ms-wmv",
+ "video/x-msvideo",
+ "video/x-nsv",
+ "video/x-real-video",
+ NULL
+ }
+ },
+ { N_("Picture"),
+ { "application/vnd.oasis.opendocument.image",
+ "application/x-krita",
+ "image/bmp",
+ "image/cgm",
+ "image/gif",
+ "image/jpeg",
+ "image/jpeg2000",
+ "image/png",
+ "image/svg+xml",
+ "image/tiff",
+ "image/x-compressed-xcf",
+ "image/x-pcx",
+ "image/x-photo-cd",
+ "image/x-psd",
+ "image/x-tga",
+ "image/x-xcf",
+ NULL
+ }
+ },
+ { N_("Illustration"),
+ { "application/illustrator",
+ "application/vnd.corel-draw",
+ "application/vnd.stardivision.draw",
+ "application/vnd.oasis.opendocument.graphics",
+ "application/x-dia-diagram",
+ "application/x-karbon",
+ "application/x-killustrator",
+ "application/x-kivio",
+ "application/x-kontour",
+ "application/x-wpg",
+ NULL
+ }
+ },
+ { N_("Spreadsheet"),
+ { "application/vnd.lotus-1-2-3",
+ "application/vnd.ms-excel",
+ "application/vnd.stardivision.calc",
+ "application/vnd.sun.xml.calc",
+ "application/vnd.oasis.opendocument.spreadsheet",
+ "application/x-applix-spreadsheet",
+ "application/x-gnumeric",
+ "application/x-kspread",
+ "application/x-kspread-crypt",
+ "application/x-quattropro",
+ "application/x-sc",
+ "application/x-siag",
+ NULL
+ }
+ },
+ { N_("Presentation"),
+ { "application/vnd.ms-powerpoint",
+ "application/vnd.sun.xml.impress",
+ "application/vnd.oasis.opendocument.presentation",
+ "application/x-magicpoint",
+ "application/x-kpresenter",
+ NULL
+ }
+ },
+ { N_("Pdf / Postscript"),
+ { "application/pdf",
+ "application/postscript",
+ "application/x-dvi",
+ "image/x-eps",
+ NULL
+ }
+ },
+ { N_("Text File"),
+ { "text/plain",
+ NULL
+ }
+ }
+};
+
+static void
+type_combo_changed (GtkComboBox *combo_box, NautilusQueryEditorRow *row)
+{
+ GtkTreeIter iter;
+ gboolean other;
+ GtkTreeModel *model;
+
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
+ &iter)) {
+ return;
+ }
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
+ gtk_tree_model_get (model, &iter, 3, &other, -1);
+
+ if (other) {
+ /* TODO: Ask for other mimetype and add it to list + select it */
+ /* But can't read list of mimetypes atm */
+ }
+
+ nautilus_query_editor_changed (row->editor);
+}
+
+static void
+type_add_custom_type (NautilusQueryEditorRow *row,
+ const char *mime_type,
+ const char *description,
+ GtkTreeIter *iter)
+{
+ GtkTreeModel *model;
+ GtkListStore *store;
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
+ store = GTK_LIST_STORE (model);
+
+ gtk_list_store_append (store, iter);
+ gtk_list_store_set (store, iter,
+ 0, description,
+ 2, mime_type,
+ -1);
+}
+
+
+static GtkWidget *
+type_row_create_widgets (NautilusQueryEditorRow *row)
+{
+ GtkWidget *combo;
+ GtkCellRenderer *cell;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ int i;
+
+ store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
+ "text", 0,
+ NULL);
+ gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
+ type_separator_func,
+ NULL, NULL);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _("Any"), -1);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, "---", -1);
+
+ for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++) {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, gettext (mime_type_groups[i].name),
+ 1, mime_type_groups[i].mimetypes,
+ -1);
+ }
+
+#if 0 /* Disable this for now, as there is no way to read list of mimetypes */
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, "---", -1);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, _("Other Type..."), 3, TRUE, -1);
+#endif
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+
+ g_signal_connect (combo, "changed",
+ G_CALLBACK (type_combo_changed),
+ row);
+
+ gtk_widget_show (combo);
+
+ gtk_box_pack_start (GTK_BOX (row->hbox), combo, FALSE, FALSE, 0);
+
+ return combo;
+}
+
+static void
+type_row_add_to_query (NautilusQueryEditorRow *row,
+ NautilusQuery *query)
+{
+ GtkTreeIter iter;
+ char **mimetypes;
+ char *mimetype;
+ GtkTreeModel *model;
+
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
+ &iter)) {
+ return;
+ }
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
+ gtk_tree_model_get (model, &iter, 1, &mimetypes, 2, &mimetype, -1);
+
+ if (mimetypes != NULL) {
+ while (*mimetypes != NULL) {
+ nautilus_query_add_mime_type (query, *mimetypes);
+ mimetypes++;
+ }
+ }
+ if (mimetype) {
+ nautilus_query_add_mime_type (query, mimetype);
+ g_free (mimetype);
+ }
+}
+
+static void
+type_row_free_data (NautilusQueryEditorRow *row)
+{
+}
+
+static gboolean
+all_group_types_in_list (char **group_types, GList *mime_types)
+{
+ GList *l;
+ char **group_type;
+ char *mime_type;
+ gboolean found;
+
+ group_type = group_types;
+ while (*group_type != NULL) {
+ found = FALSE;
+
+ for (l = mime_types; l != NULL; l = l->next) {
+ mime_type = l->data;
+
+ if (strcmp (mime_type, *group_type) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ return FALSE;
+ }
+ group_type++;
+ }
+ return TRUE;
+}
+
+static GList *
+remove_group_types_from_list (char **group_types, GList *mime_types)
+{
+ GList *l, *next;
+ char **group_type;
+ char *mime_type;
+ gboolean found;
+
+ group_type = group_types;
+ while (*group_type != NULL) {
+ found = FALSE;
+
+ for (l = mime_types; l != NULL; l = next) {
+ mime_type = l->data;
+ next = l->next;
+
+ if (strcmp (mime_type, *group_type) == 0) {
+ mime_types = g_list_remove_link (mime_types, l);
+ g_free (mime_type);
+ break;
+ }
+ }
+
+ group_type++;
+ }
+ return mime_types;
+}
+
+
+static void
+type_add_rows_from_query (NautilusQueryEditor *editor,
+ NautilusQuery *query)
+{
+ GList *mime_types;
+ char *mime_type;
+ const char *desc;
+ NautilusQueryEditorRow *row;
+ GtkTreeIter iter;
+ int i;
+ GtkTreeModel *model;
+ GList *l;
+
+ mime_types = nautilus_query_get_mime_types (query);
+
+ if (mime_types == NULL) {
+ return;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++) {
+ if (all_group_types_in_list (mime_type_groups[i].mimetypes,
+ mime_types)) {
+ mime_types = remove_group_types_from_list (mime_type_groups[i].mimetypes,
+ mime_types);
+
+ row = nautilus_query_editor_add_row (editor,
+ NAUTILUS_QUERY_EDITOR_ROW_TYPE);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
+
+ gtk_tree_model_iter_nth_child (model, &iter, NULL, i + 2);
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
+ &iter);
+ }
+ }
+
+ for (l = mime_types; l != NULL; l = l->next) {
+ mime_type = l->data;
+
+ desc = gnome_vfs_mime_get_value (mime_type, "description");
+ if (desc == NULL) {
+ desc = mime_type;
+ }
+
+ row = nautilus_query_editor_add_row (editor,
+ NAUTILUS_QUERY_EDITOR_ROW_TYPE);
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
+
+ type_add_custom_type (row, mime_type, desc, &iter);
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
+ &iter);
+ }
+
+ eel_g_list_free_deep (mime_types);
+
+}
+
+/* End of row types */
+
+static NautilusQueryEditorRowType
+get_next_free_type (NautilusQueryEditor *editor)
+{
+ NautilusQueryEditorRow *row;
+ NautilusQueryEditorRowType type;
+ gboolean found;
+ GList *l;
+
+
+ for (type = 0; type < NAUTILUS_QUERY_EDITOR_ROW_LAST; type++) {
+ found = FALSE;
+ for (l = editor->details->rows; l != NULL; l = l->next) {
+ row = l->data;
+ if (row->type == type) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ return type;
+ }
+ }
+ return NAUTILUS_QUERY_EDITOR_ROW_TYPE;
+}
+
+static void
+remove_row_cb (GtkButton *clicked_button, NautilusQueryEditorRow *row)
+{
+ NautilusQueryEditor *editor;
+
+ editor = row->editor;
+ gtk_container_remove (GTK_CONTAINER (editor->details->visible_vbox),
+ row->hbox);
+
+ editor->details->rows = g_list_remove (editor->details->rows, row);
+
+ row_type[row->type].free_data (row);
+ g_free (row);
+
+ nautilus_query_editor_changed (editor);
+}
+
+static void
+create_type_widgets (NautilusQueryEditorRow *row)
+{
+ row->type_widget = row_type[row->type].create_widgets (row);
+}
+
+static void
+row_type_combo_changed_cb (GtkComboBox *combo_box, NautilusQueryEditorRow *row)
+{
+ NautilusQueryEditorRowType type;
+
+ type = gtk_combo_box_get_active (combo_box);
+
+ if (type == row->type) {
+ return;
+ }
+
+ if (row->type_widget != NULL) {
+ gtk_widget_destroy (row->type_widget);
+ row->type_widget = NULL;
+ }
+
+ row_type[row->type].free_data (row);
+ row->data = NULL;
+
+ row->type = type;
+
+ create_type_widgets (row);
+
+ nautilus_query_editor_changed (row->editor);
+}
+
+static NautilusQueryEditorRow *
+nautilus_query_editor_add_row (NautilusQueryEditor *editor,
+ NautilusQueryEditorRowType type)
+{
+ GtkWidget *hbox, *button, *image, *combo;
+ NautilusQueryEditorRow *row;
+ int i;
+
+ row = g_new0 (NautilusQueryEditorRow, 1);
+ row->editor = editor;
+ row->type = type;
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ row->hbox = hbox;
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
+
+ combo = gtk_combo_box_new_text ();
+ row->combo = combo;
+ for (i = 0; i < NAUTILUS_QUERY_EDITOR_ROW_LAST; i++) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (combo), gettext (row_type[i].name));
+ }
+ gtk_widget_show (combo);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), row->type);
+
+ editor->details->rows = g_list_append (editor->details->rows, row);
+
+ g_signal_connect (combo, "changed",
+ G_CALLBACK (row_type_combo_changed_cb), row);
+
+ create_type_widgets (row);
+
+ button = gtk_button_new ();
+ image = gtk_image_new_from_stock (GTK_STOCK_REMOVE,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_show (image);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (remove_row_cb), row);
+
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ return row;
+}
+
+static void
+go_search_cb (GtkButton *clicked_button, NautilusQueryEditor *editor)
+{
+ nautilus_query_editor_changed_force (editor, TRUE);
+}
+
+static void
+add_new_row_cb (GtkButton *clicked_button, NautilusQueryEditor *editor)
+{
+ nautilus_query_editor_add_row (editor, get_next_free_type (editor));
+ nautilus_query_editor_changed (editor);
+}
+
+static void
+nautilus_query_editor_init (NautilusQueryEditor *editor)
+{
+ GtkWidget *hbox, *label, *button;
+
+ editor->details = g_new0 (NautilusQueryEditorDetails, 1);
+ editor->details->is_visible = TRUE;
+
+ editor->details->invisible_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (editor), editor->details->invisible_vbox,
+ FALSE, FALSE, 0);
+ editor->details->visible_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (editor), editor->details->visible_vbox,
+ FALSE, FALSE, 0);
+ /* Only show visible vbox */
+ gtk_widget_show (editor->details->visible_vbox);
+
+ /* Create invisible part: */
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (editor->details->invisible_vbox),
+ hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Search Folder</b>"));
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ button = gtk_button_new_with_label (_("Edit"));
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (edit_clicked), editor);
+}
+
+void
+nautilus_query_editor_set_default_query (NautilusQueryEditor *editor)
+{
+ if (!editor->details->is_indexed) {
+ nautilus_query_editor_add_row (editor, NAUTILUS_QUERY_EDITOR_ROW_LOCATION);
+ nautilus_query_editor_changed (editor);
+ }
+}
+
+static void
+finish_first_line (NautilusQueryEditor *editor, GtkWidget *hbox, gboolean use_go)
+{
+ GtkWidget *button, *image;
+
+ button = gtk_button_new ();
+ image = gtk_image_new_from_stock (GTK_STOCK_ADD,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_show (image);
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (add_new_row_cb), editor);
+
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ if (!editor->details->is_indexed) {
+ if (use_go) {
+ button = gtk_button_new_with_label (_("Go"));
+ } else {
+ button = gtk_button_new_with_label (_("Reload"));
+ }
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (go_search_cb), editor);
+
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ }
+}
+
+static void
+setup_internal_entry (NautilusQueryEditor *editor)
+{
+ GtkWidget *hbox, *label;
+
+ /* Create visible part: */
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>_Search for:</b>"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ editor->details->entry = gtk_entry_new ();
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), editor->details->entry);
+ gtk_box_pack_start (GTK_BOX (hbox), editor->details->entry, TRUE, TRUE, 0);
+
+ g_signal_connect (editor->details->entry, "activate",
+ G_CALLBACK (entry_activate_cb), editor);
+ g_signal_connect (editor->details->entry, "changed",
+ G_CALLBACK (entry_changed_cb), editor);
+ gtk_widget_show (editor->details->entry);
+
+ finish_first_line (editor, hbox, TRUE);
+}
+
+static void
+setup_external_entry (NautilusQueryEditor *editor, GtkWidget *entry)
+{
+ GtkWidget *hbox, *label;
+
+ /* Create visible part: */
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new (_("Search results"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ editor->details->entry = entry;
+ g_signal_connect (editor->details->entry, "activate",
+ G_CALLBACK (entry_activate_cb), editor);
+ g_signal_connect (editor->details->entry, "changed",
+ G_CALLBACK (entry_changed_cb), editor);
+
+ finish_first_line (editor, hbox, FALSE);
+
+}
+
+void
+nautilus_query_editor_set_visible (NautilusQueryEditor *editor,
+ gboolean visible)
+{
+ editor->details->is_visible = visible;
+ if (visible) {
+ gtk_widget_show (editor->details->visible_vbox);
+ gtk_widget_hide (editor->details->invisible_vbox);
+ } else {
+ gtk_widget_hide (editor->details->visible_vbox);
+ gtk_widget_show (editor->details->invisible_vbox);
+ }
+}
+
+static gboolean
+query_is_valid (NautilusQueryEditor *editor)
+{
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
+
+ return text != NULL && text[0] != '\0';
+}
+
+static void
+nautilus_query_editor_changed_force (NautilusQueryEditor *editor, gboolean force_reload)
+{
+ NautilusQuery *query;
+
+ if (editor->details->change_frozen) {
+ return;
+ }
+
+ if (query_is_valid (editor)) {
+ query = nautilus_query_editor_get_query (editor);
+ g_signal_emit (editor, signals[CHANGED], 0,
+ query, editor->details->is_indexed || force_reload);
+ g_object_unref (query);
+ }
+}
+
+static void
+nautilus_query_editor_changed (NautilusQueryEditor *editor)
+{
+ nautilus_query_editor_changed_force (editor, FALSE);
+}
+
+void
+nautilus_query_editor_grab_focus (NautilusQueryEditor *editor)
+{
+ gtk_widget_grab_focus (editor->details->entry);
+}
+
+NautilusQuery *
+nautilus_query_editor_get_query (NautilusQueryEditor *editor)
+{
+ const char *query_text;
+ NautilusQuery *query;
+ GList *l;
+ NautilusQueryEditorRow *row;
+
+ query_text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
+
+ /* Empty string is a NULL query */
+ if (query_text && query_text[0] == '\0') {
+ return NULL;
+ }
+
+ query = nautilus_query_new ();
+ nautilus_query_set_text (query, query_text);
+
+ for (l = editor->details->rows; l != NULL; l = l->next) {
+ row = l->data;
+
+ row_type[row->type].add_to_query (row, query);
+ }
+
+ return query;
+}
+
+void
+nautilus_query_editor_clear_query (NautilusQueryEditor *editor)
+{
+ editor->details->change_frozen = TRUE;
+ gtk_entry_set_text (GTK_ENTRY (editor->details->entry), "");
+ editor->details->change_frozen = FALSE;
+}
+
+GtkWidget *
+nautilus_query_editor_new (gboolean start_hidden, gboolean is_indexed)
+{
+ GtkWidget *editor;
+
+ editor = g_object_new (NAUTILUS_TYPE_QUERY_EDITOR, NULL);
+
+ NAUTILUS_QUERY_EDITOR (editor)->details->is_indexed = is_indexed;
+
+ nautilus_query_editor_set_visible (NAUTILUS_QUERY_EDITOR (editor),
+ !start_hidden);
+
+ setup_internal_entry (NAUTILUS_QUERY_EDITOR (editor));
+
+ return editor;
+}
+
+GtkWidget*
+nautilus_query_editor_new_with_bar (gboolean start_hidden,
+ gboolean is_indexed,
+ NautilusSearchBar *bar)
+{
+ GtkWidget *entry;
+ NautilusQueryEditor *editor;
+
+ editor = NAUTILUS_QUERY_EDITOR (g_object_new (NAUTILUS_TYPE_QUERY_EDITOR, NULL));
+ editor->details->is_indexed = is_indexed;
+
+ nautilus_query_editor_set_visible (editor, !start_hidden);
+
+ editor->details->bar = bar;
+ eel_add_weak_pointer (&editor->details->bar);
+
+ entry = nautilus_search_bar_borrow_entry (bar);
+ setup_external_entry (editor, entry);
+
+ return GTK_WIDGET (editor);
+}
+
+void
+nautilus_query_editor_set_query (NautilusQueryEditor *editor, NautilusQuery *query)
+{
+ NautilusQueryEditorRowType type;
+ const char *text;
+
+ if (!query) {
+ nautilus_query_editor_clear_query (editor);
+ return;
+ }
+
+ text = nautilus_query_get_text (query);
+ if (!text) {
+ text = "";
+ }
+
+ editor->details->change_frozen = TRUE;
+ gtk_entry_set_text (GTK_ENTRY (editor->details->entry), text);
+
+ for (type = 0; type < NAUTILUS_QUERY_EDITOR_ROW_LAST; type++) {
+ row_type[type].add_rows_from_query (editor, query);
+ }
+
+ editor->details->change_frozen = FALSE;
+}
diff --git a/src/nautilus-query-editor.h b/src/nautilus-query-editor.h
new file mode 100644
index 000000000..38bb88e6d
--- /dev/null
+++ b/src/nautilus-query-editor.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ *
+ */
+
+#ifndef NAUTILUS_QUERY_EDITOR_H
+#define NAUTILUS_QUERY_EDITOR_H
+
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkentry.h>
+#include <libnautilus-private/nautilus-query.h>
+#include <nautilus-search-bar.h>
+
+#define NAUTILUS_TYPE_QUERY_EDITOR (nautilus_query_editor_get_type ())
+#define NAUTILUS_QUERY_EDITOR(obj) GTK_CHECK_CAST (obj, NAUTILUS_TYPE_QUERY_EDITOR, NautilusQueryEditor)
+#define NAUTILUS_QUERY_EDITOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, NAUTILUS_TYPE_QUERY_EDITOR, NautilusQueryEditorClass)
+#define NAUTILUS_IS_QUERY_EDITOR(obj) GTK_CHECK_TYPE (obj, NAUTILUS_TYPE_QUERY_EDITOR)
+
+typedef struct NautilusQueryEditorDetails NautilusQueryEditorDetails;
+
+typedef struct NautilusQueryEditor {
+ GtkVBox parent;
+ NautilusQueryEditorDetails *details;
+} NautilusQueryEditor;
+
+typedef struct {
+ GtkVBoxClass parent_class;
+
+ void (* changed) (NautilusQueryEditor *editor,
+ NautilusQuery *query,
+ gboolean reload);
+ void (* cancel) (NautilusQueryEditor *editor);
+} NautilusQueryEditorClass;
+
+GType nautilus_query_editor_get_type (void);
+GtkWidget* nautilus_query_editor_new (gboolean start_hidden,
+ gboolean is_indexed);
+GtkWidget* nautilus_query_editor_new_with_bar (gboolean start_hidden,
+ gboolean is_indexed,
+ NautilusSearchBar *bar);
+void nautilus_query_editor_set_default_query (NautilusQueryEditor *editor);
+
+void nautilus_query_editor_grab_focus (NautilusQueryEditor *editor);
+void nautilus_query_editor_clear_query (NautilusQueryEditor *editor);
+
+NautilusQuery *nautilus_query_editor_get_query (NautilusQueryEditor *editor);
+void nautilus_query_editor_set_query (NautilusQueryEditor *editor,
+ NautilusQuery *query);
+void nautilus_query_editor_set_visible (NautilusQueryEditor *editor,
+ gboolean visible);
+
+#endif /* NAUTILUS_QUERY_EDITOR_H */
diff --git a/src/nautilus-search-bar.c b/src/nautilus-search-bar.c
new file mode 100644
index 000000000..00c74e146
--- /dev/null
+++ b/src/nautilus-search-bar.c
@@ -0,0 +1,218 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2005 Novell, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ */
+
+#include <config.h>
+#include "nautilus-search-bar.h"
+
+#include <glib/gi18n.h>
+#include <eel/eel-gtk-macros.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkalignment.h>
+#include <gtk/gtkbindings.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+
+struct NautilusSearchBarDetails {
+ GtkWidget *entry;
+ gboolean entry_borrowed;
+};
+
+enum {
+ ACTIVATE,
+ CANCEL,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void nautilus_search_bar_class_init (NautilusSearchBarClass *class);
+static void nautilus_search_bar_init (NautilusSearchBar *bar);
+
+EEL_CLASS_BOILERPLATE (NautilusSearchBar,
+ nautilus_search_bar,
+ GTK_TYPE_EVENT_BOX)
+
+
+static void
+finalize (GObject *object)
+{
+ NautilusSearchBar *bar;
+
+ bar = NAUTILUS_SEARCH_BAR (object);
+
+ g_free (bar->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+nautilus_search_bar_class_init (NautilusSearchBarClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkBindingSet *binding_set;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ signals[ACTIVATE] =
+ g_signal_new ("activate",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusSearchBarClass, activate),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[CANCEL] =
+ g_signal_new ("cancel",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
+ G_STRUCT_OFFSET (NautilusSearchBarClass, cancel),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ binding_set = gtk_binding_set_by_class (class);
+ gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "cancel", 0);
+}
+
+static gboolean
+entry_has_text (NautilusSearchBar *bar)
+{
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (bar->details->entry));
+
+ return text != NULL && text[0] != '\0';
+}
+
+static void
+entry_activate_cb (GtkWidget *entry, NautilusSearchBar *bar)
+{
+ if (entry_has_text (bar) && !bar->details->entry_borrowed) {
+ g_signal_emit (bar, signals[ACTIVATE], 0);
+ }
+}
+
+
+static void
+nautilus_search_bar_init (NautilusSearchBar *bar)
+{
+ GtkWidget *alignment;
+ GtkWidget *hbox;
+ GtkWidget *label;
+
+ bar->details = g_new0 (NautilusSearchBarDetails, 1);
+
+ alignment = gtk_alignment_new (0.5, 0.5,
+ 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+ 0, 0, 6, 6);
+ gtk_widget_show (alignment);
+ gtk_container_add (GTK_CONTAINER (bar), alignment);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_container_add (GTK_CONTAINER (alignment), hbox);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), _("<b>Search:</b>"));
+ gtk_widget_show (label);
+
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ bar->details->entry = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), bar->details->entry, TRUE, TRUE, 0);
+
+ g_signal_connect (bar->details->entry, "activate",
+ G_CALLBACK (entry_activate_cb), bar);
+
+ gtk_widget_show (bar->details->entry);
+}
+
+GtkWidget *
+nautilus_search_bar_borrow_entry (NautilusSearchBar *bar)
+{
+ GtkBindingSet *binding_set;
+
+ bar->details->entry_borrowed = TRUE;
+
+ binding_set = gtk_binding_set_by_class (G_OBJECT_GET_CLASS (bar));
+ gtk_binding_entry_clear (binding_set, GDK_Escape, 0);
+ return bar->details->entry;
+}
+
+void
+nautilus_search_bar_return_entry (NautilusSearchBar *bar)
+{
+ GtkBindingSet *binding_set;
+
+ bar->details->entry_borrowed = FALSE;
+
+ binding_set = gtk_binding_set_by_class (G_OBJECT_GET_CLASS (bar));
+ gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "cancel", 0);
+}
+
+GtkWidget *
+nautilus_search_bar_new (void)
+{
+ GtkWidget *bar;
+
+ bar = g_object_new (NAUTILUS_TYPE_SEARCH_BAR, NULL);
+
+ return bar;
+}
+
+NautilusQuery *
+nautilus_search_bar_get_query (NautilusSearchBar *bar)
+{
+ const char *query_text;
+ NautilusQuery *query;
+
+ query_text = gtk_entry_get_text (GTK_ENTRY (bar->details->entry));
+
+ /* Empty string is a NULL query */
+ if (query_text && query_text[0] == '\0') {
+ return NULL;
+ }
+
+ query = nautilus_query_new ();
+ nautilus_query_set_text (query, query_text);
+
+ return query;
+}
+
+void
+nautilus_search_bar_grab_focus (NautilusSearchBar *bar)
+{
+ gtk_widget_grab_focus (bar->details->entry);
+}
+
+void
+nautilus_search_bar_clear (NautilusSearchBar *bar)
+{
+ gtk_entry_set_text (GTK_ENTRY (bar->details->entry), "");
+}
diff --git a/src/nautilus-search-bar.h b/src/nautilus-search-bar.h
new file mode 100644
index 000000000..c278caff4
--- /dev/null
+++ b/src/nautilus-search-bar.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2005 Novell, Inc.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ */
+
+#ifndef NAUTILUS_SEARCH_BAR_H
+#define NAUTILUS_SEARCH_BAR_H
+
+#include <gtk/gtkeventbox.h>
+#include <libnautilus-private/nautilus-query.h>
+
+#define NAUTILUS_TYPE_SEARCH_BAR (nautilus_search_bar_get_type ())
+#define NAUTILUS_SEARCH_BAR(obj) \
+ GTK_CHECK_CAST (obj, NAUTILUS_TYPE_SEARCH_BAR, NautilusSearchBar)
+#define NAUTILUS_SEARCH_BAR_CLASS(klass) \
+ GTK_CHECK_CLASS_CAST (klass, NAUTILUS_TYPE_SEARCH_BAR, NautilusSearchBarClass)
+#define NAUTILUS_IS_SEARCH_BAR(obj) \
+ GTK_CHECK_TYPE (obj, NAUTILUS_TYPE_SEARCH_BAR)
+
+typedef struct NautilusSearchBarDetails NautilusSearchBarDetails;
+
+typedef struct NautilusSearchBar {
+ GtkEventBox parent;
+ NautilusSearchBarDetails *details;
+} NautilusSearchBar;
+
+typedef struct {
+ GtkEventBoxClass parent_class;
+
+ void (* activate) (NautilusSearchBar *bar);
+ void (* cancel) (NautilusSearchBar *bar);
+} NautilusSearchBarClass;
+
+GType nautilus_search_bar_get_type (void);
+GtkWidget* nautilus_search_bar_new (void);
+
+GtkWidget * nautilus_search_bar_borrow_entry (NautilusSearchBar *bar);
+void nautilus_search_bar_return_entry (NautilusSearchBar *bar);
+void nautilus_search_bar_grab_focus (NautilusSearchBar *bar);
+NautilusQuery *nautilus_search_bar_get_query (NautilusSearchBar *bar);
+void nautilus_search_bar_clear (NautilusSearchBar *bar);
+
+#endif /* NAUTILUS_SEARCH_BAR_H */
diff --git a/src/nautilus-spatial-window-ui.xml b/src/nautilus-spatial-window-ui.xml
index 941450df7..eefb0d590 100644
--- a/src/nautilus-spatial-window-ui.xml
+++ b/src/nautilus-spatial-window-ui.xml
@@ -17,6 +17,7 @@
<menuitem name="Go to Templates" action="Go to Templates"/>
<menuitem name="Go to Trash" action="Go to Trash"/>
<menuitem name="Go to Burn CD" action="Go to Burn CD"/>
+ <menuitem name="Search" action="Search"/>
<separator/>
<placeholder name="Bookmarks Placeholder"/>
<separator/>
diff --git a/src/nautilus-spatial-window.c b/src/nautilus-spatial-window.c
index 67610d79b..075b37fc7 100644
--- a/src/nautilus-spatial-window.c
+++ b/src/nautilus-spatial-window.c
@@ -38,6 +38,8 @@
#include "nautilus-bookmarks-window.h"
#include "nautilus-location-dialog.h"
#include "nautilus-main.h"
+#include "nautilus-query-editor.h"
+#include "nautilus-search-bar.h"
#include "nautilus-signaller.h"
#include "nautilus-window-manage-views.h"
#include "nautilus-zoom-control.h"
@@ -77,6 +79,8 @@
#include <libnautilus-private/nautilus-program-choosing.h>
#include <libnautilus-private/nautilus-clipboard.h>
#include <libnautilus-private/nautilus-undo.h>
+#include <libnautilus-private/nautilus-search-directory.h>
+#include <libnautilus-private/nautilus-search-engine.h>
#include <math.h>
#include <sys/time.h>
@@ -98,6 +102,8 @@ struct _NautilusSpatialWindowDetails {
GtkWidget *location_label;
GtkWidget *location_icon;
+ GtkWidget *query_editor;
+
GnomeVFSURI *location;
};
@@ -288,6 +294,11 @@ nautilus_spatial_window_show (GtkWidget *widget)
window = NAUTILUS_SPATIAL_WINDOW (widget);
GTK_WIDGET_CLASS (parent_class)->show (widget);
+
+ if (NAUTILUS_WINDOW (window)->details->search_mode &&
+ window->details->query_editor != NULL) {
+ nautilus_query_editor_grab_focus (NAUTILUS_QUERY_EDITOR (window->details->query_editor));
+ }
}
static void
@@ -319,6 +330,60 @@ real_prompt_for_location (NautilusWindow *window,
gtk_widget_show (dialog);
}
+static void
+query_editor_changed_callback (NautilusSearchBar *bar,
+ NautilusQuery *query,
+ gboolean reload,
+ NautilusWindow *window)
+{
+ NautilusDirectory *directory;
+
+ directory = nautilus_directory_get_for_file (window->details->viewed_file);
+ g_assert (NAUTILUS_IS_SEARCH_DIRECTORY (directory));
+
+ nautilus_search_directory_set_query (NAUTILUS_SEARCH_DIRECTORY (directory),
+ query);
+ if (reload) {
+ nautilus_window_reload (window);
+ }
+
+ nautilus_directory_unref (directory);
+}
+
+static void
+real_set_search_mode (NautilusWindow *window, gboolean search_mode,
+ NautilusSearchDirectory *search_directory)
+{
+ NautilusSpatialWindow *spatial_window;
+ GtkWidget *query_editor;
+ NautilusQuery *query;
+
+ spatial_window = NAUTILUS_SPATIAL_WINDOW (window);
+
+ spatial_window->details->query_editor = NULL;
+
+ if (search_mode) {
+ query_editor = nautilus_query_editor_new (nautilus_search_directory_is_saved_search (search_directory),
+ nautilus_search_directory_is_indexed (search_directory));
+ spatial_window->details->query_editor = query_editor;
+
+ nautilus_window_add_extra_location_widget (window, query_editor);
+ gtk_widget_show (query_editor);
+ nautilus_query_editor_grab_focus (NAUTILUS_QUERY_EDITOR (query_editor));
+ g_signal_connect_object (query_editor, "changed",
+ G_CALLBACK (query_editor_changed_callback), window, 0);
+
+ query = nautilus_search_directory_get_query (search_directory);
+ if (query != NULL) {
+ nautilus_query_editor_set_query (NAUTILUS_QUERY_EDITOR (query_editor),
+ query);
+ g_object_unref (query);
+ } else {
+ nautilus_query_editor_set_default_query (NAUTILUS_QUERY_EDITOR (query_editor));
+ }
+ }
+}
+
static char *
real_get_icon_name (NautilusWindow *window)
{
@@ -746,6 +811,20 @@ action_edit_bookmarks_callback (GtkAction *action,
nautilus_window_edit_bookmarks (NAUTILUS_WINDOW (user_data));
}
+static void
+action_search_callback (GtkAction *action,
+ gpointer user_data)
+{
+ NautilusWindow *window;
+ char *uri;
+
+ window = NAUTILUS_WINDOW (user_data);
+
+ uri = nautilus_search_directory_generate_new_uri ();
+ nautilus_window_go_to (window, uri);
+ g_free (uri);
+}
+
static const GtkActionEntry spatial_entries[] = {
{ SPATIAL_ACTION_PLACES, NULL, N_("_Places") }, /* name, stock id, label */
{ SPATIAL_ACTION_GO_TO_LOCATION, NULL, N_("Open _Location..."), /* name, stock id, label */
@@ -763,6 +842,9 @@ static const GtkActionEntry spatial_entries[] = {
{ "Edit Bookmarks", NULL, N_("_Edit Bookmarks"), /* name, stock id, label */
"<control>b", N_("Display a window that allows editing the bookmarks in this menu"),
G_CALLBACK (action_edit_bookmarks_callback) },
+ { "Search", "gtk-find", N_("_Search"), /* name, stock id, label */
+ "<control>F", N_("Search for files"),
+ G_CALLBACK (action_search_callback) },
};
static void
@@ -770,7 +852,7 @@ nautilus_spatial_window_instance_init (NautilusSpatialWindow *window)
{
GtkRcStyle *rc_style;
GtkWidget *arrow;
- GtkWidget *hbox;
+ GtkWidget *hbox, *vbox, *eventbox, *extras_vbox;
GtkActionGroup *action_group;
GtkUIManager *ui_manager;
GtkTargetList *targets;
@@ -779,16 +861,28 @@ nautilus_spatial_window_instance_init (NautilusSpatialWindow *window)
window->details = g_new0 (NautilusSpatialWindowDetails, 1);
window->affect_spatial_window_on_next_location_change = TRUE;
- window->details->content_box =
- gtk_hbox_new (FALSE, 0);
+ vbox = gtk_vbox_new (FALSE, 0);
gtk_table_attach (GTK_TABLE (NAUTILUS_WINDOW (window)->details->table),
- window->details->content_box,
+ vbox,
/* X direction */ /* Y direction */
0, 1, 1, 4,
GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_EXPAND | GTK_FILL | GTK_SHRINK,
0, 0);
- gtk_widget_show (window->details->content_box);
+ gtk_widget_show (vbox);
+ eventbox = gtk_event_box_new ();
+ gtk_widget_set_name (eventbox, "nautilus-extra-view-widget");
+ gtk_box_pack_start (GTK_BOX (vbox), eventbox, FALSE, FALSE, 0);
+ gtk_widget_show (eventbox);
+
+ extras_vbox = gtk_vbox_new (FALSE, 0);
+ NAUTILUS_WINDOW (window)->details->extra_location_widgets = extras_vbox;
+ gtk_container_add (GTK_CONTAINER (eventbox), extras_vbox);
+
+ window->details->content_box = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), window->details->content_box, TRUE, TRUE, 0);
+ gtk_widget_show (window->details->content_box);
+
window->details->location_button = gtk_button_new ();
g_signal_connect (window->details->location_button,
"button-press-event",
@@ -861,8 +955,6 @@ nautilus_spatial_window_instance_init (NautilusSpatialWindow *window)
ui = nautilus_ui_string_get ("nautilus-spatial-window-ui.xml");
gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
-
- return;
}
static void
@@ -881,6 +973,8 @@ nautilus_spatial_window_class_init (NautilusSpatialWindowClass *class)
NAUTILUS_WINDOW_CLASS (class)->prompt_for_location =
real_prompt_for_location;
+ NAUTILUS_WINDOW_CLASS (class)->set_search_mode =
+ real_set_search_mode;
NAUTILUS_WINDOW_CLASS (class)->get_icon_name =
real_get_icon_name;
NAUTILUS_WINDOW_CLASS (class)->set_title =
diff --git a/src/nautilus-window-manage-views.c b/src/nautilus-window-manage-views.c
index 305eeb824..1384cbc61 100644
--- a/src/nautilus-window-manage-views.c
+++ b/src/nautilus-window-manage-views.c
@@ -31,6 +31,7 @@
#include "nautilus-actions.h"
#include "nautilus-application.h"
#include "nautilus-location-bar.h"
+#include "nautilus-search-bar.h"
#include "nautilus-pathbar.h"
#include "nautilus-main.h"
#include "nautilus-window-private.h"
@@ -59,6 +60,7 @@
#include <libnautilus-private/nautilus-metadata.h>
#include <libnautilus-private/nautilus-mime-actions.h>
#include <libnautilus-private/nautilus-monitor.h>
+#include <libnautilus-private/nautilus-search-directory.h>
#include <libnautilus-private/nautilus-view-factory.h>
#include <libnautilus-private/nautilus-window-info.h>
@@ -104,6 +106,8 @@ static void location_has_really_changed (NautilusWindow
static void update_for_new_location (NautilusWindow *window);
static void zoom_parameters_changed_callback (NautilusView *view,
NautilusWindow *window);
+static void update_extra_location_widgets_visibility (NautilusWindow *window);
+static void remove_extra_location_widgets (NautilusWindow *window);
void
nautilus_window_report_selection_changed (NautilusWindowInfo *window)
@@ -1139,6 +1143,8 @@ update_for_new_location (NautilusWindow *window)
{
char *new_location;
NautilusFile *file;
+ NautilusDirectory *directory;
+ gboolean location_really_changed;
new_location = window->details->pending_location;
window->details->pending_location = NULL;
@@ -1147,6 +1153,8 @@ update_for_new_location (NautilusWindow *window)
update_history (window, window->details->location_change_type, new_location);
+ location_really_changed = eel_strcmp (window->details->location, new_location) != 0;
+
/* Set the new location. */
g_free (window->details->location);
window->details->location = new_location;
@@ -1176,6 +1184,20 @@ update_for_new_location (NautilusWindow *window)
/* Load menus from nautilus extensions for this location */
nautilus_window_load_extension_menus (window);
+ if (location_really_changed) {
+ remove_extra_location_widgets (window);
+
+ directory = nautilus_directory_get (window->details->location);
+ if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
+ nautilus_window_set_search_mode (window, TRUE, NAUTILUS_SEARCH_DIRECTORY (directory));
+ } else {
+ nautilus_window_set_search_mode (window, FALSE, NULL);
+ }
+ nautilus_directory_unref (directory);
+
+ update_extra_location_widgets_visibility (window);
+ }
+
#if !NEW_UI_COMPLETE
if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
/* Check if the back and forward buttons need enabling or disabling. */
@@ -1701,3 +1723,44 @@ nautilus_window_reload (NautilusWindow *window)
g_free (location);
eel_g_list_free_deep (selection);
}
+
+static void
+remove_all (GtkWidget *widget,
+ gpointer data)
+{
+ GtkContainer *container;
+ container = GTK_CONTAINER (data);
+
+ gtk_container_remove (container, widget);
+}
+
+static void
+remove_extra_location_widgets (NautilusWindow *window)
+{
+ gtk_container_foreach (GTK_CONTAINER (window->details->extra_location_widgets),
+ remove_all,
+ window->details->extra_location_widgets);
+}
+
+void
+nautilus_window_add_extra_location_widget (NautilusWindow *window,
+ GtkWidget *widget)
+{
+ gtk_box_pack_start (GTK_BOX (window->details->extra_location_widgets),
+ widget, TRUE, TRUE, 0);
+}
+
+static void
+update_extra_location_widgets_visibility (NautilusWindow *window)
+{
+ GList *children;
+
+ children = gtk_container_get_children (GTK_CONTAINER (window->details->extra_location_widgets));
+
+ if (children != NULL) {
+ gtk_widget_show (window->details->extra_location_widgets);
+ } else {
+ gtk_widget_show (window->details->extra_location_widgets);
+ }
+ g_list_free (children);
+}
diff --git a/src/nautilus-window-menus.c b/src/nautilus-window-menus.c
index aa2c96301..2adbcf8df 100644
--- a/src/nautilus-window-menus.c
+++ b/src/nautilus-window-menus.c
@@ -39,6 +39,7 @@
#include "nautilus-window-bookmarks.h"
#include "nautilus-window-private.h"
#include "nautilus-desktop-window.h"
+#include "nautilus-search-bar.h"
#include <eel/eel-debug.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gnome-extensions.h>
@@ -65,6 +66,8 @@
#include <libnautilus-private/nautilus-icon-factory.h>
#include <libnautilus-private/nautilus-module.h>
#include <libnautilus-private/nautilus-undo-manager.h>
+#include <libnautilus-private/nautilus-search-directory.h>
+#include <libnautilus-private/nautilus-search-engine.h>
#define MENU_PATH_EXTENSION_ACTIONS "/MenuBar/File/Extension Actions"
#define POPUP_PATH_EXTENSION_ACTIONS "/background/Before Zoom Items/Extension Actions"
diff --git a/src/nautilus-window-private.h b/src/nautilus-window-private.h
index c2bf5f641..45e2242d0 100644
--- a/src/nautilus-window-private.h
+++ b/src/nautilus-window-private.h
@@ -52,6 +52,8 @@ struct NautilusWindowDetails
GtkWidget *table;
GtkWidget *statusbar;
GtkWidget *menubar;
+
+ GtkWidget *extra_location_widgets;
GtkUIManager *ui_manager;
GtkActionGroup *main_action_group; /* owned by ui_manager */
@@ -94,15 +96,18 @@ struct NautilusWindowDetails
guint location_change_at_idle_id;
NautilusWindowShowHiddenFilesMode show_hidden_files_mode;
+ gboolean search_mode;
};
struct _NautilusNavigationWindowDetails {
GtkWidget *content_paned;
+ GtkWidget *content_box;
GtkActionGroup *navigation_action_group; /* owned by ui_manager */
/* Location bar */
gboolean temporary_navigation_bar;
gboolean temporary_location_bar;
+ gboolean temporary_search_bar;
/* Side Pane */
int side_pane_width;
diff --git a/src/nautilus-window.c b/src/nautilus-window.c
index 6bd000133..365250a69 100644
--- a/src/nautilus-window.c
+++ b/src/nautilus-window.c
@@ -40,6 +40,7 @@
#include "nautilus-window-manage-views.h"
#include "nautilus-window-bookmarks.h"
#include "nautilus-zoom-control.h"
+#include "nautilus-search-bar.h"
#include <eel/eel-debug.h>
#include <eel/eel-marshal.h>
#include <eel/eel-gdk-extensions.h>
@@ -77,6 +78,7 @@
#include <libnautilus-private/nautilus-view-factory.h>
#include <libnautilus-private/nautilus-clipboard.h>
#include <libnautilus-private/nautilus-undo.h>
+#include <libnautilus-private/nautilus-search-directory.h>
#include <math.h>
#include <sys/time.h>
@@ -88,6 +90,8 @@
#define MAX_HISTORY_ITEMS 50
+#define EXTRA_VIEW_WIDGETS_BACKGROUND "#a7c6e1"
+
/* FIXME bugzilla.gnome.org 41245: hardwired sizes */
#define SIDE_PANE_MINIMUM_WIDTH 1
#define SIDE_PANE_MINIMUM_HEIGHT 400
@@ -142,7 +146,7 @@ nautilus_window_init (NautilusWindow *window)
GtkWidget *table;
GtkWidget *menu;
GtkWidget *statusbar;
-
+
window->details = g_new0 (NautilusWindowDetails, 1);
window->details->show_hidden_files_mode = NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT;
@@ -150,7 +154,7 @@ nautilus_window_init (NautilusWindow *window)
/* Set initial window title */
gtk_window_set_title (GTK_WINDOW (window), _("Nautilus"));
- table = gtk_table_new (1, 5, FALSE);
+ table = gtk_table_new (1, 6, FALSE);
window->details->table = table;
gtk_widget_show (table);
gtk_container_add (GTK_CONTAINER (window), table);
@@ -161,7 +165,7 @@ nautilus_window_init (NautilusWindow *window)
gtk_table_attach (GTK_TABLE (table),
statusbar,
/* X direction */ /* Y direction */
- 0, 1, 4, 5,
+ 0, 1, 5, 6,
GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0,
0, 0);
window->details->help_message_cid = gtk_statusbar_get_context_id
@@ -180,7 +184,6 @@ nautilus_window_init (NautilusWindow *window)
GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0,
0, 0);
-
/* Register IconFactory callback to update the window border icon
* when the icon-theme is changed.
*/
@@ -396,6 +399,20 @@ nautilus_window_get_location (NautilusWindow *window)
}
void
+nautilus_window_set_search_mode (NautilusWindow *window,
+ gboolean search_mode,
+ NautilusSearchDirectory *search_directory)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+
+ window->details->search_mode = search_mode;
+
+ EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window,
+ set_search_mode, (window, search_mode, search_directory));
+}
+
+
+void
nautilus_window_zoom_in (NautilusWindow *window)
{
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
@@ -1037,7 +1054,6 @@ nautilus_window_display_error (NautilusWindow *window, const char *error_msg)
gtk_widget_show (dialog);
}
-
static char *
real_get_title (NautilusWindow *window)
{
@@ -1558,4 +1574,14 @@ nautilus_window_class_init (NautilusWindowClass *class)
class->reload = nautilus_window_reload;
class->go_up = nautilus_window_go_up_signal;
+
+ /* Allow to set the colors of the extra view widgets */
+ gtk_rc_parse_string ("\n"
+ " style \"nautilus-extra-view-widgets-style-internal\"\n"
+ " {\n"
+ " bg[NORMAL] = \"" EXTRA_VIEW_WIDGETS_BACKGROUND "\"\n"
+ " }\n"
+ "\n"
+ " widget \"*.nautilus-extra-view-widget\" style:rc \"nautilus-extra-view-widgets-style-internal\" \n"
+ "\n");
}
diff --git a/src/nautilus-window.h b/src/nautilus-window.h
index 553b71fc9..8c656f7b6 100644
--- a/src/nautilus-window.h
+++ b/src/nautilus-window.h
@@ -29,11 +29,12 @@
#ifndef NAUTILUS_WINDOW_H
#define NAUTILUS_WINDOW_H
-#include <bonobo/bonobo-window.h>
#include <gtk/gtkuimanager.h>
+#include <gtk/gtkwindow.h>
#include <eel/eel-glib-extensions.h>
#include <libnautilus-private/nautilus-bookmark.h>
#include <libnautilus-private/nautilus-window-info.h>
+#include <libnautilus-private/nautilus-search-directory.h>
#include "nautilus-application.h"
#include "nautilus-information-panel.h"
#include "nautilus-side-pane.h"
@@ -77,6 +78,7 @@ typedef struct {
void (* set_allow_up) (NautilusWindow *window, gboolean allow);
void (* reload) (NautilusWindow *window);
void (* prompt_for_location) (NautilusWindow *window, const char *initial);
+ void (* set_search_mode) (NautilusWindow *window, gboolean search_enabled, NautilusSearchDirectory *search_directory);
void (* get_default_size) (NautilusWindow *window, guint *default_width, guint *default_height);
void (* show_window) (NautilusWindow *window);
void (* close) (NautilusWindow *window);
@@ -128,6 +130,9 @@ void nautilus_window_go_up (NautilusWindow *window
gboolean close_behind);
void nautilus_window_prompt_for_location (NautilusWindow *window,
const char *initial);
+void nautilus_window_set_search_mode (NautilusWindow *window,
+ gboolean search_mode,
+ NautilusSearchDirectory *search_directory);
void nautilus_window_launch_cd_burner (NautilusWindow *window);
void nautilus_window_update_title (NautilusWindow *window);
void nautilus_window_display_error (NautilusWindow *window,
@@ -143,5 +148,7 @@ void nautilus_window_allow_stop (NautilusWindow *window
void nautilus_window_allow_burn_cd (NautilusWindow *window,
gboolean allow);
GtkUIManager * nautilus_window_get_ui_manager (NautilusWindow *window);
+void nautilus_window_add_extra_location_widget (NautilusWindow *window,
+ GtkWidget *widget);
#endif