summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore1
-rw-r--r--ChangeLog239
-rw-r--r--configure.in37
-rw-r--r--data/.cvsignore1
-rw-r--r--data/Makefile.am20
-rw-r--r--data/nautilus.xml.in8
-rw-r--r--icons/Search.pngbin0 -> 597 bytes
-rw-r--r--icons/nautilus-desktop.pngbin0 -> 3002 bytes
-rw-r--r--icons/nautilus-file-management-properties.pngbin0 -> 2044 bytes
-rw-r--r--icons/nautilus-mini-logo.pngbin0 -> 685 bytes
-rw-r--r--icons/nautilus-server-connect.pngbin0 -> 4151 bytes
-rw-r--r--icons/side_bar_image.pngbin0 -> 495 bytes
-rw-r--r--libnautilus-private/Makefile.am23
-rw-r--r--libnautilus-private/nautilus-directory-async.c2
-rw-r--r--libnautilus-private/nautilus-directory-metafile.c114
-rw-r--r--libnautilus-private/nautilus-directory-private.h3
-rw-r--r--libnautilus-private/nautilus-directory.c39
-rw-r--r--libnautilus-private/nautilus-directory.h14
-rw-r--r--libnautilus-private/nautilus-file-dnd.c11
-rw-r--r--libnautilus-private/nautilus-file-private.h1
-rw-r--r--libnautilus-private/nautilus-file-utilities.c42
-rw-r--r--libnautilus-private/nautilus-file-utilities.h6
-rw-r--r--libnautilus-private/nautilus-file.c79
-rw-r--r--libnautilus-private/nautilus-file.h3
-rw-r--r--libnautilus-private/nautilus-icon-container.c33
-rw-r--r--libnautilus-private/nautilus-icon-container.h3
-rw-r--r--libnautilus-private/nautilus-icon-factory.c3
-rw-r--r--libnautilus-private/nautilus-icon-private.h1
-rw-r--r--libnautilus-private/nautilus-marshal.list15
-rw-r--r--libnautilus-private/nautilus-metafile-factory.c4
-rw-r--r--libnautilus-private/nautilus-metafile.c7
-rw-r--r--libnautilus-private/nautilus-query.c372
-rw-r--r--libnautilus-private/nautilus-query.h67
-rw-r--r--libnautilus-private/nautilus-saved-search-file.c62
-rw-r--r--libnautilus-private/nautilus-saved-search-file.h54
-rw-r--r--libnautilus-private/nautilus-search-directory-file.c239
-rw-r--r--libnautilus-private/nautilus-search-directory-file.h55
-rw-r--r--libnautilus-private/nautilus-search-directory.c864
-rw-r--r--libnautilus-private/nautilus-search-directory.h70
-rw-r--r--libnautilus-private/nautilus-search-engine-beagle.c289
-rw-r--r--libnautilus-private/nautilus-search-engine-beagle.h51
-rw-r--r--libnautilus-private/nautilus-search-engine-simple.c370
-rw-r--r--libnautilus-private/nautilus-search-engine-simple.h51
-rw-r--r--libnautilus-private/nautilus-search-engine.c207
-rw-r--r--libnautilus-private/nautilus-search-engine.h76
-rw-r--r--libnautilus-private/nautilus-tree-view-drag-dest.c18
-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
-rw-r--r--test/.cvsignore2
-rw-r--r--test/Makefile.am6
-rw-r--r--test/test-nautilus-directory-async.c106
-rw-r--r--test/test-nautilus-search-engine.c56
82 files changed, 6464 insertions, 506 deletions
diff --git a/.cvsignore b/.cvsignore
index d5e3cbdf3..b6db3bc11 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -25,6 +25,7 @@ nautilus.desktop
nautilus.spec
nautilus-computer.desktop
nautilus-file-management-properties.desktop
+nautilus-folder-handler.desktop
nautilus-home.desktop
obj
stamp-h
diff --git a/ChangeLog b/ChangeLog
index c066b858f..9811fb6e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,242 @@
+2005-12-06 Alexander Larsson <alexl@redhat.com>
+
+ Merge in changes from NAUTILUS_SEARCH2_MERGE_ANCHOR1 to
+ NAUTILUS_SEARCH2_MERGE_ANCHOR2 (on HEAD).
+ (This is NAUTILUS_SEARCH2_MERGE_POINT2)
+
+2005-12-12 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-file.c (nautilus_file_new_from_relative_uri):
+ Another case where we need to create a saved search file.
+
+2005-12-12 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Make it possible to build without beagle.
+
+2005-12-12 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/Makefile.am:
+ * libnautilus-private/nautilus-search-engine-simple.[ch]:
+ Add new NautilusSearchEngineSimple backend.
+
+ * libnautilus-private/nautilus-file-utilities.[ch]:
+ Add nautilus_get_home_directory_uri.
+
+ * libnautilus-private/nautilus-marshal.list:
+ Add VOID:OBJECT,BOOLEAN, sort
+
+ * libnautilus-private/nautilus-search-directory.[ch]:
+ Add nautilus_search_directory_is_indexed.
+ Make sure saved searches are never returned as search hits.
+
+ * libnautilus-private/nautilus-search-engine-beagle.[ch]:
+ Make _new fail if we can't contact beagle daemon.
+ Set text on query as one string (it can have keywords in it)
+ Move freeing of query data to after query is done.
+ Add _is_indexed
+
+ * libnautilus-private/nautilus-search-engine.[ch]:
+ Add nautilus_search_engine_is_indexed
+ Remove nautilus_search_engine_enabled
+ Use beagle if availible, otherwise simple backend.
+
+ * src/nautilus-navigation-window-menus.c:
+ Remove search disabled code
+
+ * src/nautilus-query-editor.[ch]:
+ Rename activate to changed and add reload argument
+ Add go/reload button for non-indexed searches
+ Add mnemonic for entry
+ Change saved search string to "Search Folder"
+
+ * src/nautilus-navigation-window.c:
+ Update for query editor changes
+ For indexed search engines, default to search in homedir
+
+ * src/nautilus-spatial-window.c:
+ Update for query editor changes
+ For indexed search engines, default to search in homedir
+ Remove search disabled code
+
+2005-12-07 Alexander Larsson <alexl@redhat.com>
+
+ * src/nautilus-query-editor.c (setup_external_entry):
+ Make ugly string slightly better.
+
+2005-12-07 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Mime API needs gnome-vfs-module. Unfortunate...
+
+ * libnautilus-private/nautilus-query.c:
+ Parse queries fully
+
+ * libnautilus-private/nautilus-search-engine-beagle.c:
+ Look at mime types and location.
+
+ * src/nautilus-query-editor.c:
+ Add mime type and location to query editor
+
+2005-12-06 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-query.[ch]:
+ Add new fields to NautilusQuery
+
+2005-12-06 Alexander Larsson <alexl@redhat.com>
+
+ Merge in changes from NAUTILUS_2_12_1 to
+ NAUTILUS_SEARCH2_MERGE_ANCHOR1 (on HEAD).
+ (This is NAUTILUS_SEARCH2_MERGE_POINT1)
+
+2005-12-06 Alexander Larsson <alexl@redhat.com>
+
+ * src/nautilus-history-sidebar.c: (update_history),
+ (nautilus_history_sidebar_init):
+ Fix leaks of bookmarks and model.
+
+2005-12-06 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-search-engine-beagle.c:
+ (nautilus_search_engine_beagle_set_query):
+ Unref the right query.
+
+2005-12-05 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-file-utilities.c:
+ (nautilus_compute_title_for_uri):
+ Handle NULL query in search.
+
+ * libnautilus-private/nautilus-file-utilities.h:
+ * libnautilus-private/nautilus-search-directory.h:
+ Move saved search uri/mimetype define to
+ nautilus-file-utilities.h.
+
+ * libnautilus-private/nautilus-search-directory.c:
+ Ref query in get
+
+ * libnautilus-private/nautilus-search-engine.c:
+ Remove unused stuff.
+
+ * src/Makefile.am:
+ * src/nautilus-query-editor.[ch]:
+ Add new files implementing NautilusQueryEditor
+
+ * src/nautilus-places-sidebar.c:
+ Remove search from places sidebar.
+
+ * src/nautilus-search-bar.[ch]:
+ Only handle text queries.
+
+ * src/nautilus-window.[ch]:
+ * src/nautilus-window-private.h:
+ * src/nautilus-navigation-window-menus.c:
+ * src/nautilus-window-manage-views.c:
+ extra location widgets support and some search mode changes
+
+ * src/nautilus-navigation-window.[ch]:
+ * src/nautilus-spatial-window.c:
+ Implement new search ui using extra location widgets
+
+ * src/file-manager/fm-directory-view.c:
+ Implement save search and save search as.
+ Fix free bugs in fm_directory_view_stop.
+
+ * src/file-manager/fm-icon-view.c: (fm_icon_view_supports_uri):
+ * src/file-manager/fm-list-view.c: (fm_list_view_supports_uri):
+ Also handle saved search mimetypes.
+
+
+2005-12-02 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-search-directory.[ch]:
+ More functions to save queres.
+
+ * src/file-manager/fm-actions.h:
+ * src/file-manager/fm-directory-view.c:
+ * src/file-manager/nautilus-directory-view-ui.xml:
+ Initial stubs for save search menu items.
+
+2005-12-01 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-directory.c:
+ * libnautilus-private/nautilus-search-directory.[ch]:
+ * src/nautilus-bookmark-list.c:
+ Further refactor the query loading, and remove all traces
+ of the old load/save mechanism.
+
+2005-12-01 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-directory.c:
+ * libnautilus-private/nautilus-query.[ch]:
+ * libnautilus-private/nautilus-search-directory.[ch]:
+ Refactor query loading into NautilusQuery object.
+
+2005-12-01 Alexander Larsson <alexl@redhat.com>
+
+ * configure.in:
+ Check for update-mime-database
+
+ * data/.cvsignore:
+ * data/Makefile.am:
+ * data/nautilus.xml.in:
+ Add mime database entries for saved searches.
+
+ * libnautilus-private/Makefile.am:
+ * libnautilus-private/nautilus-saved-search-file.[ch]:
+ Special file type for saved search files to pretend that
+ they are directories.
+
+ * libnautilus-private/nautilus-directory.[ch]:
+ Make nautilus_directory_ref return its arg.
+ Create NautilusSearchDirectory for saved searches.
+
+ * libnautilus-private/nautilus-file-dnd.c:
+ Non-editable directories do not accept drops.
+
+ * libnautilus-private/nautilus-file-private.h:
+ * libnautilus-private/nautilus-file.h:
+ Move nautilus_file_get_existing to public header.
+
+ * libnautilus-private/nautilus-file.c:
+ Create saved search files at right time
+
+ * libnautilus-private/nautilus-marshal.list:
+ Add new marshallers
+
+ * libnautilus-private/nautilus-monitor.c:
+ Remove some spew
+
+ * libnautilus-private/nautilus-search-directory.[ch]:
+ Split out search file loading to a separate function.
+
+ * libnautilus-private/nautilus-tree-view-drag-dest.c:
+ Handle several layers of cannot accept drop.
+
+ * src/file-manager/fm-directory-view.[ch]:
+ Make files be related to the directory they are in, since
+ a file can be in a tree multiple times, with searches.
+ Sorting us now done in base class, and inheriting classes just
+ add a compare function.
+ Fix file leak in new_folder_done.
+
+ * src/file-manager/fm-icon-view.c:
+ Update to new base class API.
+ In scroll_to_file, don't create a NautilusFile if it doesn't exist.
+
+ * src/file-manager/fm-list-model.[ch]:
+ Rearrange data so that we can have one file in multiple dirs.
+ Still problems with the same directory in multiple dirs.
+ In scroll_to_file, don't create a NautilusFile if it doesn't exist.
+ Fix leak in each_path_get_data_binder
+
+ * src/file-manager/fm-list-view.c:
+ Update to new APIs (base class and model).
+ Fix leak in fm_list_view_get_selection_foreach_func.
+
+
+--- nautilus-search2 branch ---
+
2005-12-12 Alexander Larsson <alexl@redhat.com>
* src/file-manager/fm-directory-view.c:
diff --git a/configure.in b/configure.in
index b61142e04..efcc72073 100644
--- a/configure.in
+++ b/configure.in
@@ -19,6 +19,7 @@ m4_define(rsvg_minver, 2.0.1)
m4_define(xml_minver, 2.4.7)
m4_define(startup_notification_minver, 0.8)
m4_define(exif_minver, 0.5.12)
+m4_define(beagle_minver, 0.0.12)
AC_INIT(nautilus, 2.13.3,
[http://bugzilla.gnome.org/enter_bug.cgi?product=nautilus])
@@ -85,6 +86,7 @@ PKG_CHECK_MODULES(ALL, [
glib-2.0 >= glib_minver
gnome-desktop-2.0 >= gnome_desktop_minver
gnome-vfs-2.0 >= gnome_vfs_minver
+ gnome-vfs-module-2.0 >= gnome_vfs_minver
ORBit-2.0 >= orbit_minver
pango >= pango_minver
gtk+-2.0 >= gtk_minver
@@ -224,6 +226,27 @@ PKG_CHECK_MODULES(EXIF, libexif > exif_minver, [
AC_SUBST(EXIF_LIBS)
])])
+
+dnl ==========================================================================
+dnl search implementations
+dnl ****************************
+AM_CONDITIONAL(HAVE_BEAGLE, false)
+
+dnl libbeagle checking
+
+AC_ARG_ENABLE(beagle, [ --disable-beagle build without beagle support])
+msg_beagle=no
+if test "x$enable_beagle" != "xno"; then
+ PKG_CHECK_MODULES(BEAGLE, libbeagle-0.0 >= beagle_minver, [
+ AM_CONDITIONAL(HAVE_BEAGLE, true)
+ AC_DEFINE(HAVE_BEAGLE, 1, [Define to enable beagle support])
+ ]
+ msg_beagle=yes,
+ [AM_CONDITIONAL(HAVE_BEAGLE, false)])
+ AC_SUBST(BEAGLE_CFLAGS)
+ AC_SUBST(BEAGLE_LIBS)
+fi
+
dnl ==========================================================================
dnl Turn on the additional warnings last, so -Werror doesn't affect other tests.
@@ -293,7 +316,7 @@ LIBNAUTILUS_EXTENSION_LIBS="`$PKG_CONFIG --libs $LIBNAUTILUS_EXTENSION_MODULES`"
AC_SUBST(LIBNAUTILUS_EXTENSION_LIBS)
dnl core nautilus (must list bonobo-activation and libbonobo because idldir does not respect "requires")
-CORE_MODULES="eel-2.0 librsvg-2.0 bonobo-activation-2.0 libbonobo-2.0 esound gnome-desktop-2.0 $EXTRA_CORE_MODULES"
+CORE_MODULES="eel-2.0 librsvg-2.0 bonobo-activation-2.0 libbonobo-2.0 esound gnome-desktop-2.0 gnome-vfs-module-2.0 $EXTRA_CORE_MODULES"
CORE_CFLAGS="`$PKG_CONFIG --cflags $CORE_MODULES` $x_cflags"
AC_SUBST(CORE_CFLAGS)
CORE_LIBS="`$PKG_CONFIG --libs $CORE_MODULES` $CDDA_LIBS $LIBJPEG $x_libs"
@@ -331,6 +354,17 @@ fi
AM_GCONF_SOURCE_2
+dnl ==========================================================================
+
+AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no)
+
+AC_ARG_ENABLE(update-mimedb,
+ AC_HELP_STRING([--disable-update-mimedb],
+ [disable the update-mime-database after install [default=no]]),,
+ enable_update_mimedb=yes)
+AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes)
+
+
AC_CONFIG_FILES([
Makefile
cut-n-paste-code/Makefile
@@ -362,6 +396,7 @@ nautilus-$VERSION:
prefix: ${prefix}
source code location: ${srcdir}
compiler: ${CC}
+ beagle support: $msg_beagle
profiling support: ${profiling_support}
"
diff --git a/data/.cvsignore b/data/.cvsignore
index 07c9a1a1b..60fc27a7c 100644
--- a/data/.cvsignore
+++ b/data/.cvsignore
@@ -2,3 +2,4 @@ Makefile
Makefile.in
*.desktop
*.directory
+nautilus.xml
diff --git a/data/Makefile.am b/data/Makefile.am
index 200744891..6fea76049 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,5 +1,12 @@
NULL=
+xml_in_files = nautilus.xml.in
+xml_files = $(xml_in_files:.xml.in=.xml)
+@INTLTOOL_XML_RULE@
+
+mimedir = $(datadir)/mime/packages
+mime_DATA = $(xml_files)
+
nautilusdatadir = $(datadir)/nautilus
nautilusdata_DATA = \
@@ -9,8 +16,21 @@ nautilusdata_DATA = \
$(NULL)
EXTRA_DIST = $(nautilusdata_DATA) \
+ $(xml_in_files) \
$(NULL)
+CLEANFILES = $(xml_files)
+
SUBDIRS = \
patterns \
$(NULL)
+
+install-data-hook:
+if ENABLE_UPDATE_MIMEDB
+ $(UPDATE_MIME_DATABASE) "$(DESTDIR)$(datadir)/mime"
+endif
+
+uninstall-hook:
+if ENABLE_UPDATE_MIMEDB
+ $(UPDATE_MIME_DATABASE) "$(DESTDIR)$(datadir)/mime"
+endif
diff --git a/data/nautilus.xml.in b/data/nautilus.xml.in
new file mode 100644
index 000000000..744d0d481
--- /dev/null
+++ b/data/nautilus.xml.in
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-gnome-saved-search">
+ <sub-class-of type="text/xml"/>
+ <_comment>Saved search</_comment>
+ <glob pattern="*.savedSearch"/>
+ </mime-type>
+</mime-info>
diff --git a/icons/Search.png b/icons/Search.png
new file mode 100644
index 000000000..b324cbc2b
--- /dev/null
+++ b/icons/Search.png
Binary files differ
diff --git a/icons/nautilus-desktop.png b/icons/nautilus-desktop.png
new file mode 100644
index 000000000..e3107a6e0
--- /dev/null
+++ b/icons/nautilus-desktop.png
Binary files differ
diff --git a/icons/nautilus-file-management-properties.png b/icons/nautilus-file-management-properties.png
new file mode 100644
index 000000000..05921a668
--- /dev/null
+++ b/icons/nautilus-file-management-properties.png
Binary files differ
diff --git a/icons/nautilus-mini-logo.png b/icons/nautilus-mini-logo.png
new file mode 100644
index 000000000..fe1273142
--- /dev/null
+++ b/icons/nautilus-mini-logo.png
Binary files differ
diff --git a/icons/nautilus-server-connect.png b/icons/nautilus-server-connect.png
new file mode 100644
index 000000000..cb504eb82
--- /dev/null
+++ b/icons/nautilus-server-connect.png
Binary files differ
diff --git a/icons/side_bar_image.png b/icons/side_bar_image.png
new file mode 100644
index 000000000..ee65b95af
--- /dev/null
+++ b/icons/side_bar_image.png
Binary files differ
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am
index d3abe35ca..d01102961 100644
--- a/libnautilus-private/Makefile.am
+++ b/libnautilus-private/Makefile.am
@@ -8,6 +8,7 @@ INCLUDES = \
-I$(top_srcdir)/cut-n-paste-code \
$(CORE_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS) \
+ $(BEAGLE_CFLAGS) \
-DDATADIR=\""$(datadir)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DNAUTILUS_DATADIR=\""$(datadir)/nautilus"\" \
@@ -27,8 +28,10 @@ libnautilus_private_la_LDFLAGS = \
libnautilus_private_la_LIBADD = \
$(dependency_static_libs) \
+ $(BEAGLE_LIBS) \
$(top_builddir)/libnautilus-extension/libnautilus-extension.la \
- $(CORE_LIBS)
+ $(CORE_LIBS) \
+ $(NULL)
nautilus_metafile_server_idl_sources = \
nautilus-metafile-server-stubs.c \
@@ -151,10 +154,22 @@ libnautilus_private_la_SOURCES = \
nautilus-program-choosing.h \
nautilus-recent.c \
nautilus-recent.h \
+ nautilus-saved-search-file.c \
+ nautilus-saved-search-file.h \
+ nautilus-search-directory.c \
+ nautilus-search-directory.h \
+ nautilus-search-directory-file.c \
+ nautilus-search-directory-file.h \
+ nautilus-search-engine.c \
+ nautilus-search-engine.h \
+ nautilus-search-engine-simple.c \
+ nautilus-search-engine-simple.h \
nautilus-sidebar-provider.c \
nautilus-sidebar-provider.h \
nautilus-sidebar.c \
nautilus-sidebar.h \
+ nautilus-query.c \
+ nautilus-query.h \
nautilus-thumbnails.c \
nautilus-thumbnails.h \
nautilus-trash-directory.c \
@@ -188,6 +203,12 @@ libnautilus_private_la_SOURCES = \
nautilus-window-info.h \
$(NULL)
+if HAVE_BEAGLE
+libnautilus_private_la_SOURCES += \
+ nautilus-search-engine-beagle.c
+ nautilus-search-engine-beagle.h
+endif
+
$(lib_LTLIBRARIES): $(dependency_static_libs)
$(nautilus_metafile_server_idl_sources): nautilus_metafile_server_idl_stamp
diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c
index 20e46c75b..87dc9cfee 100644
--- a/libnautilus-private/nautilus-directory-async.c
+++ b/libnautilus-private/nautilus-directory-async.c
@@ -1002,7 +1002,7 @@ directory_load_done (NautilusDirectory *directory,
}
nautilus_directory_emit_load_error (directory,
- result);
+ result, NULL);
}
/* Call the idle function right away. */
diff --git a/libnautilus-private/nautilus-directory-metafile.c b/libnautilus-private/nautilus-directory-metafile.c
index 840d96d66..d6b8ee230 100644
--- a/libnautilus-private/nautilus-directory-metafile.c
+++ b/libnautilus-private/nautilus-directory-metafile.c
@@ -158,8 +158,6 @@ get_metafile (NautilusDirectory *directory)
g_free (uri);
}
- g_assert (directory->details->metafile_corba_object != CORBA_OBJECT_NIL);
-
return directory->details->metafile_corba_object;
}
@@ -168,12 +166,19 @@ nautilus_directory_is_metadata_read (NautilusDirectory *directory)
{
CORBA_Environment ev;
gboolean result;
+ Nautilus_Metafile metafile;
g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), FALSE);
CORBA_exception_init (&ev);
- result = Nautilus_Metafile_is_read (get_metafile (directory), &ev);
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return TRUE;
+ }
+
+ result = Nautilus_Metafile_is_read (metafile, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -191,6 +196,7 @@ nautilus_directory_get_file_metadata (NautilusDirectory *directory,
char *result;
const char *non_null_default;
CORBA_char *corba_value;
+ Nautilus_Metafile metafile;
g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), g_strdup (default_metadata));
g_return_val_if_fail (!eel_str_is_empty (file_name), g_strdup (default_metadata));
@@ -201,7 +207,13 @@ nautilus_directory_get_file_metadata (NautilusDirectory *directory,
CORBA_exception_init (&ev);
- corba_value = Nautilus_Metafile_get (get_metafile (directory), file_name, key, non_null_default, &ev);
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return g_strdup (default_metadata);
+ }
+
+ corba_value = Nautilus_Metafile_get (metafile, file_name, key, non_null_default, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("Failed to get file metadata.");
@@ -235,16 +247,23 @@ nautilus_directory_get_file_metadata_list (NautilusDirectory *directory,
GList *result;
Nautilus_MetadataList *corba_value;
CORBA_unsigned_long buf_pos;
+ Nautilus_Metafile metafile;
g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
g_return_val_if_fail (!eel_str_is_empty (file_name), NULL);
g_return_val_if_fail (!eel_str_is_empty (list_key), NULL);
g_return_val_if_fail (!eel_str_is_empty (list_subkey), NULL);
- CORBA_exception_init (&ev);
+ metafile = get_metafile (directory);
- corba_value = Nautilus_Metafile_get_list (get_metafile (directory), file_name, list_key, list_subkey, &ev);
+ if (metafile == CORBA_OBJECT_NIL) {
+ return NULL;
+ }
+ CORBA_exception_init (&ev);
+
+ corba_value = Nautilus_Metafile_get_list (metafile, file_name, list_key, list_subkey, &ev);
+
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -266,11 +285,18 @@ nautilus_directory_set_file_metadata (NautilusDirectory *directory,
const char *metadata)
{
CORBA_Environment ev;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (!eel_str_is_empty (file_name));
g_return_if_fail (!eel_str_is_empty (key));
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
/* We can't pass NULL as a CORBA_string - pass "" instead.
*/
if (default_metadata == NULL) {
@@ -282,7 +308,7 @@ nautilus_directory_set_file_metadata (NautilusDirectory *directory,
CORBA_exception_init (&ev);
- Nautilus_Metafile_set (get_metafile (directory), file_name, key, default_metadata, metadata, &ev);
+ Nautilus_Metafile_set (metafile, file_name, key, default_metadata, metadata, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -296,7 +322,7 @@ nautilus_directory_set_file_metadata_list (NautilusDirectory *directory,
GList *list)
{
CORBA_Environment ev;
-
+ Nautilus_Metafile metafile;
Nautilus_MetadataList *corba_list;
int len;
int buf_pos;
@@ -306,7 +332,13 @@ nautilus_directory_set_file_metadata_list (NautilusDirectory *directory,
g_return_if_fail (!eel_str_is_empty (file_name));
g_return_if_fail (!eel_str_is_empty (list_key));
g_return_if_fail (!eel_str_is_empty (list_subkey));
-
+
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
len = g_list_length (list);
corba_list = Nautilus_MetadataList__alloc ();
@@ -329,7 +361,7 @@ nautilus_directory_set_file_metadata_list (NautilusDirectory *directory,
CORBA_exception_init (&ev);
- Nautilus_Metafile_set_list (get_metafile (directory), file_name, list_key, list_subkey, corba_list, &ev);
+ Nautilus_Metafile_set_list (metafile, file_name, list_key, list_subkey, corba_list, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -438,17 +470,24 @@ nautilus_directory_copy_file_metadata (NautilusDirectory *source_directory,
{
CORBA_Environment ev;
char *destination_uri;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (source_directory));
g_return_if_fail (source_file_name != NULL);
g_return_if_fail (NAUTILUS_IS_DIRECTORY (destination_directory));
g_return_if_fail (destination_file_name != NULL);
-
+
+ metafile = get_metafile (source_directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
destination_uri = nautilus_directory_get_uri (destination_directory);
CORBA_exception_init (&ev);
- Nautilus_Metafile_copy (get_metafile (source_directory), source_file_name,
+ Nautilus_Metafile_copy (metafile, source_file_name,
destination_uri, destination_file_name, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
@@ -462,13 +501,20 @@ nautilus_directory_remove_file_metadata (NautilusDirectory *directory,
const char *file_name)
{
CORBA_Environment ev;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (file_name != NULL);
-
+
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
CORBA_exception_init (&ev);
- Nautilus_Metafile_remove (get_metafile (directory), file_name, &ev);
+ Nautilus_Metafile_remove (metafile, file_name, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -480,14 +526,21 @@ nautilus_directory_rename_file_metadata (NautilusDirectory *directory,
const char *new_file_name)
{
CORBA_Environment ev;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (old_file_name != NULL);
g_return_if_fail (new_file_name != NULL);
-
+
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
CORBA_exception_init (&ev);
- Nautilus_Metafile_rename (get_metafile (directory), old_file_name, new_file_name, &ev);
+ Nautilus_Metafile_rename (metafile, old_file_name, new_file_name, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -498,13 +551,20 @@ nautilus_directory_rename_directory_metadata (NautilusDirectory *directory,
const char *new_directory_uri)
{
CORBA_Environment ev;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (new_directory_uri != NULL);
-
+
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
CORBA_exception_init (&ev);
- Nautilus_Metafile_rename_directory (get_metafile (directory), new_directory_uri, &ev);
+ Nautilus_Metafile_rename_directory (metafile, new_directory_uri, &ev);
/* FIXME bugzilla.gnome.org 46664: examine ev for errors */
CORBA_exception_free (&ev);
@@ -514,6 +574,7 @@ void
nautilus_directory_register_metadata_monitor (NautilusDirectory *directory)
{
CORBA_Environment ev;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
@@ -522,12 +583,18 @@ nautilus_directory_register_metadata_monitor (NautilusDirectory *directory)
return;
}
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
directory->details->metafile_monitor = nautilus_metafile_monitor_new (directory);
CORBA_exception_init (&ev);
Nautilus_Metafile_register_monitor
- (get_metafile (directory),
+ (metafile,
BONOBO_OBJREF (directory->details->metafile_monitor),
&ev);
@@ -539,14 +606,21 @@ void
nautilus_directory_unregister_metadata_monitor (NautilusDirectory *directory)
{
CORBA_Environment ev;
+ Nautilus_Metafile metafile;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (NAUTILUS_IS_METAFILE_MONITOR (directory->details->metafile_monitor));
+ metafile = get_metafile (directory);
+
+ if (metafile == CORBA_OBJECT_NIL) {
+ return;
+ }
+
CORBA_exception_init (&ev);
Nautilus_Metafile_unregister_monitor
- (get_metafile (directory),
+ (metafile,
BONOBO_OBJREF (directory->details->metafile_monitor),
&ev);
diff --git a/libnautilus-private/nautilus-directory-private.h b/libnautilus-private/nautilus-directory-private.h
index 4c0cf4e0c..930084f93 100644
--- a/libnautilus-private/nautilus-directory-private.h
+++ b/libnautilus-private/nautilus-directory-private.h
@@ -192,7 +192,8 @@ void nautilus_directory_emit_change_signals (NautilusD
void emit_change_signals_for_all_files (NautilusDirectory *directory);
void nautilus_directory_emit_done_loading (NautilusDirectory *directory);
void nautilus_directory_emit_load_error (NautilusDirectory *directory,
- GnomeVFSResult error_result);
+ GnomeVFSResult error_result,
+ const char *error_message);
NautilusDirectory *nautilus_directory_get_internal (const char *uri,
gboolean create);
char * nautilus_directory_get_name_for_self_as_new_file (NautilusDirectory *directory);
diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c
index 4831480f5..c31b345ca 100644
--- a/libnautilus-private/nautilus-directory.c
+++ b/libnautilus-private/nautilus-directory.c
@@ -30,8 +30,10 @@
#include "nautilus-file-attributes.h"
#include "nautilus-file-private.h"
#include "nautilus-file-utilities.h"
+#include "nautilus-search-directory.h"
#include "nautilus-global-preferences.h"
#include "nautilus-lib-self-check-functions.h"
+#include "nautilus-marshal.h"
#include "nautilus-metadata.h"
#include "nautilus-metafile.h"
#include "nautilus-desktop-directory.h"
@@ -71,6 +73,7 @@ static void nautilus_directory_class_init (NautilusDirectoryClass
static NautilusDirectory *nautilus_directory_new (const char *uri);
static char * real_get_name_for_self_as_new_file (NautilusDirectory *directory);
static GList * real_get_file_list (NautilusDirectory *directory);
+static gboolean real_is_editable (NautilusDirectory *directory);
static void set_directory_uri (NautilusDirectory *directory,
const char *new_uri);
@@ -117,11 +120,12 @@ nautilus_directory_class_init (NautilusDirectoryClass *klass)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NautilusDirectoryClass, 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);
klass->get_name_for_self_as_new_file = real_get_name_for_self_as_new_file;
klass->get_file_list = real_get_file_list;
+ klass->is_editable = real_is_editable;
g_type_class_add_private (klass, sizeof (NautilusDirectoryDetails));
}
@@ -143,16 +147,17 @@ nautilus_directory_init (gpointer object, gpointer klass)
directory->details->hidden_file_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
-void
+NautilusDirectory *
nautilus_directory_ref (NautilusDirectory *directory)
{
if (directory == NULL) {
- return;
+ return directory;
}
- g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
+ g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
g_object_ref (directory);
+ return directory;
}
void
@@ -515,6 +520,10 @@ nautilus_directory_new (const char *uri)
directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_TRASH_DIRECTORY, NULL));
} else if (eel_uri_is_desktop (uri)) {
directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY, NULL));
+ } else if (eel_uri_is_search (uri)) {
+ directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY, NULL));
+ } else if (g_str_has_suffix (uri, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
+ directory = NAUTILUS_DIRECTORY (nautilus_search_directory_new_from_saved_search (uri));
} else {
directory = NAUTILUS_DIRECTORY (g_object_new (NAUTILUS_TYPE_VFS_DIRECTORY, NULL));
}
@@ -764,11 +773,12 @@ nautilus_directory_emit_done_loading (NautilusDirectory *directory)
void
nautilus_directory_emit_load_error (NautilusDirectory *directory,
- GnomeVFSResult error_result)
+ GnomeVFSResult error_result,
+ const char *error_message)
{
g_signal_emit (directory,
signals[LOAD_ERROR], 0,
- error_result);
+ error_result, error_message);
}
@@ -994,7 +1004,6 @@ nautilus_directory_notify_files_added (GList *uris)
nautilus_directory_unref (directory);
}
-
/* Now get file info for the new files. This creates NautilusFile
* objects for the new files, and sends out a files_added signal.
*/
@@ -1652,6 +1661,20 @@ real_get_file_list (NautilusDirectory *directory)
return non_tentative_files;
}
+static gboolean
+real_is_editable (NautilusDirectory *directory)
+{
+ return TRUE;
+}
+
+gboolean
+nautilus_directory_is_editable (NautilusDirectory *directory)
+{
+ return EEL_CALL_METHOD_WITH_RETURN_VALUE
+ (NAUTILUS_DIRECTORY_CLASS, directory,
+ is_editable, (directory));
+}
+
GList *
nautilus_directory_match_pattern (NautilusDirectory *directory, const char *pattern)
{
diff --git a/libnautilus-private/nautilus-directory.h b/libnautilus-private/nautilus-directory.h
index c708daaaa..10571bb4a 100644
--- a/libnautilus-private/nautilus-directory.h
+++ b/libnautilus-private/nautilus-directory.h
@@ -100,7 +100,9 @@ typedef struct
*/
void (* done_loading) (NautilusDirectory *directory);
- void (* load_error) (NautilusDirectory *directory);
+ void (* load_error) (NautilusDirectory *directory,
+ GnomeVFSResult error_result,
+ const char *error_message);
/*** Virtual functions for subclasses to override. ***/
gboolean (* contains_file) (NautilusDirectory *directory,
@@ -134,6 +136,12 @@ typedef struct
* the list of standard icons (Computer, Home, Trash) on the desktop.
*/
GList * (* get_file_list) (NautilusDirectory *directory);
+
+ /* Should return FALSE if the directory is read-only and doesn't
+ * allow setting of metadata.
+ * An example of this is the search directory.
+ */
+ gboolean (* is_editable) (NautilusDirectory *directory);
} NautilusDirectoryClass;
/* Basic GObject requirements. */
@@ -151,7 +159,7 @@ NautilusDirectory *nautilus_directory_get_for_file (NautilusFile
* 1) You don't have to cast to GtkObject *, so using these is type safe.
* 2) You are allowed to call these with NULL,
*/
-void nautilus_directory_ref (NautilusDirectory *directory);
+NautilusDirectory *nautilus_directory_ref (NautilusDirectory *directory);
void nautilus_directory_unref (NautilusDirectory *directory);
/* Access to a URI. */
@@ -227,5 +235,7 @@ GList * nautilus_directory_list_sort_by_uri (GList
/* Fast way to check if a directory is the desktop directory */
gboolean nautilus_directory_is_desktop_directory (NautilusDirectory *directory);
+gboolean nautilus_directory_is_editable (NautilusDirectory *directory);
+
#endif /* NAUTILUS_DIRECTORY_H */
diff --git a/libnautilus-private/nautilus-file-dnd.c b/libnautilus-private/nautilus-file-dnd.c
index fd55a3d5c..4729831d6 100644
--- a/libnautilus-private/nautilus-file-dnd.c
+++ b/libnautilus-private/nautilus-file-dnd.c
@@ -28,6 +28,7 @@
#include "nautilus-desktop-icon-file.h"
#include "nautilus-dnd.h"
+#include "nautilus-directory.h"
#include <eel/eel-glib-extensions.h>
#include <eel/eel-string.h>
@@ -35,14 +36,20 @@ gboolean
nautilus_drag_can_accept_item (NautilusFile *drop_target_item,
const char *item_uri)
{
+ NautilusDirectory *directory;
+ gboolean res;
+
if (nautilus_file_matches_uri (drop_target_item, item_uri)) {
/* can't accept itself */
return FALSE;
}
if (nautilus_file_is_directory (drop_target_item)) {
- /* target is a directory, accept anything */
- return TRUE;
+ /* target is a directory, accept if editable */
+ directory = nautilus_directory_get_for_file (drop_target_item);
+ res = nautilus_directory_is_editable (directory);
+ nautilus_directory_unref (directory);
+ return res;
}
if (NAUTILUS_IS_DESKTOP_ICON_FILE (drop_target_item)) {
diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h
index 24466f8ab..7faae5a85 100644
--- a/libnautilus-private/nautilus-file-private.h
+++ b/libnautilus-private/nautilus-file-private.h
@@ -151,7 +151,6 @@ struct NautilusFileDetails
NautilusFile *nautilus_file_new_from_info (NautilusDirectory *directory,
GnomeVFSFileInfo *info);
-NautilusFile *nautilus_file_get_existing (const char *uri);
void nautilus_file_emit_changed (NautilusFile *file);
void nautilus_file_mark_gone (NautilusFile *file);
gboolean nautilus_file_info_missing (NautilusFile *file,
diff --git a/libnautilus-private/nautilus-file-utilities.c b/libnautilus-private/nautilus-file-utilities.c
index d5fc80833..0f4fbc74f 100644
--- a/libnautilus-private/nautilus-file-utilities.c
+++ b/libnautilus-private/nautilus-file-utilities.c
@@ -30,6 +30,7 @@
#include "nautilus-metadata.h"
#include "nautilus-metafile.h"
#include "nautilus-file.h"
+#include "nautilus-search-directory.h"
#include <eel/eel-glib-extensions.h>
#include <eel/eel-string.h>
#include <eel/eel-vfs-extensions.h>
@@ -56,10 +57,26 @@ nautilus_compute_title_for_uri (const char *text_uri)
GnomeVFSURI *uri;
char *title, *displayname;
const char *hostname;
-
+ NautilusDirectory *directory;
+ NautilusQuery *query;
hostname = NULL;
if (text_uri) {
+ if (eel_uri_is_search (text_uri)) {
+ directory = nautilus_directory_get (text_uri);
+
+ query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
+ nautilus_directory_unref (directory);
+
+ if (query != NULL) {
+ title = nautilus_query_to_readable_string (query);
+ g_object_unref (query);
+ } else {
+ title = g_strdup (_("Search"));
+ }
+
+ return title;
+ }
file = nautilus_file_get (text_uri);
uri = gnome_vfs_uri_new (text_uri);
if (uri && !gnome_vfs_uri_is_local (uri)) {
@@ -208,6 +225,13 @@ nautilus_get_desktop_directory_uri_no_create (void)
}
char *
+nautilus_get_home_directory_uri (void)
+{
+ return gnome_vfs_get_uri_from_local_path (g_get_home_dir ());
+}
+
+
+char *
nautilus_get_templates_directory (void)
{
return g_build_filename (g_get_home_dir(),
@@ -237,6 +261,22 @@ nautilus_get_templates_directory_uri (void)
return uri;
}
+char *
+nautilus_get_searches_directory (void)
+{
+ char *user_dir;
+ char *searches_dir;
+
+ user_dir = nautilus_get_user_directory ();
+ searches_dir = g_build_filename (user_dir, "searches", NULL);
+ g_free (user_dir);
+
+ if (!g_file_test (searches_dir, G_FILE_TEST_EXISTS))
+ mkdir (searches_dir, DEFAULT_NAUTILUS_DIRECTORY_MODE);
+
+ return searches_dir;
+}
+
/* These need to be reset to NULL when desktop_is_home_dir changes */
static char *escaped_desktop_dir = NULL;
static char *escaped_desktop_dir_dirname = NULL;
diff --git a/libnautilus-private/nautilus-file-utilities.h b/libnautilus-private/nautilus-file-utilities.h
index 15b04c68c..ac8a520ea 100644
--- a/libnautilus-private/nautilus-file-utilities.h
+++ b/libnautilus-private/nautilus-file-utilities.h
@@ -27,6 +27,9 @@
#include <libgnomevfs/gnome-vfs-types.h>
+#define NAUTILUS_SAVED_SEARCH_EXTENSION ".savedSearch"
+#define NAUTILUS_SAVED_SEARCH_MIMETYPE "application/x-gnome-saved-search"
+
/* Recognizing special file names. */
gboolean nautilus_file_name_matches_hidden_pattern (const char *name_or_relative_uri);
gboolean nautilus_file_name_matches_backup_pattern (const char *name_or_relative_uri);
@@ -37,6 +40,7 @@ gboolean nautilus_file_name_matches_backup_pattern (const char *name_or_relati
char * nautilus_get_user_directory (void);
char * nautilus_get_desktop_directory (void);
char * nautilus_get_desktop_directory_uri (void);
+char * nautilus_get_home_directory_uri (void);
gboolean nautilus_is_desktop_directory_file_escaped (char *escaped_dirname,
char *escaped_filename);
gboolean nautilus_is_desktop_directory_escaped (char *escaped_dir);
@@ -49,6 +53,8 @@ char * nautilus_get_templates_directory (void);
char * nautilus_get_templates_directory_uri (void);
void nautilus_create_templates_directory (void);
+char * nautilus_get_searches_directory (void);
+
char * nautilus_compute_title_for_uri (const char *text_uri);
/* This function returns something that needs to be freed with g_free,
diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c
index bd0daa4c1..aa55dd441 100644
--- a/libnautilus-private/nautilus-file.c
+++ b/libnautilus-private/nautilus-file.c
@@ -40,10 +40,13 @@
#include "nautilus-link-desktop-file.h"
#include "nautilus-metadata.h"
#include "nautilus-module.h"
+#include "nautilus-search-directory.h"
+#include "nautilus-search-directory-file.h"
#include "nautilus-thumbnails.h"
#include "nautilus-trash-directory.h"
#include "nautilus-trash-file.h"
#include "nautilus-vfs-file.h"
+#include "nautilus-saved-search-file.h"
#include <eel/eel-debug.h>
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gtk-extensions.h>
@@ -72,12 +75,15 @@
/* Time in seconds to cache getpwuid results */
#define GETPWUID_CACHE_TIME (5*60)
+
#undef NAUTILUS_FILE_DEBUG_REF
+#undef NAUTILUS_FILE_DEBUG_REF_VALGRIND
-#ifdef NAUTILUS_FILE_DEBUG_REF
-extern void eazel_dump_stack_trace (const char *print_prefix,
- int num_levels);
-/* from libleakcheck.so */
+#ifdef NAUTILUS_FILE_DEBUG_REF_VALGRIND
+#include <valgrind/valgrind.h>
+#define DEBUG_REF_PRINTF VALGRIND_PRINTF_BACKTRACE
+#else
+#define DEBUG_REF_PRINTF printf
#endif
/* Files that start with these characters sort after files that don't. */
@@ -195,20 +201,28 @@ nautilus_file_new_from_relative_uri (NautilusDirectory *directory,
file = NULL;
g_assert_not_reached ();
}
+ } else if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
+ if (self_owned) {
+ file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NULL));
+ } else {
+ file = NULL;
+ g_assert_not_reached ();
+ }
+ } else if (g_str_has_suffix (relative_uri, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
+ file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SAVED_SEARCH_FILE, NULL));
} else {
file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
}
-#ifdef NAUTILUS_FILE_DEBUG_REF
- printf("%10p ref'd\n", file);
- eazel_dump_stack_trace ("\t", 10);
-#endif
-
nautilus_directory_ref (directory);
file->details->directory = directory;
file->details->relative_uri = g_strdup (relative_uri);
+#ifdef NAUTILUS_FILE_DEBUG_REF
+ DEBUG_REF_PRINTF("%10p ref'd", file);
+#endif
+
return file;
}
@@ -305,17 +319,23 @@ nautilus_file_new_from_info (NautilusDirectory *directory,
g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
g_return_val_if_fail (info != NULL, NULL);
- file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
-
-#ifdef NAUTILUS_FILE_DEBUG_REF
- printf("%10p ref'd\n", file);
- eazel_dump_stack_trace ("\t", 10);
-#endif
+ if (info->mime_type &&
+ strcmp (info->mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0) {
+ file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SAVED_SEARCH_FILE, NULL));
+ } else {
+ file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
+ }
nautilus_directory_ref (directory);
file->details->directory = directory;
update_info_and_name (file, info, FALSE);
+
+
+#ifdef NAUTILUS_FILE_DEBUG_REF
+ DEBUG_REF_PRINTF("%10p ref'd", file);
+#endif
+
return file;
}
@@ -397,14 +417,22 @@ nautilus_file_get_internal (const char *uri, gboolean create)
file_name = nautilus_directory_get_name_for_self_as_new_file (directory);
relative_uri = gnome_vfs_escape_string (file_name);
g_free (file_name);
- } else if (eel_uri_is_desktop (uri)) {
- /* Special case desktop files here. They have no vfs_uri */
- relative_uri_tmp = uri + strlen (EEL_DESKTOP_URI);
+ } else if (eel_uri_is_desktop (uri) ||
+ eel_uri_is_search (uri)) {
+ /* Special case virtual methods like desktop and search
+ files here. They have no vfs_uri. */
+ relative_uri_tmp = uri;
+ /* Skip "method:" */
+ while (*relative_uri_tmp != 0 && *relative_uri_tmp != ':') {
+ relative_uri_tmp++;
+ }
+ relative_uri_tmp++;
+ /* Skip initial slashes */
while (*relative_uri_tmp == '/') {
relative_uri_tmp++;
}
relative_uri = strdup (relative_uri_tmp);
- }
+ }
}
/* Check to see if it's a file that's already known. */
@@ -524,12 +552,10 @@ nautilus_file_ref (NautilusFile *file)
g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
#ifdef NAUTILUS_FILE_DEBUG_REF
- printf("%10p ref'd\n", file);
- eazel_dump_stack_trace ("\t", 10);
+ DEBUG_REF_PRINTF("%10p ref'd", file);
#endif
-
- g_object_ref (file);
- return file;
+
+ return g_object_ref (file);
}
void
@@ -542,10 +568,9 @@ nautilus_file_unref (NautilusFile *file)
g_return_if_fail (NAUTILUS_IS_FILE (file));
#ifdef NAUTILUS_FILE_DEBUG_REF
- printf("%10p unref'd\n", file);
- eazel_dump_stack_trace ("\t", 10);
+ DEBUG_REF_PRINTF("%10p unref'd", file);
#endif
-
+
g_object_unref (file);
}
diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h
index bb2562a18..d14d0e07a 100644
--- a/libnautilus-private/nautilus-file.h
+++ b/libnautilus-private/nautilus-file.h
@@ -97,6 +97,9 @@ GType nautilus_file_get_type (void);
/* Getting at a single file. */
NautilusFile * nautilus_file_get (const char *uri);
+/* Get a file only if the nautilus version already exists */
+NautilusFile * nautilus_file_get_existing (const char *uri);
+
/* Covers for gtk_object_ref and gtk_object_unref that provide two conveniences:
* 1) You don't have to cast to GtkObject *, so using these is type safe.
* 2) You are allowed to call these with NULL,
diff --git a/libnautilus-private/nautilus-icon-container.c b/libnautilus-private/nautilus-icon-container.c
index db92bb4a5..85207694f 100644
--- a/libnautilus-private/nautilus-icon-container.c
+++ b/libnautilus-private/nautilus-icon-container.c
@@ -3558,6 +3558,7 @@ motion_notify_event (GtkWidget *widget,
NautilusIconContainerDetails *details;
double world_x, world_y;
int canvas_x, canvas_y;
+ GdkDragAction actions;
container = NAUTILUS_ICON_CONTAINER (widget);
details = container->details;
@@ -3588,13 +3589,16 @@ motion_notify_event (GtkWidget *widget,
&canvas_x,
&canvas_y);
+ actions = GDK_ACTION_COPY
+ | GDK_ACTION_LINK
+ | GDK_ACTION_ASK;
+
+ if (container->details->drag_allow_moves) {
+ actions |= GDK_ACTION_MOVE;
+ }
+
nautilus_icon_dnd_begin_drag (container,
- details->drag_state == DRAG_STATE_MOVE_OR_COPY
- ? (GDK_ACTION_MOVE
- | GDK_ACTION_COPY
- | GDK_ACTION_LINK
- | GDK_ACTION_ASK)
- : GDK_ACTION_ASK,
+ actions,
details->drag_button,
event,
canvas_x,
@@ -7216,6 +7220,23 @@ nautilus_icon_container_get_icon_description (NautilusIconContainer *container,
}
}
+gboolean
+nautilus_icon_container_get_allow_moves (NautilusIconContainer *container)
+{
+ g_return_val_if_fail (NAUTILUS_IS_ICON_CONTAINER (container), FALSE);
+
+ return container->details->drag_allow_moves;
+}
+
+void
+nautilus_icon_container_set_allow_moves (NautilusIconContainer *container,
+ gboolean allow_moves)
+{
+ g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
+
+ container->details->drag_allow_moves = allow_moves;
+}
+
/* NautilusIconContainerAccessible */
static NautilusIconContainerAccessiblePrivate *
diff --git a/libnautilus-private/nautilus-icon-container.h b/libnautilus-private/nautilus-icon-container.h
index c3fe4c5ae..83b899ed8 100644
--- a/libnautilus-private/nautilus-icon-container.h
+++ b/libnautilus-private/nautilus-icon-container.h
@@ -287,5 +287,8 @@ void nautilus_icon_container_set_use_drop_shadows (Nautilu
gboolean use_drop_shadows);
char* nautilus_icon_container_get_icon_description (NautilusIconContainer *container,
NautilusIconData *data);
+gboolean nautilus_icon_container_get_allow_moves (NautilusIconContainer *container);
+void nautilus_icon_container_set_allow_moves (NautilusIconContainer *container,
+ gboolean allow_moves);
#endif /* NAUTILUS_ICON_CONTAINER_H */
diff --git a/libnautilus-private/nautilus-icon-factory.c b/libnautilus-private/nautilus-icon-factory.c
index 10ddfb888..e47f97dbe 100644
--- a/libnautilus-private/nautilus-icon-factory.c
+++ b/libnautilus-private/nautilus-icon-factory.c
@@ -830,6 +830,9 @@ get_special_icon_for_file (NautilusFile *file)
} else {
ret = ICON_NAME_TRASH_FULL;
}
+ } else if (eel_uri_is_search (uri)) {
+ /* FIXME: We really need a better icon than this */
+ ret = "gnome-searchtool";
}
g_free (uri);
diff --git a/libnautilus-private/nautilus-icon-private.h b/libnautilus-private/nautilus-icon-private.h
index ae8a993a4..442b2dfa5 100644
--- a/libnautilus-private/nautilus-icon-private.h
+++ b/libnautilus-private/nautilus-icon-private.h
@@ -155,6 +155,7 @@ struct NautilusIconContainerDetails {
DragState drag_state;
gboolean drag_started;
StretchState stretch_start;
+ gboolean drag_allow_moves;
gboolean icon_selected_on_button_down;
NautilusIcon *double_click_icon[2]; /* Both clicks in a double click need to be on the same icon */
diff --git a/libnautilus-private/nautilus-marshal.list b/libnautilus-private/nautilus-marshal.list
index 5b7826c1b..beeff9dc5 100644
--- a/libnautilus-private/nautilus-marshal.list
+++ b/libnautilus-private/nautilus-marshal.list
@@ -1,17 +1,20 @@
-STRING:VOID
-OBJECT:BOXED
BOOLEAN:POINTER
BOOLEAN:VOID
-INT:POINTER,INT
INT:POINTER,BOOLEAN
+INT:POINTER,INT
INT:POINTER,POINTER
+OBJECT:BOXED
POINTER:VOID
+STRING:VOID
VOID:DOUBLE
-VOID:STRING,ENUM,INT,INT
+VOID:INT,STRING
+VOID:OBJECT,BOOLEAN
+VOID:OBJECT,OBJECT
+VOID:POINTER,ENUM
VOID:POINTER,POINTER
VOID:POINTER,POINTER
+VOID:POINTER,POINTER,POINTER,ENUM,INT,INT
VOID:POINTER,STRING
VOID:POINTER,STRING,ENUM,INT,INT
+VOID:STRING,ENUM,INT,INT
VOID:STRING,STRING
-VOID:POINTER,POINTER,POINTER,ENUM,INT,INT
-VOID:POINTER,ENUM
diff --git a/libnautilus-private/nautilus-metafile-factory.c b/libnautilus-private/nautilus-metafile-factory.c
index eadd69336..c939b440b 100644
--- a/libnautilus-private/nautilus-metafile-factory.c
+++ b/libnautilus-private/nautilus-metafile-factory.c
@@ -54,6 +54,10 @@ corba_open (PortableServer_Servant servant,
metafile = nautilus_metafile_get (directory);
+ if (!metafile) {
+ return CORBA_OBJECT_NIL;
+ }
+
return CORBA_Object_duplicate (BONOBO_OBJREF (metafile), ev);
}
diff --git a/libnautilus-private/nautilus-metafile.c b/libnautilus-private/nautilus-metafile.c
index 7ddefd490..f0541c163 100644
--- a/libnautilus-private/nautilus-metafile.c
+++ b/libnautilus-private/nautilus-metafile.c
@@ -249,7 +249,12 @@ nautilus_metafile_get (const char *directory_uri)
char *canonical_uri;
g_return_val_if_fail (directory_uri != NULL, NULL);
-
+
+ /* We don't have metafiles for search uris */
+ if (eel_uri_is_search (directory_uri)) {
+ return NULL;
+ }
+
if (metafiles == NULL) {
metafiles = eel_g_hash_table_new_free_at_exit
(g_str_hash, g_str_equal, __FILE__ ": metafiles");
diff --git a/libnautilus-private/nautilus-query.c b/libnautilus-private/nautilus-query.c
new file mode 100644
index 000000000..b8e761a63
--- /dev/null
+++ b/libnautilus-private/nautilus-query.c
@@ -0,0 +1,372 @@
+/* -*- 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 <string.h>
+
+#include "nautilus-query.h"
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-glib-extensions.h>
+
+struct NautilusQueryDetails {
+ char *text;
+ char *location_uri;
+ GList *mime_types;
+};
+
+static void nautilus_query_class_init (NautilusQueryClass *class);
+static void nautilus_query_init (NautilusQuery *query);
+
+G_DEFINE_TYPE (NautilusQuery,
+ nautilus_query,
+ G_TYPE_OBJECT);
+
+static GObjectClass *parent_class = NULL;
+
+static void
+finalize (GObject *object)
+{
+ NautilusQuery *query;
+
+ query = NAUTILUS_QUERY (object);
+
+ g_free (query->details->text);
+ g_free (query->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+nautilus_query_class_init (NautilusQueryClass *class)
+{
+ GObjectClass *gobject_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+}
+
+static void
+nautilus_query_init (NautilusQuery *query)
+{
+ query->details = g_new0 (NautilusQueryDetails, 1);
+}
+
+NautilusQuery *
+nautilus_query_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_QUERY, NULL);
+}
+
+
+char *
+nautilus_query_get_text (NautilusQuery *query)
+{
+ return g_strdup (query->details->text);
+}
+
+void
+nautilus_query_set_text (NautilusQuery *query, const char *text)
+{
+ g_free (query->details->text);
+ query->details->text = g_strdup (text);
+}
+
+char *
+nautilus_query_get_location (NautilusQuery *query)
+{
+ return g_strdup (query->details->location_uri);
+}
+
+void
+nautilus_query_set_location (NautilusQuery *query, const char *uri)
+{
+ g_free (query->details->location_uri);
+ query->details->location_uri = g_strdup (uri);
+}
+
+GList *
+nautilus_query_get_mime_types (NautilusQuery *query)
+{
+ return eel_g_str_list_copy (query->details->mime_types);
+}
+
+void
+nautilus_query_set_mime_types (NautilusQuery *query, GList *mime_types)
+{
+ eel_g_list_free_deep (query->details->mime_types);
+ query->details->mime_types = eel_g_str_list_copy (mime_types);
+}
+
+void
+nautilus_query_add_mime_type (NautilusQuery *query, const char *mime_type)
+{
+ query->details->mime_types = g_list_append (query->details->mime_types,
+ g_strdup (mime_type));
+}
+
+char *
+nautilus_query_to_readable_string (NautilusQuery *query)
+{
+ if (!query || !query->details->text) {
+ return g_strdup ("Search");
+ }
+
+ return g_strdup_printf ("Search for \"%s\"", query->details->text);
+}
+
+static char *
+encode_home_uri (const char *uri)
+{
+ char *home_uri;
+ const char *encoded_uri;
+
+ home_uri = gnome_vfs_get_uri_from_local_path (g_get_home_dir ());
+
+ if (g_str_has_prefix (uri, home_uri)) {
+ encoded_uri = uri + strlen (home_uri);
+ if (*encoded_uri == '/') {
+ encoded_uri++;
+ }
+ } else {
+ encoded_uri = uri;
+ }
+
+ g_free (home_uri);
+
+ return g_markup_escape_text (encoded_uri, -1);
+}
+
+static char *
+decode_home_uri (const char *uri)
+{
+ char *home_uri;
+ char *decoded_uri;
+
+ if (g_str_has_prefix (uri, "file:")) {
+ decoded_uri = g_strdup (uri);
+ } else {
+ home_uri = gnome_vfs_get_uri_from_local_path (g_get_home_dir ());
+
+ decoded_uri = g_strconcat (home_uri, "/", uri, NULL);
+
+ g_free (home_uri);
+ }
+
+ return decoded_uri;
+}
+
+
+typedef struct {
+ NautilusQuery *query;
+ gboolean in_text;
+ gboolean in_location;
+ gboolean in_mimetypes;
+ gboolean in_mimetype;
+} ParserInfo;
+
+static void
+start_element_cb (GMarkupParseContext *ctx,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ gpointer user_data,
+ GError **err)
+{
+ ParserInfo *info;
+
+ info = (ParserInfo *) user_data;
+
+ if (strcmp (element_name, "text") == 0)
+ info->in_text = TRUE;
+ else if (strcmp (element_name, "location") == 0)
+ info->in_location = TRUE;
+ else if (strcmp (element_name, "mimetypes") == 0)
+ info->in_mimetypes = TRUE;
+ else if (strcmp (element_name, "mimetype") == 0)
+ info->in_mimetype = TRUE;
+}
+
+static void
+end_element_cb (GMarkupParseContext *ctx,
+ const char *element_name,
+ gpointer user_data,
+ GError **err)
+{
+ ParserInfo *info;
+
+ info = (ParserInfo *) user_data;
+
+ if (strcmp (element_name, "text") == 0)
+ info->in_text = FALSE;
+ else if (strcmp (element_name, "location") == 0)
+ info->in_location = FALSE;
+ else if (strcmp (element_name, "mimetypes") == 0)
+ info->in_mimetypes = FALSE;
+ else if (strcmp (element_name, "mimetype") == 0)
+ info->in_mimetype = FALSE;
+}
+
+static void
+text_cb (GMarkupParseContext *ctx,
+ const char *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **err)
+{
+ ParserInfo *info;
+ char *t, *uri;
+
+ info = (ParserInfo *) user_data;
+
+ t = g_strndup (text, text_len);
+
+ if (info->in_text) {
+ nautilus_query_set_text (info->query, t);
+ } else if (info->in_location) {
+ uri = decode_home_uri (t);
+ nautilus_query_set_location (info->query, uri);
+ g_free (uri);
+ } else if (info->in_mimetypes && info->in_mimetype) {
+ nautilus_query_add_mime_type (info->query, t);
+ }
+
+ g_free (t);
+
+}
+
+static void
+error_cb (GMarkupParseContext *ctx,
+ GError *err,
+ gpointer user_data)
+{
+}
+
+static GMarkupParser parser = {
+ start_element_cb,
+ end_element_cb,
+ text_cb,
+ NULL,
+ error_cb
+};
+
+
+static NautilusQuery *
+nautilus_query_parse_xml (char *xml, gsize xml_len)
+{
+ ParserInfo info = { NULL };
+ GMarkupParseContext *ctx;
+
+ if (xml_len == -1) {
+ xml_len = strlen (xml);
+ }
+
+ info.query = nautilus_query_new ();
+ info.in_text = FALSE;
+
+ ctx = g_markup_parse_context_new (&parser, 0, &info, NULL);
+ g_markup_parse_context_parse (ctx, xml, xml_len, NULL);
+
+ return info.query;
+}
+
+
+NautilusQuery *
+nautilus_query_load (char *file)
+{
+ NautilusQuery *query;
+ char *xml;
+ gsize xml_len;
+
+ if (!g_file_test (file, G_FILE_TEST_EXISTS)) {
+ return NULL;
+ }
+
+
+ g_file_get_contents (file, &xml, &xml_len, NULL);
+ query = nautilus_query_parse_xml (xml, xml_len);
+ g_free (xml);
+
+ return query;
+}
+
+static char *
+nautilus_query_to_xml (NautilusQuery *query)
+{
+ GString *xml;
+ char *text;
+ char *uri;
+ char *mimetype;
+ GList *l;
+
+ xml = g_string_new ("");
+ g_string_append (xml,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<query version=\"1.0\">\n");
+
+ text = g_markup_escape_text (query->details->text, -1);
+ g_string_append_printf (xml, " <text>%s</text>\n", text);
+ g_free (text);
+
+ if (query->details->location_uri) {
+ uri = encode_home_uri (query->details->location_uri);
+ g_string_append_printf (xml, " <location>%s</location>\n", uri);
+ g_free (uri);
+ }
+
+ if (query->details->mime_types) {
+ g_string_append (xml, " <mimetypes>\n");
+ for (l = query->details->mime_types; l != NULL; l = l->next) {
+ mimetype = g_markup_escape_text (l->data, -1);
+ g_string_append_printf (xml, " <mimetype>%s</mimetype>\n", mimetype);
+ g_free (mimetype);
+ }
+ g_string_append (xml, " </mimetypes>\n");
+ }
+
+ g_string_append (xml, "</query>\n");
+
+ return g_string_free (xml, FALSE);
+}
+
+gboolean
+nautilus_query_save (NautilusQuery *query, char *file)
+{
+ char *xml;
+ GError *err = NULL;
+ gboolean res;
+
+
+ res = TRUE;
+ xml = nautilus_query_to_xml (query);
+ g_file_set_contents (file, xml, strlen (xml), &err);
+ g_free (xml);
+
+ if (err != NULL) {
+ res = FALSE;
+ g_error_free (err);
+ }
+ return res;
+}
diff --git a/libnautilus-private/nautilus-query.h b/libnautilus-private/nautilus-query.h
new file mode 100644
index 000000000..fae278042
--- /dev/null
+++ b/libnautilus-private/nautilus-query.h
@@ -0,0 +1,67 @@
+/* -*- 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_QUERY_H
+#define NAUTILUS_QUERY_H
+
+#include <glib-object.h>
+#include <libgnomevfs/gnome-vfs-result.h>
+
+#define NAUTILUS_TYPE_QUERY (nautilus_query_get_type ())
+#define NAUTILUS_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_QUERY, NautilusQuery))
+#define NAUTILUS_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_QUERY, NautilusQueryClass))
+#define NAUTILUS_IS_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_QUERY))
+#define NAUTILUS_IS_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_QUERY))
+#define NAUTILUS_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_QUERY, NautilusQueryClass))
+
+typedef struct NautilusQueryDetails NautilusQueryDetails;
+
+typedef struct NautilusQuery {
+ GObject parent;
+ NautilusQueryDetails *details;
+} NautilusQuery;
+
+typedef struct {
+ GObjectClass parent_class;
+} NautilusQueryClass;
+
+GType nautilus_query_get_type (void);
+gboolean nautilus_query_enabled (void);
+
+NautilusQuery* nautilus_query_new (void);
+
+char * nautilus_query_get_text (NautilusQuery *query);
+void nautilus_query_set_text (NautilusQuery *query, const char *text);
+
+char * nautilus_query_get_location (NautilusQuery *query);
+void nautilus_query_set_location (NautilusQuery *query, const char *uri);
+
+GList * nautilus_query_get_mime_types (NautilusQuery *query);
+void nautilus_query_set_mime_types (NautilusQuery *query, GList *mime_types);
+void nautilus_query_add_mime_type (NautilusQuery *query, const char *mime_type);
+
+char * nautilus_query_to_readable_string (NautilusQuery *query);
+NautilusQuery *nautilus_query_load (char *file);
+gboolean nautilus_query_save (NautilusQuery *query, char *file);
+
+#endif /* NAUTILUS_QUERY_H */
diff --git a/libnautilus-private/nautilus-saved-search-file.c b/libnautilus-private/nautilus-saved-search-file.c
new file mode 100644
index 000000000..35ce6d6a3
--- /dev/null
+++ b/libnautilus-private/nautilus-saved-search-file.c
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-saved-search-file.h: Subclass of NautilusVFSFile to implement the
+ the case of a Saved Search file.
+
+ Copyright (C) 2005 Red Hat, Inc
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson
+*/
+#include <config.h>
+#include "nautilus-saved-search-file.h"
+#include <eel/eel-gtk-macros.h>
+
+static void nautilus_saved_search_file_init (gpointer object, gpointer klass);
+static void nautilus_saved_search_file_class_init (gpointer klass);
+
+EEL_CLASS_BOILERPLATE (NautilusSavedSearchFile,
+ nautilus_saved_search_file,
+ NAUTILUS_TYPE_VFS_FILE)
+
+
+
+static void
+nautilus_saved_search_file_init (gpointer object, gpointer klass)
+{
+ NautilusVFSFile *file;
+
+ file = NAUTILUS_VFS_FILE (object);
+
+}
+
+static GnomeVFSFileType
+saved_search_get_file_type (NautilusFile *file)
+{
+ return GNOME_VFS_FILE_TYPE_DIRECTORY;
+}
+
+static void
+nautilus_saved_search_file_class_init (gpointer klass)
+{
+ NautilusFileClass *file_class;
+
+ file_class = NAUTILUS_FILE_CLASS (klass);
+
+ file_class->get_file_type = saved_search_get_file_type;
+}
+
diff --git a/libnautilus-private/nautilus-saved-search-file.h b/libnautilus-private/nautilus-saved-search-file.h
new file mode 100644
index 000000000..16cf35943
--- /dev/null
+++ b/libnautilus-private/nautilus-saved-search-file.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-saved-search-file.h: Subclass of NautilusVFSFile to implement the
+ the case of a Saved Search file.
+
+ Copyright (C) 2005 Red Hat, Inc
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson
+*/
+
+#ifndef NAUTILUS_SAVED_SEARCH_FILE_H
+#define NAUTILUS_SAVED_SEARCH_FILE_H
+
+#include <libnautilus-private/nautilus-vfs-file.h>
+
+#define NAUTILUS_TYPE_SAVED_SEARCH_FILE \
+ (nautilus_saved_search_file_get_type ())
+#define NAUTILUS_SAVED_SEARCH_FILE(obj) \
+ (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_SAVED_SEARCH_FILE, NautilusSavedSearchFile))
+#define NAUTILUS_SAVED_SEARCH_FILE_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SAVED_SEARCH_FILE, NautilusSavedSearchFileClass))
+#define NAUTILUS_IS_SAVED_SEARCH_FILE(obj) \
+ (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_SAVED_SEARCH_FILE))
+#define NAUTILUS_IS_SAVED_SEARCH_FILE_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SAVED_SEARCH_FILE))
+
+typedef struct NautilusSavedSearchFileDetails NautilusSavedSearchFileDetails;
+
+typedef struct {
+ NautilusFile parent_slot;
+} NautilusSavedSearchFile;
+
+typedef struct {
+ NautilusFileClass parent_slot;
+} NautilusSavedSearchFileClass;
+
+GType nautilus_saved_search_file_get_type (void);
+
+#endif /* NAUTILUS_SAVED_SEARCH_FILE_H */
diff --git a/libnautilus-private/nautilus-search-directory-file.c b/libnautilus-private/nautilus-search-directory-file.c
new file mode 100644
index 000000000..86c077a94
--- /dev/null
+++ b/libnautilus-private/nautilus-search-directory-file.c
@@ -0,0 +1,239 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-search-directory-file.c: Subclass of NautilusFile to help implement the
+ searches
+
+ Copyright (C) 2005 Novell, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Anders Carlsson <andersca@imendio.com>
+*/
+
+#include <config.h>
+#include "nautilus-search-directory-file.h"
+
+#include "nautilus-directory-notify.h"
+#include "nautilus-directory-private.h"
+#include "nautilus-file-attributes.h"
+#include "nautilus-file-private.h"
+#include "nautilus-file-utilities.h"
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-gtk-macros.h>
+#include "nautilus-search-directory.h"
+#include <gtk/gtksignal.h>
+#include <libgnome/gnome-i18n.h>
+#include <string.h>
+
+static void nautilus_search_directory_file_init (gpointer object,
+ gpointer klass);
+static void nautilus_search_directory_file_class_init (gpointer klass);
+
+EEL_CLASS_BOILERPLATE (NautilusSearchDirectoryFile,
+ nautilus_search_directory_file,
+ NAUTILUS_TYPE_FILE);
+
+struct NautilusSearchDirectoryFileDetails {
+ NautilusSearchDirectory *search_directory;
+};
+
+static void
+search_directory_file_monitor_add (NautilusFile *file,
+ gconstpointer client,
+ NautilusFileAttributes attributes)
+{
+ /* No need for monitoring, we always emit changed when files
+ are added/removed, and no other metadata changes */
+}
+
+static void
+search_directory_file_monitor_remove (NautilusFile *file,
+ gconstpointer client)
+{
+ /* Do nothing here, we don't have any monitors */
+}
+
+static void
+search_directory_file_call_when_ready (NautilusFile *file,
+ NautilusFileAttributes file_attributes,
+ NautilusFileCallback callback,
+ gpointer callback_data)
+
+{
+ /* All data for directory-as-file is always uptodate */
+ (* callback) (file, callback_data);
+}
+
+static void
+search_directory_file_cancel_call_when_ready (NautilusFile *file,
+ NautilusFileCallback callback,
+ gpointer callback_data)
+{
+ /* Do nothing here, we don't have any pending calls */
+}
+
+
+static gboolean
+search_directory_file_check_if_ready (NautilusFile *file,
+ NautilusFileAttributes attributes)
+{
+ return TRUE;
+}
+
+static GnomeVFSFileType
+search_directory_file_get_file_type (NautilusFile *file)
+{
+ return GNOME_VFS_FILE_TYPE_DIRECTORY;
+}
+
+static gboolean
+search_directory_file_get_item_count (NautilusFile *file,
+ guint *count,
+ gboolean *count_unreadable)
+{
+ NautilusSearchDirectory *search_dir;
+ GList *file_list;
+
+ if (count) {
+ search_dir = NAUTILUS_SEARCH_DIRECTORY (file->details->directory);
+
+ file_list = nautilus_directory_get_file_list (file->details->directory);
+
+ *count = g_list_length (file_list);
+
+ nautilus_file_list_free (file_list);
+ }
+
+ return TRUE;
+}
+
+static NautilusRequestStatus
+search_directory_file_get_deep_counts (NautilusFile *file,
+ guint *directory_count,
+ guint *file_count,
+ guint *unreadable_directory_count,
+ GnomeVFSFileSize *total_size)
+{
+ NautilusSearchDirectory *search_dir;
+ NautilusFile *dir_file;
+ GList *file_list, *l;
+ guint dirs, files;
+ GnomeVFSFileType type;
+
+ search_dir = NAUTILUS_SEARCH_DIRECTORY (file->details->directory);
+
+ file_list = nautilus_directory_get_file_list (file->details->directory);
+
+ dirs = files = 0;
+ for (l = file_list; l != NULL; l = l->next) {
+ dir_file = NAUTILUS_FILE (l->data);
+ type = nautilus_file_get_file_type (dir_file);
+ if (type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+ dirs++;
+ } else {
+ files++;
+ }
+ }
+
+ if (directory_count != NULL) {
+ *directory_count = dirs;
+ }
+ if (file_count != NULL) {
+ *file_count = files;
+ }
+ if (unreadable_directory_count != NULL) {
+ *unreadable_directory_count = 0;
+ }
+ if (total_size != NULL) {
+ /* FIXME: Maybe we want to calculate this? */
+ *total_size = 0;
+ }
+
+ nautilus_file_list_free (file_list);
+
+ return NAUTILUS_REQUEST_DONE;
+}
+
+static char *
+search_directory_file_get_where_string (NautilusFile *file)
+{
+ return g_strdup (_("Search"));
+}
+
+static void
+nautilus_search_directory_file_init (gpointer object, gpointer klass)
+{
+ NautilusSearchDirectoryFile *search_file;
+ NautilusFile *file;
+ GnomeVFSFileInfo *file_info;
+
+ search_file = NAUTILUS_SEARCH_DIRECTORY_FILE (object);
+ file = NAUTILUS_FILE(object);
+
+ file_info = file->details->info = gnome_vfs_file_info_new ();
+
+ file_info->name = g_strdup (_("Search"));
+ file_info->mime_type = g_strdup ("x-directory/normal");
+ file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
+ file_info->flags = GNOME_VFS_FILE_FLAGS_NONE;
+ file_info->link_count = 1;
+ file_info->size = 0;
+ file_info->permissions =
+ GNOME_VFS_PERM_OTHER_WRITE |
+ GNOME_VFS_PERM_GROUP_WRITE |
+ GNOME_VFS_PERM_USER_READ |
+ GNOME_VFS_PERM_OTHER_READ |
+ GNOME_VFS_PERM_GROUP_READ;
+
+ file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE |
+ GNOME_VFS_FILE_INFO_FIELDS_FLAGS |
+ GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE |
+ GNOME_VFS_FILE_INFO_FIELDS_SIZE |
+ GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS |
+ GNOME_VFS_FILE_INFO_FIELDS_LINK_COUNT;
+
+ file->details->file_info_is_up_to_date = TRUE;
+
+ file->details->display_name = g_strdup (_("Search"));
+ file->details->custom_icon = NULL;
+ file->details->activation_uri = NULL;
+ file->details->got_link_info = TRUE;
+ file->details->link_info_is_up_to_date = TRUE;
+
+ file->details->directory_count = 0;
+ file->details->got_directory_count = TRUE;
+ file->details->directory_count_is_up_to_date = TRUE;
+}
+
+static void
+nautilus_search_directory_file_class_init (gpointer klass)
+{
+ GObjectClass *object_class;
+ NautilusFileClass *file_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ file_class = NAUTILUS_FILE_CLASS (klass);
+
+ file_class->monitor_add = search_directory_file_monitor_add;
+ file_class->monitor_remove = search_directory_file_monitor_remove;
+ file_class->call_when_ready = search_directory_file_call_when_ready;
+ file_class->cancel_call_when_ready = search_directory_file_cancel_call_when_ready;
+ file_class->get_file_type = search_directory_file_get_file_type;
+ file_class->check_if_ready = search_directory_file_check_if_ready;
+ file_class->get_item_count = search_directory_file_get_item_count;
+ file_class->get_deep_counts = search_directory_file_get_deep_counts;
+ file_class->get_where_string = search_directory_file_get_where_string;
+}
diff --git a/libnautilus-private/nautilus-search-directory-file.h b/libnautilus-private/nautilus-search-directory-file.h
new file mode 100644
index 000000000..57432f887
--- /dev/null
+++ b/libnautilus-private/nautilus-search-directory-file.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-search-directory-file.h: Subclass of NautilusFile to implement the
+ the case of the search directory
+
+ Copyright (C) 2003 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+#ifndef NAUTILUS_SEARCH_DIRECTORY_FILE_H
+#define NAUTILUS_SEARCH_DIRECTORY_FILE_H
+
+#include <libnautilus-private/nautilus-file.h>
+
+#define NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE \
+ (nautilus_search_directory_file_get_type ())
+#define NAUTILUS_SEARCH_DIRECTORY_FILE(obj) \
+ (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NautilusSearchDirectoryFile))
+#define NAUTILUS_SEARCH_DIRECTORY_FILE_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NautilusSearchDirectoryFileClass))
+#define NAUTILUS_IS_SEARCH_DIRECTORY_FILE(obj) \
+ (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE))
+#define NAUTILUS_IS_SEARCH_DIRECTORY_FILE_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE))
+
+typedef struct NautilusSearchDirectoryFileDetails NautilusSearchDirectoryFileDetails;
+
+typedef struct {
+ NautilusFile parent_slot;
+ NautilusSearchDirectoryFileDetails *details;
+} NautilusSearchDirectoryFile;
+
+typedef struct {
+ NautilusFileClass parent_slot;
+} NautilusSearchDirectoryFileClass;
+
+GType nautilus_search_directory_file_get_type (void);
+
+#endif /* NAUTILUS_SEARCH_DIRECTORY_FILE_H */
diff --git a/libnautilus-private/nautilus-search-directory.c b/libnautilus-private/nautilus-search-directory.c
new file mode 100644
index 000000000..2172bc245
--- /dev/null
+++ b/libnautilus-private/nautilus-search-directory.c
@@ -0,0 +1,864 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ Copyright (C) 2005 Novell, Inc
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Anders Carlsson <andersca@imendio.com>
+*/
+
+#include <config.h>
+#include "nautilus-search-directory.h"
+
+#include "nautilus-directory-private.h"
+#include "nautilus-file.h"
+#include "nautilus-file-private.h"
+#include "nautilus-file-utilities.h"
+#include "nautilus-search-engine.h"
+#include <eel/eel-glib-extensions.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <gtk/gtksignal.h>
+#include <libgnome/gnome-macros.h>
+#include <string.h>
+#include <sys/time.h>
+
+struct NautilusSearchDirectoryDetails {
+ NautilusQuery *query;
+ char *saved_search_uri;
+ gboolean modified;
+
+ NautilusSearchEngine *engine;
+
+ gboolean search_running;
+ gboolean search_finished;
+
+ GList *files;
+ GHashTable *file_hash;
+
+ GList *monitor_list;
+ GList *callback_list;
+ GList *pending_callback_list;
+};
+
+typedef struct {
+ gboolean monitor_hidden_files;
+ gboolean monitor_backup_files;
+ NautilusFileAttributes monitor_attributes;
+
+ gconstpointer client;
+} SearchMonitor;
+
+typedef struct {
+ NautilusSearchDirectory *search_directory;
+
+ NautilusDirectoryCallback callback;
+ gpointer callback_data;
+
+ NautilusFileAttributes wait_for_attributes;
+ gboolean wait_for_file_list;
+ GList *file_list;
+ GHashTable *non_ready_hash;
+} SearchCallback;
+
+GNOME_CLASS_BOILERPLATE (NautilusSearchDirectory, nautilus_search_directory,
+ NautilusDirectory, NAUTILUS_TYPE_DIRECTORY)
+
+static void search_engine_hits_added (NautilusSearchEngine *engine, GList *hits, NautilusSearchDirectory *search);
+static void search_engine_hits_subtracted (NautilusSearchEngine *engine, GList *hits, NautilusSearchDirectory *search);
+static void search_engine_finished (NautilusSearchEngine *engine, NautilusSearchDirectory *search);
+static void search_engine_error (NautilusSearchEngine *engine, const char *error, NautilusSearchDirectory *search);
+static void search_callback_file_ready_callback (NautilusFile *file, gpointer data);
+static void file_changed (NautilusFile *file, NautilusSearchDirectory *search);
+
+static void
+ensure_search_engine (NautilusSearchDirectory *search)
+{
+ if (!search->details->engine) {
+ search->details->engine = nautilus_search_engine_new ();
+ g_signal_connect (search->details->engine, "hits-added",
+ G_CALLBACK (search_engine_hits_added),
+ search);
+ g_signal_connect (search->details->engine, "hits-subtracted",
+ G_CALLBACK (search_engine_hits_subtracted),
+ search);
+ g_signal_connect (search->details->engine, "finished",
+ G_CALLBACK (search_engine_finished),
+ search);
+ g_signal_connect (search->details->engine, "error",
+ G_CALLBACK (search_engine_error),
+ search);
+ }
+}
+
+static void
+reset_file_list (NautilusSearchDirectory *search)
+{
+ GList *list, *monitor_list;
+ NautilusFile *file;
+ SearchMonitor *monitor;
+
+ /* Remove file connections */
+ for (list = search->details->files; list != NULL; list = list->next) {
+ file = list->data;
+
+ /* Disconnect change handler */
+ g_signal_handlers_disconnect_by_func (file, file_changed, search);
+
+ /* Remove monitors */
+ for (monitor_list = search->details->monitor_list; monitor_list;
+ monitor_list = monitor_list->next) {
+ monitor = monitor_list->data;
+ nautilus_file_monitor_remove (file, monitor);
+ }
+ }
+
+ nautilus_file_list_free (search->details->files);
+ search->details->files = NULL;
+}
+
+static void
+start_or_stop_search_engine (NautilusSearchDirectory *search, gboolean adding)
+{
+ if (adding && (search->details->monitor_list ||
+ search->details->pending_callback_list) &&
+ search->details->query &&
+ !search->details->search_running) {
+ /* We need to start the search engine */
+ search->details->search_running = TRUE;
+ search->details->search_finished = FALSE;
+ ensure_search_engine (search);
+ nautilus_search_engine_set_query (search->details->engine, search->details->query);
+
+ reset_file_list (search);
+
+ nautilus_search_engine_start (search->details->engine);
+ } else if (!adding && !search->details->monitor_list &&
+ !search->details->pending_callback_list &&
+ search->details->engine &&
+ search->details->search_running) {
+ search->details->search_running = FALSE;
+ nautilus_search_engine_stop (search->details->engine);
+
+ reset_file_list (search);
+ }
+
+}
+
+static void
+file_changed (NautilusFile *file, NautilusSearchDirectory *search)
+{
+ GList list;
+
+ list.data = file;
+ list.next = NULL;
+
+ nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (search), &list);
+}
+
+static void
+search_monitor_add (NautilusDirectory *directory,
+ gconstpointer client,
+ gboolean monitor_hidden_files,
+ gboolean monitor_backup_files,
+ NautilusFileAttributes file_attributes,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ GList *list;
+ SearchMonitor *monitor;
+ NautilusSearchDirectory *search;
+ NautilusFile *file;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ monitor = g_new0 (SearchMonitor, 1);
+ monitor->monitor_hidden_files = monitor_hidden_files;
+ monitor->monitor_backup_files = monitor_backup_files;
+ monitor->monitor_attributes = file_attributes;
+ monitor->client = client;
+
+ search->details->monitor_list = g_list_prepend (search->details->monitor_list, monitor);
+
+ if (callback != NULL) {
+ (* callback) (directory, search->details->files, callback_data);
+ }
+
+ for (list = search->details->files; list != NULL; list = list->next) {
+ file = list->data;
+
+ /* Add monitors */
+ nautilus_file_monitor_add (file, monitor, file_attributes);
+ }
+
+ start_or_stop_search_engine (search, TRUE);
+}
+
+static void
+search_monitor_remove_file_monitors (SearchMonitor *monitor, NautilusSearchDirectory *search)
+{
+ GList *list;
+ NautilusFile *file;
+
+ for (list = search->details->files; list != NULL; list = list->next) {
+ file = list->data;
+
+ nautilus_file_monitor_remove (file, monitor);
+ }
+}
+
+static void
+search_monitor_destroy (SearchMonitor *monitor, NautilusSearchDirectory *search)
+{
+ search_monitor_remove_file_monitors (monitor, search);
+
+ g_free (monitor);
+}
+
+static void
+search_monitor_remove (NautilusDirectory *directory,
+ gconstpointer client)
+{
+ NautilusSearchDirectory *search;
+ SearchMonitor *monitor;
+ GList *list;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ for (list = search->details->monitor_list; list != NULL; list = list->next) {
+ monitor = list->data;
+
+ if (monitor->client == client) {
+ search->details->monitor_list = g_list_delete_link (search->details->monitor_list, list);
+
+ search_monitor_destroy (monitor, search);
+
+ break;
+ }
+ }
+
+ start_or_stop_search_engine (search, FALSE);
+}
+
+static void
+cancel_call_when_ready (gpointer key, gpointer value, gpointer user_data)
+{
+ SearchCallback *search_callback;
+ NautilusFile *file;
+
+ file = key;
+ search_callback = user_data;
+
+ nautilus_file_cancel_call_when_ready (file, search_callback_file_ready_callback,
+ search_callback);
+}
+
+static void
+search_callback_destroy (SearchCallback *search_callback)
+{
+ if (search_callback->non_ready_hash) {
+ g_hash_table_foreach (search_callback->non_ready_hash, cancel_call_when_ready, search_callback);
+ g_hash_table_destroy (search_callback->non_ready_hash);
+ }
+
+ nautilus_file_list_free (search_callback->file_list);
+
+ g_free (search_callback);
+}
+
+static void
+search_callback_invoke_and_destroy (SearchCallback *search_callback)
+{
+ search_callback->callback (NAUTILUS_DIRECTORY (search_callback->search_directory),
+ search_callback->file_list,
+ search_callback->callback_data);
+
+ search_callback->search_directory->details->callback_list =
+ g_list_remove (search_callback->search_directory->details->callback_list, search_callback);
+
+ search_callback_destroy (search_callback);
+}
+
+static void
+search_callback_file_ready_callback (NautilusFile *file, gpointer data)
+{
+ SearchCallback *search_callback = data;
+
+ g_hash_table_remove (search_callback->non_ready_hash, file);
+
+ if (g_hash_table_size (search_callback->non_ready_hash) == 0) {
+ search_callback_invoke_and_destroy (search_callback);
+ }
+}
+
+static void
+search_callback_add_file_callbacks (SearchCallback *callback)
+{
+ GList *file_list_copy, *list;
+ NautilusFile *file;
+
+ file_list_copy = g_list_copy (callback->file_list);
+
+ for (list = file_list_copy; list != NULL; list = list->next) {
+ file = list->data;
+
+ nautilus_file_call_when_ready (file,
+ callback->wait_for_attributes,
+ search_callback_file_ready_callback,
+ callback);
+ }
+ g_list_free (file_list_copy);
+}
+
+static SearchCallback *
+search_callback_find (NautilusSearchDirectory *search, NautilusDirectoryCallback callback, gpointer callback_data)
+{
+ SearchCallback *search_callback;
+ GList *list;
+
+ for (list = search->details->callback_list; list != NULL; list = list->next) {
+ search_callback = list->data;
+
+ if (search_callback->callback == callback &&
+ search_callback->callback_data == callback_data) {
+ return search_callback;
+ }
+ }
+
+ return NULL;
+}
+
+static SearchCallback *
+search_callback_find_pending (NautilusSearchDirectory *search, NautilusDirectoryCallback callback, gpointer callback_data)
+{
+ SearchCallback *search_callback;
+ GList *list;
+
+ for (list = search->details->pending_callback_list; list != NULL; list = list->next) {
+ search_callback = list->data;
+
+ if (search_callback->callback == callback &&
+ search_callback->callback_data == callback_data) {
+ return search_callback;
+ }
+ }
+
+ return NULL;
+}
+
+static GHashTable *
+file_list_to_hash_table (GList *file_list)
+{
+ GList *list;
+ GHashTable *table;
+
+ if (!file_list)
+ return NULL;
+
+ table = g_hash_table_new (NULL, NULL);
+
+ for (list = file_list; list != NULL; list = list->next) {
+ g_hash_table_insert (table, list->data, list->data);
+ }
+
+ return table;
+}
+
+static void
+search_call_when_ready (NautilusDirectory *directory,
+ NautilusFileAttributes file_attributes,
+ gboolean wait_for_file_list,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ NautilusSearchDirectory *search;
+ SearchCallback *search_callback;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ search_callback = search_callback_find (search, callback, callback_data);
+ if (search_callback == NULL) {
+ search_callback = search_callback_find_pending (search, callback, callback_data);
+ }
+
+ if (search_callback) {
+ g_warning ("tried to add a new callback while an old one was pending");
+ return;
+ }
+
+ search_callback = g_new0 (SearchCallback, 1);
+ search_callback->search_directory = search;
+ search_callback->callback = callback;
+ search_callback->callback_data = callback_data;
+ search_callback->wait_for_attributes = file_attributes;
+ search_callback->wait_for_file_list = wait_for_file_list;
+
+ if (wait_for_file_list && !search->details->search_finished) {
+ /* Add it to the pending callback list, which will be
+ * processed when the directory has finished loading
+ */
+ search->details->pending_callback_list =
+ g_list_prepend (search->details->pending_callback_list, search_callback);
+
+ /* We might need to start the search engine */
+ start_or_stop_search_engine (search, TRUE);
+ } else {
+ search_callback->file_list = nautilus_file_list_copy (search->details->files);
+ search_callback->non_ready_hash = file_list_to_hash_table (search->details->files);
+
+ if (!search_callback->non_ready_hash) {
+ /* If there are no ready files, we invoke the callback
+ with an empty list.
+ */
+ search_callback_invoke_and_destroy (search_callback);
+ } else {
+ search->details->callback_list = g_list_prepend (search->details->callback_list, search_callback);
+ search_callback_add_file_callbacks (search_callback);
+ }
+ }
+}
+
+static void
+search_cancel_callback (NautilusDirectory *directory,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ NautilusSearchDirectory *search;
+ SearchCallback *search_callback;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+ search_callback = search_callback_find (search, callback, callback_data);
+
+ if (search_callback) {
+ search->details->callback_list = g_list_remove (search->details->callback_list, search_callback);
+
+ search_callback_destroy (search_callback);
+
+ return;
+ }
+
+ /* Check for a pending callback */
+ search_callback = search_callback_find_pending (search, callback, callback_data);
+
+ if (search_callback) {
+ search->details->pending_callback_list = g_list_remove (search->details->pending_callback_list, search_callback);
+
+ search_callback_destroy (search_callback);
+
+ /* We might need to stop the search engine now */
+ start_or_stop_search_engine (search, FALSE);
+ }
+}
+
+
+static void
+search_engine_hits_added (NautilusSearchEngine *engine, GList *hits,
+ NautilusSearchDirectory *search)
+{
+ GList *hit_list;
+ GList *file_list;
+ NautilusFile *file;
+ char *uri;
+ SearchMonitor *monitor;
+ GList *monitor_list;
+
+ file_list = NULL;
+
+ for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next) {
+ uri = hit_list->data;
+
+ if (g_str_has_suffix (uri, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
+ /* Never return saved searches themselves as hits */
+ continue;
+ }
+
+ file = nautilus_file_get (uri);
+
+ for (monitor_list = search->details->monitor_list; monitor_list; monitor_list = monitor_list->next) {
+ monitor = monitor_list->data;
+
+ /* Add monitors */
+ nautilus_file_monitor_add (file, monitor, monitor->monitor_attributes);
+ }
+
+ g_signal_connect (file, "changed", G_CALLBACK (file_changed), search),
+
+ file_list = g_list_prepend (file_list, file);
+ }
+
+ search->details->files = g_list_concat (search->details->files, file_list);
+
+ nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (search), file_list);
+
+ file = nautilus_directory_get_corresponding_file (NAUTILUS_DIRECTORY (search));
+ nautilus_file_emit_changed (file);
+ nautilus_file_unref (file);
+}
+
+static void
+search_engine_hits_subtracted (NautilusSearchEngine *engine, GList *hits,
+ NautilusSearchDirectory *search)
+{
+ GList *hit_list;
+ GList *monitor_list;
+ SearchMonitor *monitor;
+ GList *file_list;
+ char *uri;
+ NautilusFile *file;
+
+ file_list = NULL;
+
+ for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next) {
+ uri = hit_list->data;
+ file = nautilus_file_get (uri);
+
+ for (monitor_list = search->details->monitor_list; monitor_list;
+ monitor_list = monitor_list->next) {
+ monitor = monitor_list->data;
+ /* Remove monitors */
+ nautilus_file_monitor_remove (file, monitor);
+ }
+
+ g_signal_handlers_disconnect_by_func (file, file_changed, search);
+
+ search->details->files = g_list_remove (search->details->files, file);
+
+ file_list = g_list_prepend (file_list, file);
+ }
+
+ nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (search), file_list);
+
+ nautilus_file_list_free (file_list);
+
+ file = nautilus_directory_get_corresponding_file (NAUTILUS_DIRECTORY (search));
+ nautilus_file_emit_changed (file);
+ nautilus_file_unref (file);
+}
+
+static void
+search_callback_add_pending_file_callbacks (SearchCallback *callback)
+{
+ callback->file_list = nautilus_file_list_copy (callback->search_directory->details->files);
+ callback->non_ready_hash = file_list_to_hash_table (callback->search_directory->details->files);
+
+ search_callback_add_file_callbacks (callback);
+}
+
+static void
+search_engine_error (NautilusSearchEngine *engine, const char *error_message, NautilusSearchDirectory *search)
+{
+ nautilus_directory_emit_load_error (NAUTILUS_DIRECTORY (search),
+ -1, error_message);
+}
+
+static void
+search_engine_finished (NautilusSearchEngine *engine, NautilusSearchDirectory *search)
+{
+ search->details->search_finished = TRUE;
+
+ nautilus_directory_emit_done_loading (NAUTILUS_DIRECTORY (search));
+
+ /* Add all file callbacks */
+ g_list_foreach (search->details->pending_callback_list,
+ (GFunc)search_callback_add_pending_file_callbacks, NULL);
+ search->details->callback_list = g_list_concat (search->details->callback_list,
+ search->details->pending_callback_list);
+
+ g_list_free (search->details->pending_callback_list);
+ search->details->pending_callback_list = NULL;
+}
+
+static void
+search_force_reload (NautilusDirectory *directory)
+{
+ NautilusSearchDirectory *search;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ if (!search->details->query) {
+ return;
+ }
+
+ search->details->search_finished = FALSE;
+
+ if (!search->details->engine) {
+ return;
+ }
+
+ /* Remove file monitors */
+ reset_file_list (search);
+
+ if (search->details->search_running) {
+ nautilus_search_engine_stop (search->details->engine);
+ nautilus_search_engine_set_query (search->details->engine, search->details->query);
+ nautilus_search_engine_start (search->details->engine);
+ }
+}
+
+static gboolean
+search_are_all_files_seen (NautilusDirectory *directory)
+{
+ NautilusSearchDirectory *search;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ return (!search->details->query ||
+ search->details->search_finished);
+}
+
+static gboolean
+search_contains_file (NautilusDirectory *directory,
+ NautilusFile *file)
+{
+ NautilusSearchDirectory *search;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ /* FIXME: Maybe put the files in a hash */
+ return (g_list_find (search->details->files, file) != NULL);
+}
+
+static GList *
+search_get_file_list (NautilusDirectory *directory)
+{
+ NautilusSearchDirectory *search;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (directory);
+
+ return nautilus_file_list_copy (search->details->files);
+}
+
+
+static gboolean
+search_is_editable (NautilusDirectory *directory)
+{
+ return FALSE;
+}
+
+static void
+search_dispose (GObject *object)
+{
+ NautilusSearchDirectory *search;
+ GList *list;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (object);
+
+ /* Remove search monitors */
+ if (search->details->monitor_list) {
+ for (list = search->details->monitor_list; list != NULL; list = list->next) {
+ search_monitor_destroy ((SearchMonitor *)list->data, search);
+ }
+
+ g_list_free (search->details->monitor_list);
+ search->details->monitor_list = NULL;
+ }
+
+ reset_file_list (search);
+
+ if (search->details->callback_list) {
+ /* Remove callbacks */
+ g_list_foreach (search->details->callback_list,
+ (GFunc)search_callback_destroy, NULL);
+ g_list_free (search->details->callback_list);
+ search->details->callback_list = NULL;
+ }
+
+ if (search->details->pending_callback_list) {
+ g_list_foreach (search->details->pending_callback_list,
+ (GFunc)search_callback_destroy, NULL);
+ g_list_free (search->details->pending_callback_list);
+ search->details->pending_callback_list = NULL;
+ }
+
+ if (search->details->query) {
+ g_object_unref (search->details->query);
+ search->details->query = NULL;
+ }
+
+ if (search->details->engine) {
+ if (search->details->search_running) {
+ nautilus_search_engine_stop (search->details->engine);
+ }
+
+ g_object_unref (search->details->engine);
+ search->details->engine = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+search_finalize (GObject *object)
+{
+ NautilusSearchDirectory *search;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (object);
+
+ g_free (search->details->saved_search_uri);
+
+ g_free (search->details);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+nautilus_search_directory_instance_init (NautilusSearchDirectory *search)
+{
+ search->details = g_new0 (NautilusSearchDirectoryDetails, 1);
+}
+
+static void
+nautilus_search_directory_class_init (NautilusSearchDirectoryClass *class)
+{
+ NautilusDirectoryClass *directory_class;
+
+ G_OBJECT_CLASS (class)->dispose = search_dispose;
+ G_OBJECT_CLASS (class)->finalize = search_finalize;
+
+ directory_class = NAUTILUS_DIRECTORY_CLASS (class);
+
+ directory_class->are_all_files_seen = search_are_all_files_seen;
+ directory_class->contains_file = search_contains_file;
+ directory_class->force_reload = search_force_reload;
+ directory_class->call_when_ready = search_call_when_ready;
+ directory_class->cancel_callback = search_cancel_callback;
+
+ directory_class->file_monitor_add = search_monitor_add;
+ directory_class->file_monitor_remove = search_monitor_remove;
+
+ directory_class->get_file_list = search_get_file_list;
+ directory_class->is_editable = search_is_editable;
+}
+
+char *
+nautilus_search_directory_generate_new_uri (void)
+{
+ static int counter = 0;
+ struct timeval tv;
+ char *uri;
+
+ gettimeofday (&tv, NULL);
+
+ uri = g_strdup_printf (EEL_SEARCH_URI"///%ld-%ld-%d/", tv.tv_sec, tv.tv_usec, counter++);
+
+ return uri;
+}
+
+
+void
+nautilus_search_directory_set_query (NautilusSearchDirectory *search,
+ NautilusQuery *query)
+{
+ if (search->details->query != query) {
+ search->details->modified = TRUE;
+ }
+
+ if (query) {
+ g_object_ref (query);
+ }
+
+ if (search->details->query) {
+ g_object_unref (search->details->query);
+ }
+
+ search->details->query = query;
+}
+
+NautilusQuery *
+nautilus_search_directory_get_query (NautilusSearchDirectory *search)
+{
+ if (search->details->query != NULL) {
+ return g_object_ref (search->details->query);
+ }
+
+ return NULL;
+}
+
+NautilusSearchDirectory *
+nautilus_search_directory_new_from_saved_search (const char *uri)
+{
+ NautilusSearchDirectory *search;
+ NautilusQuery *query;
+ char *file;
+
+ search = NAUTILUS_SEARCH_DIRECTORY (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY, NULL));
+
+ search->details->saved_search_uri = g_strdup (uri);
+
+ file = gnome_vfs_get_local_path_from_uri (uri);
+ if (file != NULL) {
+ query = nautilus_query_load (file);
+ if (query != NULL) {
+ nautilus_search_directory_set_query (search, query);
+ g_object_unref (query);
+ }
+ g_free (file);
+ } else {
+ g_warning ("Non-local saved searches not supported");
+ }
+
+ search->details->modified = FALSE;
+ return search;
+}
+
+gboolean
+nautilus_search_directory_is_saved_search (NautilusSearchDirectory *search)
+{
+ return search->details->saved_search_uri != NULL;
+}
+
+gboolean
+nautilus_search_directory_is_modified (NautilusSearchDirectory *search)
+{
+ return search->details->modified;
+}
+
+gboolean
+nautilus_search_directory_is_indexed (NautilusSearchDirectory *search)
+{
+ ensure_search_engine (search);
+ return nautilus_search_engine_is_indexed (search->details->engine);
+}
+
+
+void
+nautilus_search_directory_save_to_file (NautilusSearchDirectory *search,
+ const char *save_file_uri)
+{
+ char *file;
+
+ file = gnome_vfs_get_local_path_from_uri (save_file_uri);
+ if (file == NULL) {
+ return;
+ }
+
+ if (search->details->query != NULL) {
+ nautilus_query_save (search->details->query, file);
+ }
+
+ g_free (file);
+}
+
+void
+nautilus_search_directory_save_search (NautilusSearchDirectory *search)
+{
+ if (search->details->saved_search_uri == NULL) {
+ return;
+ }
+
+ nautilus_search_directory_save_to_file (search,
+ search->details->saved_search_uri);
+ search->details->modified = FALSE;
+}
diff --git a/libnautilus-private/nautilus-search-directory.h b/libnautilus-private/nautilus-search-directory.h
new file mode 100644
index 000000000..c00869206
--- /dev/null
+++ b/libnautilus-private/nautilus-search-directory.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ nautilus-search-directory.h: Subclass of NautilusDirectory to implement
+ a virtual directory consisting of the search directory and the search
+ icons
+
+ Copyright (C) 2005 Novell, Inc
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef NAUTILUS_SEARCH_DIRECTORY_H
+#define NAUTILUS_SEARCH_DIRECTORY_H
+
+#include <libnautilus-private/nautilus-directory.h>
+#include <libnautilus-private/nautilus-query.h>
+
+#define NAUTILUS_TYPE_SEARCH_DIRECTORY \
+ (nautilus_search_directory_get_type ())
+#define NAUTILUS_SEARCH_DIRECTORY(obj) \
+ (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_SEARCH_DIRECTORY, NautilusSearchDirectory))
+#define NAUTILUS_SEARCH_DIRECTORY_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_DIRECTORY, NautilusSearchDirectoryClass))
+#define NAUTILUS_IS_SEARCH_DIRECTORY(obj) \
+ (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_SEARCH_DIRECTORY))
+#define NAUTILUS_IS_SEARCH_DIRECTORY_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_DIRECTORY))
+
+typedef struct NautilusSearchDirectoryDetails NautilusSearchDirectoryDetails;
+
+typedef struct {
+ NautilusDirectory parent_slot;
+ NautilusSearchDirectoryDetails *details;
+} NautilusSearchDirectory;
+
+typedef struct {
+ NautilusDirectoryClass parent_slot;
+} NautilusSearchDirectoryClass;
+
+GType nautilus_search_directory_get_type (void);
+
+char *nautilus_search_directory_generate_new_uri (void);
+
+NautilusSearchDirectory *nautilus_search_directory_new_from_saved_search (const char *uri);
+
+gboolean nautilus_search_directory_is_saved_search (NautilusSearchDirectory *search);
+gboolean nautilus_search_directory_is_modified (NautilusSearchDirectory *search);
+gboolean nautilus_search_directory_is_indexed (NautilusSearchDirectory *search);
+void nautilus_search_directory_save_search (NautilusSearchDirectory *search);
+void nautilus_search_directory_save_to_file (NautilusSearchDirectory *search,
+ const char *save_file_uri);
+
+NautilusQuery *nautilus_search_directory_get_query (NautilusSearchDirectory *search);
+void nautilus_search_directory_set_query (NautilusSearchDirectory *search,
+ NautilusQuery *query);
+
+#endif /* NAUTILUS_SEARCH_DIRECTORY_H */
diff --git a/libnautilus-private/nautilus-search-engine-beagle.c b/libnautilus-private/nautilus-search-engine-beagle.c
new file mode 100644
index 000000000..e86f10d01
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine-beagle.c
@@ -0,0 +1,289 @@
+/* -*- 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-engine-beagle.h"
+#include <beagle/beagle.h>
+
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-glib-extensions.h>
+
+struct NautilusSearchEngineBeagleDetails {
+ BeagleClient *client;
+ NautilusQuery *query;
+
+ BeagleQuery *current_query;
+ char *current_query_uri_prefix;
+ gboolean query_finished;
+};
+
+
+static void nautilus_search_engine_beagle_class_init (NautilusSearchEngineBeagleClass *class);
+static void nautilus_search_engine_beagle_init (NautilusSearchEngineBeagle *engine);
+
+G_DEFINE_TYPE (NautilusSearchEngineBeagle,
+ nautilus_search_engine_beagle,
+ NAUTILUS_TYPE_SEARCH_ENGINE);
+
+static NautilusSearchEngineClass *parent_class = NULL;
+
+static void
+finalize (GObject *object)
+{
+ NautilusSearchEngineBeagle *beagle;
+
+ beagle = NAUTILUS_SEARCH_ENGINE_BEAGLE (object);
+
+ if (beagle->details->current_query) {
+ g_object_unref (beagle->details->current_query);
+ beagle->details->current_query = NULL;
+ g_free (beagle->details->current_query_uri_prefix);
+ beagle->details->current_query_uri_prefix = NULL;
+ }
+
+ if (beagle->details->query) {
+ g_object_unref (beagle->details->query);
+ beagle->details->query = NULL;
+ }
+
+ if (beagle->details->client) {
+ g_object_unref (beagle->details->client);
+ beagle->details->client = NULL;
+ }
+
+ g_free (beagle->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+beagle_hits_added (BeagleQuery *query,
+ BeagleHitsAddedResponse *response,
+ NautilusSearchEngineBeagle *engine)
+{
+ GSList *hits, *list;
+ GList *hit_uris;
+ const char *uri;
+
+ hit_uris = NULL;
+
+ hits = beagle_hits_added_response_get_hits (response);
+
+ for (list = hits; list != NULL; list = list->next) {
+ BeagleHit *hit = BEAGLE_HIT (list->data);
+
+ uri = beagle_hit_get_uri (hit);
+
+ if (engine->details->current_query_uri_prefix &&
+ !g_str_has_prefix (uri, engine->details->current_query_uri_prefix)) {
+ continue;
+ }
+
+ hit_uris = g_list_prepend (hit_uris, (char *)uri);
+ }
+
+ nautilus_search_engine_hits_added (NAUTILUS_SEARCH_ENGINE (engine), hit_uris);
+ g_list_free (hit_uris);
+}
+
+static void
+beagle_hits_subtracted (BeagleQuery *query,
+ BeagleHitsSubtractedResponse *response,
+ NautilusSearchEngineBeagle *engine)
+{
+ GSList *uris, *list;
+ GList *hit_uris;
+
+ hit_uris = NULL;
+
+ uris = beagle_hits_subtracted_response_get_uris (response);
+
+ for (list = uris; list != NULL; list = list->next) {
+ hit_uris = g_list_prepend (hit_uris, (char *)list->data);
+ }
+
+ nautilus_search_engine_hits_subtracted (NAUTILUS_SEARCH_ENGINE (engine), hit_uris);
+ g_list_free (hit_uris);
+}
+
+static void
+beagle_finished (BeagleQuery *query,
+ BeagleFinishedResponse *response,
+ NautilusSearchEngineBeagle *engine)
+{
+ /* For some reason we keep getting finished events,
+ * only emit finished once */
+ if (engine->details->query_finished) {
+ return;
+ }
+
+ engine->details->query_finished = TRUE;
+ nautilus_search_engine_finished (NAUTILUS_SEARCH_ENGINE (engine));
+}
+
+static void
+beagle_error (BeagleQuery *query,
+ GError *error,
+ NautilusSearchEngineBeagle *engine)
+{
+ nautilus_search_engine_error (NAUTILUS_SEARCH_ENGINE (engine), error->message);
+}
+
+static void
+nautilus_search_engine_beagle_start (NautilusSearchEngine *engine)
+{
+ NautilusSearchEngineBeagle *beagle;
+ GError *error;
+ GList *mimetypes, *l;
+ char *text, *mimetype;
+
+ error = NULL;
+ beagle = NAUTILUS_SEARCH_ENGINE_BEAGLE (engine);
+
+ if (beagle->details->current_query) {
+ return;
+ }
+
+ beagle->details->query_finished = FALSE;
+ beagle->details->current_query = beagle_query_new ();
+ g_signal_connect (beagle->details->current_query,
+ "hits-added", G_CALLBACK (beagle_hits_added), engine);
+ g_signal_connect (beagle->details->current_query,
+ "hits-subtracted", G_CALLBACK (beagle_hits_subtracted), engine);
+ g_signal_connect (beagle->details->current_query,
+ "finished", G_CALLBACK (beagle_finished), engine);
+ g_signal_connect (beagle->details->current_query,
+ "error", G_CALLBACK (beagle_error), engine);
+
+ /* We only want files */
+ beagle_query_add_hit_type (beagle->details->current_query,
+ "File");
+ beagle_query_set_max_hits (beagle->details->current_query,
+ 1000);
+
+ text = nautilus_query_get_text (beagle->details->query);
+ beagle_query_add_text (beagle->details->current_query,
+ text);
+
+ mimetypes = nautilus_query_get_mime_types (beagle->details->query);
+ for (l = mimetypes; l != NULL; l = l->next) {
+ mimetype = l->data;
+ beagle_query_add_mime_type (beagle->details->current_query,
+ mimetype);
+ }
+
+ beagle->details->current_query_uri_prefix = nautilus_query_get_location (beagle->details->query);
+
+ if (!beagle_client_send_request_async (beagle->details->client,
+ BEAGLE_REQUEST (beagle->details->current_query), &error)) {
+ nautilus_search_engine_error (engine, error->message);
+ g_error_free (error);
+ }
+
+ /* These must live during the lifetime of the query */
+ g_free (text);
+ eel_g_list_free_deep (mimetypes);
+}
+
+static void
+nautilus_search_engine_beagle_stop (NautilusSearchEngine *engine)
+{
+ NautilusSearchEngineBeagle *beagle;
+
+ beagle = NAUTILUS_SEARCH_ENGINE_BEAGLE (engine);
+
+ if (beagle->details->current_query) {
+ g_object_unref (beagle->details->current_query);
+ beagle->details->current_query = NULL;
+ g_free (beagle->details->current_query_uri_prefix);
+ beagle->details->current_query_uri_prefix = NULL;
+ }
+}
+
+static gboolean
+nautilus_search_engine_beagle_is_indexed (NautilusSearchEngine *engine)
+{
+ return TRUE;
+}
+
+static void
+nautilus_search_engine_beagle_set_query (NautilusSearchEngine *engine, NautilusQuery *query)
+{
+ NautilusSearchEngineBeagle *beagle;
+
+ beagle = NAUTILUS_SEARCH_ENGINE_BEAGLE (engine);
+
+ if (query) {
+ g_object_ref (query);
+ }
+
+ if (beagle->details->query) {
+ g_object_unref (beagle->details->query);
+ }
+
+ beagle->details->query = query;
+}
+
+static void
+nautilus_search_engine_beagle_class_init (NautilusSearchEngineBeagleClass *class)
+{
+ GObjectClass *gobject_class;
+ NautilusSearchEngineClass *engine_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ engine_class = NAUTILUS_SEARCH_ENGINE_CLASS (class);
+ engine_class->set_query = nautilus_search_engine_beagle_set_query;
+ engine_class->start = nautilus_search_engine_beagle_start;
+ engine_class->stop = nautilus_search_engine_beagle_stop;
+ engine_class->is_indexed = nautilus_search_engine_beagle_is_indexed;
+}
+
+static void
+nautilus_search_engine_beagle_init (NautilusSearchEngineBeagle *engine)
+{
+ engine->details = g_new0 (NautilusSearchEngineBeagleDetails, 1);
+}
+
+
+NautilusSearchEngine *
+nautilus_search_engine_beagle_new (void)
+{
+ NautilusSearchEngineBeagle *engine;
+ BeagleClient *client;
+
+ client = beagle_client_new (NULL);
+
+ if (client == NULL) {
+ return NULL;
+ }
+
+ engine = g_object_new (NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE, NULL);
+
+ engine->details->client = client;
+
+ return NAUTILUS_SEARCH_ENGINE (engine);
+}
diff --git a/libnautilus-private/nautilus-search-engine-beagle.h b/libnautilus-private/nautilus-search-engine-beagle.h
new file mode 100644
index 000000000..7ee801b37
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine-beagle.h
@@ -0,0 +1,51 @@
+/* -*- 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_ENGINE_BEAGLE_H
+#define NAUTILUS_SEARCH_ENGINE_BEAGLE_H
+
+#include <libnautilus-private/nautilus-search-engine.h>
+
+#define NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE (nautilus_search_engine_beagle_get_type ())
+#define NAUTILUS_SEARCH_ENGINE_BEAGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE, NautilusSearchEngineBeagle))
+#define NAUTILUS_SEARCH_ENGINE_BEAGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE, NautilusSearchEngineBeagleClass))
+#define NAUTILUS_IS_SEARCH_ENGINE_BEAGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE))
+#define NAUTILUS_IS_SEARCH_ENGINE_BEAGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE))
+#define NAUTILUS_SEARCH_ENGINE_BEAGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_BEAGLE, NautilusSearchEngineBeagleClass))
+
+typedef struct NautilusSearchEngineBeagleDetails NautilusSearchEngineBeagleDetails;
+
+typedef struct NautilusSearchEngineBeagle {
+ NautilusSearchEngine parent;
+ NautilusSearchEngineBeagleDetails *details;
+} NautilusSearchEngineBeagle;
+
+typedef struct {
+ NautilusSearchEngineClass parent_class;
+} NautilusSearchEngineBeagleClass;
+
+GType nautilus_search_engine_beagle_get_type (void);
+
+NautilusSearchEngine* nautilus_search_engine_beagle_new (void);
+
+#endif /* NAUTILUS_SEARCH_ENGINE_BEAGLE_H */
diff --git a/libnautilus-private/nautilus-search-engine-simple.c b/libnautilus-private/nautilus-search-engine-simple.c
new file mode 100644
index 000000000..7e5d5f314
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine-simple.c
@@ -0,0 +1,370 @@
+/* -*- 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-search-engine-simple.h"
+
+#include <string.h>
+#include <glib/gstrfuncs.h>
+#include <eel/eel-gtk-macros.h>
+#include <eel/eel-glib-extensions.h>
+#include <libgnomevfs/gnome-vfs-directory.h>
+
+#define BATCH_SIZE 500
+
+typedef struct {
+ NautilusSearchEngineSimple *engine;
+
+ GnomeVFSURI *uri;
+ GList *mime_types;
+ char **words;
+ GList *found_list;
+
+ gint n_processed_files;
+ GList *uri_hits;
+
+ /* accessed on both threads: */
+ volatile gboolean cancelled;
+} SearchThreadData;
+
+
+struct NautilusSearchEngineSimpleDetails {
+ NautilusQuery *query;
+
+ SearchThreadData *active_search;
+
+ gboolean query_finished;
+};
+
+
+static void nautilus_search_engine_simple_class_init (NautilusSearchEngineSimpleClass *class);
+static void nautilus_search_engine_simple_init (NautilusSearchEngineSimple *engine);
+
+G_DEFINE_TYPE (NautilusSearchEngineSimple,
+ nautilus_search_engine_simple,
+ NAUTILUS_TYPE_SEARCH_ENGINE);
+
+static NautilusSearchEngineClass *parent_class = NULL;
+
+static void
+finalize (GObject *object)
+{
+ NautilusSearchEngineSimple *simple;
+
+ simple = NAUTILUS_SEARCH_ENGINE_SIMPLE (object);
+
+ if (simple->details->query) {
+ g_object_unref (simple->details->query);
+ simple->details->query = NULL;
+ }
+
+ g_free (simple->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static SearchThreadData *
+search_thread_data_new (NautilusSearchEngineSimple *engine,
+ NautilusQuery *query)
+{
+ SearchThreadData *data;
+ char *text, *lower, *uri;
+
+ data = g_new0 (SearchThreadData, 1);
+
+ data->engine = engine;
+ uri = nautilus_query_get_location (query);
+ if (uri != NULL) {
+ data->uri = gnome_vfs_uri_new (uri);
+ g_free (uri);
+ }
+ if (data->uri == NULL) {
+ data->uri = gnome_vfs_uri_new ("file:///");
+ }
+
+ text = nautilus_query_get_text (query);
+ lower = g_ascii_strdown (text, -1);
+ data->words = g_strsplit (lower, " ", -1);
+ g_free (text);
+ g_free (lower);
+
+ data->mime_types = nautilus_query_get_mime_types (query);
+
+ return data;
+}
+
+static void
+search_thread_data_free (SearchThreadData *data)
+{
+ gnome_vfs_uri_unref (data->uri);
+ g_strfreev (data->words);
+ eel_g_list_free_deep (data->mime_types);
+ g_free (data);
+}
+
+static gboolean
+search_thread_done_idle (gpointer user_data)
+{
+ SearchThreadData *data;
+
+ data = user_data;
+
+ if (!data->cancelled) {
+ nautilus_search_engine_finished (NAUTILUS_SEARCH_ENGINE (data->engine));
+ data->engine->details->active_search = NULL;
+ }
+
+ search_thread_data_free (data);
+
+ return FALSE;
+}
+
+typedef struct {
+ GList *uris;
+ SearchThreadData *thread_data;
+} SearchHits;
+
+
+static gboolean
+search_thread_add_hits_idle (gpointer user_data)
+{
+ SearchHits *hits;
+
+ hits = user_data;
+
+ if (!hits->thread_data->cancelled) {
+ nautilus_search_engine_hits_added (NAUTILUS_SEARCH_ENGINE (hits->thread_data->engine),
+ hits->uris);
+ }
+
+ eel_g_list_free_deep (hits->uris);
+ g_free (hits);
+
+ return FALSE;
+}
+
+static void
+send_batch (SearchThreadData *data)
+{
+ SearchHits *hits;
+
+ data->n_processed_files = 0;
+
+ if (data->uri_hits) {
+ hits = g_new (SearchHits, 1);
+ hits->uris = data->uri_hits;
+ hits->thread_data = data;
+ g_idle_add (search_thread_add_hits_idle, hits);
+ }
+ data->uri_hits = NULL;
+}
+
+static gboolean
+search_visit_func (const gchar *rel_path,
+ GnomeVFSFileInfo *info,
+ gboolean recursing_will_loop,
+ gpointer user_data,
+ gboolean *recurse)
+{
+ SearchThreadData *data;
+ int i;
+ char *lower_name;
+ GnomeVFSURI *uri;
+ gboolean hit;
+ GList *l;
+ gboolean is_hidden;
+
+ data = user_data;
+
+ if (data->cancelled) {
+ return FALSE;
+ }
+
+ is_hidden = *info->name == '.';
+
+ if (recursing_will_loop || is_hidden) {
+ *recurse = FALSE;
+ } else {
+ *recurse = TRUE;
+ }
+
+ hit = FALSE;
+
+ if (!is_hidden) {
+ lower_name = g_ascii_strdown (info->name, -1);
+
+ hit = TRUE;
+ for (i = 0; data->words[i] != NULL; i++) {
+ if (strstr (lower_name, data->words[i]) == NULL) {
+ hit = FALSE;
+ break;
+ }
+ }
+ g_free (lower_name);
+ }
+
+ if (hit && data->mime_types != NULL) {
+ hit = FALSE;
+
+ if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) {
+ for (l = data->mime_types; l != NULL; l = l->next) {
+ if (strcmp (info->mime_type, l->data) == 0) {
+ hit = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (hit) {
+ uri = gnome_vfs_uri_append_string (data->uri, rel_path);
+ data->uri_hits = g_list_prepend (data->uri_hits, gnome_vfs_uri_to_string (uri, 0));
+ gnome_vfs_uri_unref (uri);
+ }
+
+ data->n_processed_files++;
+
+ if (data->n_processed_files > BATCH_SIZE) {
+ send_batch (data);
+ }
+
+
+ return TRUE;
+}
+
+
+
+static gpointer
+search_thread_func (gpointer user_data)
+{
+ SearchThreadData *data;
+ GnomeVFSResult res;
+
+ data = user_data;
+
+ res = gnome_vfs_directory_visit_uri (data->uri,
+ GNOME_VFS_FILE_INFO_GET_MIME_TYPE | GNOME_VFS_FILE_INFO_FOLLOW_LINKS,
+ GNOME_VFS_DIRECTORY_VISIT_LOOPCHECK,
+ search_visit_func,
+ data);
+ send_batch (data);
+
+ g_idle_add (search_thread_done_idle, data);
+
+ return NULL;
+}
+
+static void
+nautilus_search_engine_simple_start (NautilusSearchEngine *engine)
+{
+ NautilusSearchEngineSimple *simple;
+ SearchThreadData *data;
+
+ simple = NAUTILUS_SEARCH_ENGINE_SIMPLE (engine);
+
+ if (simple->details->active_search != NULL) {
+ return;
+ }
+
+ if (simple->details->query == NULL) {
+ return;
+ }
+
+ data = search_thread_data_new (simple, simple->details->query);
+
+ g_thread_create (search_thread_func, data, FALSE, NULL);
+
+ simple->details->active_search = data;
+}
+
+static void
+nautilus_search_engine_simple_stop (NautilusSearchEngine *engine)
+{
+ NautilusSearchEngineSimple *simple;
+
+ simple = NAUTILUS_SEARCH_ENGINE_SIMPLE (engine);
+
+ if (simple->details->active_search != NULL) {
+ simple->details->active_search->cancelled = TRUE;
+ simple->details->active_search = NULL;
+ }
+}
+
+static gboolean
+nautilus_search_engine_simple_is_indexed (NautilusSearchEngine *engine)
+{
+ return FALSE;
+}
+
+static void
+nautilus_search_engine_simple_set_query (NautilusSearchEngine *engine, NautilusQuery *query)
+{
+ NautilusSearchEngineSimple *simple;
+
+ simple = NAUTILUS_SEARCH_ENGINE_SIMPLE (engine);
+
+ if (query) {
+ g_object_ref (query);
+ }
+
+ if (simple->details->query) {
+ g_object_unref (simple->details->query);
+ }
+
+ simple->details->query = query;
+}
+
+static void
+nautilus_search_engine_simple_class_init (NautilusSearchEngineSimpleClass *class)
+{
+ GObjectClass *gobject_class;
+ NautilusSearchEngineClass *engine_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ engine_class = NAUTILUS_SEARCH_ENGINE_CLASS (class);
+ engine_class->set_query = nautilus_search_engine_simple_set_query;
+ engine_class->start = nautilus_search_engine_simple_start;
+ engine_class->stop = nautilus_search_engine_simple_stop;
+ engine_class->is_indexed = nautilus_search_engine_simple_is_indexed;
+}
+
+static void
+nautilus_search_engine_simple_init (NautilusSearchEngineSimple *engine)
+{
+ engine->details = g_new0 (NautilusSearchEngineSimpleDetails, 1);
+}
+
+
+NautilusSearchEngine *
+nautilus_search_engine_simple_new (void)
+{
+ NautilusSearchEngine *engine;
+
+ engine = g_object_new (NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE, NULL);
+
+ return engine;
+}
diff --git a/libnautilus-private/nautilus-search-engine-simple.h b/libnautilus-private/nautilus-search-engine-simple.h
new file mode 100644
index 000000000..be7bfb1b0
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine-simple.h
@@ -0,0 +1,51 @@
+/* -*- 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_SEARCH_ENGINE_SIMPLE_H
+#define NAUTILUS_SEARCH_ENGINE_SIMPLE_H
+
+#include <libnautilus-private/nautilus-search-engine.h>
+
+#define NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE (nautilus_search_engine_simple_get_type ())
+#define NAUTILUS_SEARCH_ENGINE_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE, NautilusSearchEngineSimple))
+#define NAUTILUS_SEARCH_ENGINE_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE, NautilusSearchEngineSimpleClass))
+#define NAUTILUS_IS_SEARCH_ENGINE_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE))
+#define NAUTILUS_IS_SEARCH_ENGINE_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE))
+#define NAUTILUS_SEARCH_ENGINE_SIMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_SEARCH_ENGINE_SIMPLE, NautilusSearchEngineSimpleClass))
+
+typedef struct NautilusSearchEngineSimpleDetails NautilusSearchEngineSimpleDetails;
+
+typedef struct NautilusSearchEngineSimple {
+ NautilusSearchEngine parent;
+ NautilusSearchEngineSimpleDetails *details;
+} NautilusSearchEngineSimple;
+
+typedef struct {
+ NautilusSearchEngineClass parent_class;
+} NautilusSearchEngineSimpleClass;
+
+GType nautilus_search_engine_simple_get_type (void);
+
+NautilusSearchEngine* nautilus_search_engine_simple_new (void);
+
+#endif /* NAUTILUS_SEARCH_ENGINE_SIMPLE_H */
diff --git a/libnautilus-private/nautilus-search-engine.c b/libnautilus-private/nautilus-search-engine.c
new file mode 100644
index 000000000..d98b1f40e
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine.c
@@ -0,0 +1,207 @@
+/* -*- 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-engine.h"
+#include "nautilus-search-engine-beagle.h"
+#include "nautilus-search-engine-simple.h"
+
+#include <eel/eel-gtk-macros.h>
+
+struct NautilusSearchEngineDetails {
+ int none;
+};
+
+enum {
+ HITS_ADDED,
+ HITS_SUBTRACTED,
+ FINISHED,
+ ERROR,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void nautilus_search_engine_class_init (NautilusSearchEngineClass *class);
+static void nautilus_search_engine_init (NautilusSearchEngine *engine);
+
+G_DEFINE_ABSTRACT_TYPE (NautilusSearchEngine,
+ nautilus_search_engine,
+ G_TYPE_OBJECT);
+
+static GObjectClass *parent_class = NULL;
+
+static void
+finalize (GObject *object)
+{
+ NautilusSearchEngine *engine;
+
+ engine = NAUTILUS_SEARCH_ENGINE (object);
+
+ g_free (engine->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+nautilus_search_engine_class_init (NautilusSearchEngineClass *class)
+{
+ GObjectClass *gobject_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ signals[HITS_ADDED] =
+ g_signal_new ("hits-added",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusSearchEngineClass, hits_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[HITS_SUBTRACTED] =
+ g_signal_new ("hits-subtracted",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusSearchEngineClass, hits_subtracted),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[FINISHED] =
+ g_signal_new ("finished",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusSearchEngineClass, finished),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[ERROR] =
+ g_signal_new ("error",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusSearchEngineClass, error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+
+}
+
+static void
+nautilus_search_engine_init (NautilusSearchEngine *engine)
+{
+ engine->details = g_new0 (NautilusSearchEngineDetails, 1);
+}
+
+NautilusSearchEngine *
+nautilus_search_engine_new (void)
+{
+ NautilusSearchEngine *engine;
+
+#ifdef HAVE_BEAGLE
+ engine = nautilus_search_engine_beagle_new ();
+ if (engine) {
+ return engine;
+ }
+#endif
+ engine = nautilus_search_engine_simple_new ();
+ return engine;
+}
+
+void
+nautilus_search_engine_set_query (NautilusSearchEngine *engine, NautilusQuery *query)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+ g_return_if_fail (NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->set_query != NULL);
+
+ NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->set_query (engine, query);
+}
+
+void
+nautilus_search_engine_start (NautilusSearchEngine *engine)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+ g_return_if_fail (NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->start != NULL);
+
+ NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->start (engine);
+}
+
+
+void
+nautilus_search_engine_stop (NautilusSearchEngine *engine)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+ g_return_if_fail (NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->stop != NULL);
+
+ NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->stop (engine);
+}
+
+gboolean
+nautilus_search_engine_is_indexed (NautilusSearchEngine *engine)
+{
+ g_return_val_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine), FALSE);
+ g_return_val_if_fail (NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->is_indexed != NULL, FALSE);
+
+ return NAUTILUS_SEARCH_ENGINE_GET_CLASS (engine)->is_indexed (engine);
+}
+
+void
+nautilus_search_engine_hits_added (NautilusSearchEngine *engine, GList *hits)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[HITS_ADDED], 0, hits);
+}
+
+
+void
+nautilus_search_engine_hits_subtracted (NautilusSearchEngine *engine, GList *hits)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[HITS_SUBTRACTED], 0, hits);
+}
+
+
+void
+nautilus_search_engine_finished (NautilusSearchEngine *engine)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[FINISHED], 0);
+}
+
+void
+nautilus_search_engine_error (NautilusSearchEngine *engine, const char *error_message)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[ERROR], 0, error_message);
+}
diff --git a/libnautilus-private/nautilus-search-engine.h b/libnautilus-private/nautilus-search-engine.h
new file mode 100644
index 000000000..79e68aeb3
--- /dev/null
+++ b/libnautilus-private/nautilus-search-engine.h
@@ -0,0 +1,76 @@
+/* -*- 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_ENGINE_H
+#define NAUTILUS_SEARCH_ENGINE_H
+
+#include <glib-object.h>
+#include <libgnomevfs/gnome-vfs-result.h>
+#include <libnautilus-private/nautilus-query.h>
+
+#define NAUTILUS_TYPE_SEARCH_ENGINE (nautilus_search_engine_get_type ())
+#define NAUTILUS_SEARCH_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_SEARCH_ENGINE, NautilusSearchEngine))
+#define NAUTILUS_SEARCH_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_ENGINE, NautilusSearchEngineClass))
+#define NAUTILUS_IS_SEARCH_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_SEARCH_ENGINE))
+#define NAUTILUS_IS_SEARCH_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_ENGINE))
+#define NAUTILUS_SEARCH_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_SEARCH_ENGINE, NautilusSearchEngineClass))
+
+typedef struct NautilusSearchEngineDetails NautilusSearchEngineDetails;
+
+typedef struct NautilusSearchEngine {
+ GObject parent;
+ NautilusSearchEngineDetails *details;
+} NautilusSearchEngine;
+
+typedef struct {
+ GObjectClass parent_class;
+
+ /* VTable */
+ void (*set_query) (NautilusSearchEngine *engine, NautilusQuery *query);
+ void (*start) (NautilusSearchEngine *engine);
+ void (*stop) (NautilusSearchEngine *engine);
+ gboolean (*is_indexed) (NautilusSearchEngine *engine);
+
+ /* Signals */
+ void (*hits_added) (NautilusSearchEngine *engine, GList *hits);
+ void (*hits_subtracted) (NautilusSearchEngine *engine, GList *hits);
+ void (*finished) (NautilusSearchEngine *engine);
+ void (*error) (NautilusSearchEngine *engine, const char *error_message);
+} NautilusSearchEngineClass;
+
+GType nautilus_search_engine_get_type (void);
+gboolean nautilus_search_engine_enabled (void);
+
+NautilusSearchEngine* nautilus_search_engine_new (void);
+
+void nautilus_search_engine_set_query (NautilusSearchEngine *engine, NautilusQuery *query);
+void nautilus_search_engine_start (NautilusSearchEngine *engine);
+void nautilus_search_engine_stop (NautilusSearchEngine *engine);
+gboolean nautilus_search_engine_is_indexed (NautilusSearchEngine *engine);
+
+void nautilus_search_engine_hits_added (NautilusSearchEngine *engine, GList *hits);
+void nautilus_search_engine_hits_subtracted (NautilusSearchEngine *engine, GList *hits);
+void nautilus_search_engine_finished (NautilusSearchEngine *engine);
+void nautilus_search_engine_error (NautilusSearchEngine *engine, const char *error_message);
+
+#endif /* NAUTILUS_SEARCH_ENGINE_H */
diff --git a/libnautilus-private/nautilus-tree-view-drag-dest.c b/libnautilus-private/nautilus-tree-view-drag-dest.c
index 4d6b3aedb..1d0c94df8 100644
--- a/libnautilus-private/nautilus-tree-view-drag-dest.c
+++ b/libnautilus-private/nautilus-tree-view-drag-dest.c
@@ -310,21 +310,23 @@ get_drop_path (NautilusTreeViewDragDest *dest,
return NULL;
}
- file = file_for_path (dest, path);
-
- ret = NULL;
+ ret = gtk_tree_path_copy (path);
+ file = file_for_path (dest, ret);
- if (!file || !nautilus_drag_can_accept_items (file, dest->details->drag_list)){
+ /* Go up the tree until we find a file that can accept a drop */
+ while (file == NULL /* dummy row */ ||
+ !nautilus_drag_can_accept_items (file, dest->details->drag_list)) {
if (gtk_tree_path_get_depth (path) == 1) {
+ gtk_tree_path_free (ret);
ret = NULL;
+ break;
} else {
- ret = gtk_tree_path_copy (path);
gtk_tree_path_up (ret);
+
+ nautilus_file_unref (file);
+ file = file_for_path (dest, ret);
}
- } else {
- ret = gtk_tree_path_copy (path);
}
-
nautilus_file_unref (file);
return ret;
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
diff --git a/test/.cvsignore b/test/.cvsignore
index 32b1fd7b8..57492f72f 100644
--- a/test/.cvsignore
+++ b/test/.cvsignore
@@ -8,3 +8,5 @@ test-nautilus-mime-actions-set
test-nautilus-preferences-change
test-nautilus-preferences-display
test-nautilus-wrap-table
+test-nautilus-directory-async
+test-nautilus-search-engine
diff --git a/test/Makefile.am b/test/Makefile.am
index b6c59464e..b6fd4cd70 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -14,10 +14,16 @@ LDADD =\
noinst_PROGRAMS =\
test-nautilus-wrap-table \
+ test-nautilus-search-engine \
+ test-nautilus-directory-async \
$(NULL)
test_nautilus_wrap_table_SOURCES = test-nautilus-wrap-table.c test.c
+test_nautilus_search_engine_SOURCES = test-nautilus-search-engine.c
+
+test_nautilus_directory_async_SOURCES = test-nautilus-directory-async.c
+
EXTRA_DIST = \
test.h \
$(NULL)
diff --git a/test/test-nautilus-directory-async.c b/test/test-nautilus-directory-async.c
new file mode 100644
index 000000000..ed6eb35ae
--- /dev/null
+++ b/test/test-nautilus-directory-async.c
@@ -0,0 +1,106 @@
+#include <gtk/gtk.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libnautilus-private/nautilus-directory.h>
+#include <libnautilus-private/nautilus-search-directory.h>
+#include <libnautilus-private/nautilus-file.h>
+#include <unistd.h>
+
+void *client1, *client2;
+
+#if 0
+static gboolean
+quit_cb (gpointer data)
+{
+ gtk_main_quit ();
+
+ return FALSE;
+}
+#endif
+
+static void
+files_added (NautilusDirectory *directory,
+ GList *added_files)
+{
+#if 0
+ GList *list;
+
+ for (list = added_files; list != NULL; list = list->next) {
+ NautilusFile *file = list->data;
+
+ g_print (" - %s\n", nautilus_file_get_uri (file));
+ }
+#endif
+
+ g_print ("files added: %d files\n",
+ g_list_length (added_files));
+}
+
+static void
+files_changed (NautilusDirectory *directory,
+ GList *changed_files)
+{
+#if 0
+ GList *list;
+
+ for (list = changed_files; list != NULL; list = list->next) {
+ NautilusFile *file = list->data;
+
+ g_print (" - %s\n", nautilus_file_get_uri (file));
+ }
+#endif
+ g_print ("files changed: %d\n",
+ g_list_length (changed_files));
+}
+
+static gboolean
+force_reload (NautilusDirectory *directory)
+{
+ g_print ("forcing reload!\n");
+
+ nautilus_directory_force_reload (directory);
+
+ return FALSE;
+}
+
+static void
+done_loading (NautilusDirectory *directory)
+{
+ static int i = 0;
+
+ g_print ("done loading\n");
+
+ if (i == 0) {
+ gtk_timeout_add (5000, (GSourceFunc)force_reload, directory);
+ i++;
+ } else {
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ NautilusDirectory *directory;
+ client1 = g_new0 (int, 1);
+ client2 = g_new0 (int, 1);
+ NautilusQuery *query;
+
+ gnome_vfs_init ();
+ gtk_init (&argc, &argv);
+
+ query = nautilus_query_new ();
+ nautilus_query_set_text (query, "richard hult");
+ directory = nautilus_directory_get ("x-nautilus-search://0/");
+ nautilus_search_directory_set_query (NAUTILUS_SEARCH_DIRECTORY (directory), query);
+ g_object_unref (query);
+
+ g_signal_connect (directory, "files-added", G_CALLBACK (files_added), NULL);
+ g_signal_connect (directory, "files-changed", G_CALLBACK (files_changed), NULL);
+ g_signal_connect (directory, "done-loading", G_CALLBACK (done_loading), NULL);
+ nautilus_directory_file_monitor_add (directory, client1, TRUE, TRUE,
+ NAUTILUS_FILE_ATTRIBUTE_METADATA,
+ NULL, NULL);
+
+
+ gtk_main ();
+ return 0;
+}
diff --git a/test/test-nautilus-search-engine.c b/test/test-nautilus-search-engine.c
new file mode 100644
index 000000000..f6224d004
--- /dev/null
+++ b/test/test-nautilus-search-engine.c
@@ -0,0 +1,56 @@
+#include <libnautilus-private/nautilus-search-engine.h>
+#include <gtk/gtk.h>
+
+static void
+hits_added_cb (NautilusSearchEngine *engine, GSList *hits)
+{
+ g_print ("hits added\n");
+ while (hits) {
+ g_print (" - %s\n", (char *)hits->data);
+ hits = hits->next;
+ }
+}
+
+static void
+hits_subtracted_cb (NautilusSearchEngine *engine, GSList *hits)
+{
+ g_print ("hits subtracted\n");
+ while (hits) {
+ g_print (" - %s\n", (char *)hits->data);
+ hits = hits->next;
+ }
+}
+
+static void
+finished_cb (NautilusSearchEngine *engine)
+{
+ g_print ("finished!\n");
+// gtk_main_quit ();
+}
+
+int
+main (int argc, char* argv[])
+{
+ NautilusSearchEngine *engine;
+ NautilusQuery *query;
+
+ gtk_init (&argc, &argv);
+
+ engine = nautilus_search_engine_new ();
+ g_signal_connect (engine, "hits-added",
+ G_CALLBACK (hits_added_cb), NULL);
+ g_signal_connect (engine, "hits-subtracted",
+ G_CALLBACK (hits_subtracted_cb), NULL);
+ g_signal_connect (engine, "finished",
+ G_CALLBACK (finished_cb), NULL);
+
+ query = nautilus_query_new ();
+ nautilus_query_set_text (query, "richard hult");
+ nautilus_search_engine_set_query (engine, query);
+ g_object_unref (query);
+
+ nautilus_search_engine_start (engine);
+
+ gtk_main ();
+ return 0;
+}