diff options
author | Dave Camp <dave@ximian.com> | 2004-01-11 20:35:02 +0000 |
---|---|---|
committer | Dave Camp <campd@src.gnome.org> | 2004-01-11 20:35:02 +0000 |
commit | 7cb9107c85bef29b5b8edc5fb7b06b52a041cc04 (patch) | |
tree | 6f1044bdbab09b99a8e595be0d4d8d16d27a1d47 /libnautilus-private | |
parent | b92ee1501d6afcd2993f468aa21e2976accd8519 (diff) | |
download | nautilus-7cb9107c85bef29b5b8edc5fb7b06b52a041cc04.tar.gz |
Merged from nautilus-extensions-branch.
2004-01-11 Dave Camp <dave@ximian.com>
* Merged from nautilus-extensions-branch.
Diffstat (limited to 'libnautilus-private')
21 files changed, 2140 insertions, 178 deletions
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index d6e826190..430176ca7 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -2,7 +2,9 @@ include $(top_srcdir)/Makefile.shared lib_LTLIBRARIES=libnautilus-private.la -libnautilus_private_la_LIBADD = ../libnautilus/libnautilus.la +libnautilus_private_la_LIBADD = \ + ../libnautilus/libnautilus.la \ + ../libnautilus-extension/libnautilus-extension.la INCLUDES = \ -I$(top_srcdir) \ @@ -13,6 +15,7 @@ INCLUDES = \ -DDATADIR=\""$(datadir)"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DNAUTILUS_DATADIR=\""$(datadir)/nautilus"\" \ + -DNAUTILUS_EXTENSIONDIR=\""$(libdir)/nautilus/extensions-1.0"\" \ $(NULL) dependency_static_libs = \ @@ -52,6 +55,10 @@ libnautilus_private_la_SOURCES = \ nautilus-cell-renderer-pixbuf-emblem.c \ nautilus-cell-renderer-pixbuf-emblem.h \ nautilus-cdrom-extensions.h \ + nautilus-column-chooser.c \ + nautilus-column-chooser.h \ + nautilus-column-utilities.c \ + nautilus-column-utilities.h \ nautilus-customization-data.c \ nautilus-customization-data.h \ nautilus-default-file-icon.c \ @@ -140,6 +147,8 @@ libnautilus_private_la_SOURCES = \ nautilus-metafile.h \ nautilus-mime-actions.c \ nautilus-mime-actions.h \ + nautilus-module.c \ + nautilus-module.h \ nautilus-monitor.c \ nautilus-monitor.h \ nautilus-program-chooser.c \ diff --git a/libnautilus-private/apps_nautilus_preferences.schemas.in b/libnautilus-private/apps_nautilus_preferences.schemas.in index 3671bc39b..8bea57ce7 100644 --- a/libnautilus-private/apps_nautilus_preferences.schemas.in +++ b/libnautilus-private/apps_nautilus_preferences.schemas.in @@ -584,6 +584,36 @@ </schema> <schema> + <key>/schemas/apps/nautilus/list_view/default_visible_columns</key> + <applyto>/apps/nautilus/list_view/default_visible_columns</applyto> + <owner>nautilus</owner> + <type>list</type> + <list_type>string</list_type> + <default>[name,size,type,date_modified]</default> + <locale name="C"> + <short>Default list of columns visible in the list view</short> + <long> + Default list of columns visible in the list view. + </long> + </locale> + </schema> + + <schema> + <key>/schemas/apps/nautilus/list_view/default_column_order</key> + <applyto>/apps/nautilus/list_view/default_column_order</applyto> + <owner>nautilus</owner> + <type>list</type> + <list_type>string</list_type> + <default>[name,size,type,date_modified]</default> + <locale name="C"> + <short>Default column order in the list view</short> + <long> + Default column order in the list view. + </long> + </locale> + </schema> + + <schema> <key>/schemas/apps/nautilus/preferences/hide_built_in_bookmarks</key> <applyto>/apps/nautilus/preferences/hide_built_in_bookmarks</applyto> <owner>nautilus</owner> diff --git a/libnautilus-private/nautilus-bonobo-extensions.c b/libnautilus-private/nautilus-bonobo-extensions.c index 6a363ce77..c9d1946a4 100644 --- a/libnautilus-private/nautilus-bonobo-extensions.c +++ b/libnautilus-private/nautilus-bonobo-extensions.c @@ -28,6 +28,8 @@ #include <config.h> #include "nautilus-bonobo-extensions.h" +#include "nautilus-icon-factory.h" + #include <eel/eel-string.h> #include <eel/eel-gnome-extensions.h> #include <eel/eel-debug.h> @@ -487,6 +489,165 @@ nautilus_bonobo_set_label_for_toolitem_and_command (BonoboUIComponent *ui, g_free (label_no_underscore); } +static char * +get_extension_menu_item_xml (NautilusMenuItem *item) +{ + GString *ui_xml; + char *pixbuf_data; + GdkPixbuf *pixbuf; + char *name; + char *icon; + + ui_xml = g_string_new (""); + + g_object_get (G_OBJECT (item), "name", &name, "icon", &icon, NULL); + + g_string_append_printf (ui_xml, + "<menuitem name=\"%s\" verb=\"%s\"", + name, name); + + if (icon) { + pixbuf = nautilus_icon_factory_get_pixbuf_from_name + (icon, + NULL, + NAUTILUS_ICON_SIZE_FOR_MENUS, + NULL); + if (pixbuf) { + pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf); + g_string_append_printf (ui_xml, " pixtype=\"pixbuf\" pixname=\"%s\"", pixbuf_data); + g_free (pixbuf_data); + g_object_unref (pixbuf); + } + } + g_string_append (ui_xml, "/>"); + + g_free (name); + g_free (icon); + + return g_string_free (ui_xml, FALSE); +} + +static void +extension_action_callback (BonoboUIComponent *component, + gpointer callback_data, const char *path) +{ + nautilus_menu_item_activate (NAUTILUS_MENU_ITEM (callback_data)); +} + +void +nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui, + NautilusMenuItem *item) +{ + GString *ui_xml; + GClosure *closure; + char *name; + char *label; + char *tip; + char *sensitive; + + ui_xml = g_string_new ("<Root><commands>"); + + g_object_get (G_OBJECT (item), + "name", &name, "label", &label, + "tip", &tip, "sensitive", &sensitive, + NULL); + + g_string_append_printf (ui_xml, + "<cmd name=\"%s\" label=\"%s\" tip=\"%s\" sensitive=\"%s\"/>", + name, label, tip, sensitive ? "1" : "0"); + + ui_xml = g_string_append (ui_xml, "</commands></Root>"); + + bonobo_ui_component_set (ui, "/", ui_xml->str, NULL); + g_string_free (ui_xml, TRUE); + + + closure = g_cclosure_new + (G_CALLBACK (extension_action_callback), + g_object_ref (item), + (GClosureNotify)g_object_unref); + + bonobo_ui_component_add_verb_full (ui, name, closure); + + g_free (name); + g_free (label); + g_free (tip); +} + +void +nautilus_bonobo_add_extension_item (BonoboUIComponent *ui, + const char *path, + NautilusMenuItem *item) +{ + char *item_xml; + + item_xml = get_extension_menu_item_xml (item); + + bonobo_ui_component_set (ui, path, item_xml, NULL); + + g_free (item_xml); +} + +static char * +get_extension_toolbar_item_xml (NautilusMenuItem *item) +{ + GString *ui_xml; + char *pixbuf_data; + GdkPixbuf *pixbuf; + char *name; + char *icon; + gboolean priority; + + ui_xml = g_string_new (""); + + + g_object_get (item, + "name", &name, "priority", &priority, + "icon", &icon, + NULL); + g_string_append_printf (ui_xml, + "<toolitem name=\"%s\" verb=\"%s\"", + name, name); + + if (priority) { + g_string_append (ui_xml, " priority=\"1\""); + } + + if (icon) { + pixbuf = nautilus_icon_factory_get_pixbuf_from_name + (icon, + NULL, + NAUTILUS_ICON_SIZE_FOR_MENUS, + NULL); + if (pixbuf) { + pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf); + g_string_append_printf (ui_xml, " pixtype=\"pixbuf\" pixname=\"%s\"", pixbuf_data); + g_free (pixbuf_data); + g_object_unref (pixbuf); + } + } + g_string_append (ui_xml, "/>"); + + g_free (name); + g_free (icon); + + return g_string_free (ui_xml, FALSE); +} + +void +nautilus_bonobo_add_extension_toolbar_item (BonoboUIComponent *ui, + const char *path, + NautilusMenuItem *item) +{ + char *item_xml; + + item_xml = get_extension_toolbar_item_xml (item); + + bonobo_ui_component_set (ui, path, item_xml, NULL); + + g_free (item_xml); +} + static void activation_handle_done (NautilusBonoboActivationHandle *handle) { diff --git a/libnautilus-private/nautilus-bonobo-extensions.h b/libnautilus-private/nautilus-bonobo-extensions.h index 3f3396192..f780761d6 100644 --- a/libnautilus-private/nautilus-bonobo-extensions.h +++ b/libnautilus-private/nautilus-bonobo-extensions.h @@ -32,6 +32,8 @@ #include <bonobo/bonobo-generic-factory.h> #include <gdk-pixbuf/gdk-pixbuf.h> +#include <libnautilus-extension/nautilus-menu-item.h> + typedef struct NautilusBonoboActivationHandle NautilusBonoboActivationHandle; typedef void (*NautilusBonoboActivationCallback) (NautilusBonoboActivationHandle *handle, @@ -41,78 +43,87 @@ typedef void (*NautilusBonoboActivationCallback) (NautilusBonoboActivationHandle typedef CORBA_Object (*NautilusBonoboCreateObject) (const char *iid, gpointer callback_data); -void nautilus_bonobo_set_accelerator (BonoboUIComponent *ui, - const char *path, - const char *accelerator); -char * nautilus_bonobo_get_label (BonoboUIComponent *ui, - const char *path); -void nautilus_bonobo_set_label (BonoboUIComponent *ui, - const char *path, - const char *label); -void nautilus_bonobo_set_tip (BonoboUIComponent *ui, - const char *path, - const char *tip); -void nautilus_bonobo_set_sensitive (BonoboUIComponent *ui, - const char *path, - gboolean sensitive); -void nautilus_bonobo_set_toggle_state (BonoboUIComponent *ui, - const char *path, - gboolean state); -void nautilus_bonobo_set_hidden (BonoboUIComponent *ui, - const char *path, - gboolean hidden); -gboolean nautilus_bonobo_get_hidden (BonoboUIComponent *ui, - const char *path); -void nautilus_bonobo_add_numbered_menu_item (BonoboUIComponent *ui, - const char *container_path, - guint index, - const char *label, - GdkPixbuf *pixbuf); -void nautilus_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui, - const char *container_path, - guint index, - const char *label); -void nautilus_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui, - const char *container_path, - guint index, - const char *label, - const char *radio_group_name); -char * nautilus_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui, - const char *container_path, - guint index); -char * nautilus_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui, - const char *container_path, - guint index); +void nautilus_bonobo_set_accelerator (BonoboUIComponent *ui, + const char *path, + const char *accelerator); +char * nautilus_bonobo_get_label (BonoboUIComponent *ui, + const char *path); +void nautilus_bonobo_set_label (BonoboUIComponent *ui, + const char *path, + const char *label); +void nautilus_bonobo_set_tip (BonoboUIComponent *ui, + const char *path, + const char *tip); +void nautilus_bonobo_set_sensitive (BonoboUIComponent *ui, + const char *path, + gboolean sensitive); +void nautilus_bonobo_set_toggle_state (BonoboUIComponent *ui, + const char *path, + gboolean state); +void nautilus_bonobo_set_hidden (BonoboUIComponent *ui, + const char *path, + gboolean hidden); +gboolean nautilus_bonobo_get_hidden (BonoboUIComponent *ui, + const char *path); +void nautilus_bonobo_add_numbered_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + GdkPixbuf *pixbuf); +void nautilus_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label); +void nautilus_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui, + const char *container_path, + guint index, + const char *label, + const char *radio_group_name); +char * nautilus_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui, + const char *container_path, + guint index); +char * nautilus_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui, + const char *container_path, + guint index); + guint nautilus_bonobo_get_numbered_menu_item_index_from_command - (const char *command); +(const char *command); char * nautilus_bonobo_get_numbered_menu_item_container_path_from_command - (const char *command); -void nautilus_bonobo_add_submenu (BonoboUIComponent *ui, - const char *container_path, - const char *label, - GdkPixbuf *pixbuf); -void nautilus_bonobo_add_menu_separator (BonoboUIComponent *ui, - const char *path); -void nautilus_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui, - const char *container_path); -void nautilus_bonobo_set_label_for_toolitem_and_command (BonoboUIComponent *ui, - const char *toolitem_path, - const char *command_path, - const char *label_with_underscore); -void nautilus_bonobo_set_icon (BonoboUIComponent *ui, - const char *path, - const char *icon_relative_path); - -void nautilus_bonobo_register_activation_shortcut (const char *iid, - NautilusBonoboCreateObject create_object_callback, - gpointer callback_data); -void nautilus_bonobo_unregister_activation_shortcut (const char *iid); -NautilusBonoboActivationHandle *nautilus_bonobo_activate_from_id (const char *iid, - NautilusBonoboActivationCallback callback, - gpointer callback_data); -void nautilus_bonobo_activate_cancel (NautilusBonoboActivationHandle *handle); - -Bonobo_RegistrationResult nautilus_bonobo_activation_register_for_display (const char *iid, - Bonobo_Unknown ref); +(const char *command); +void nautilus_bonobo_add_submenu (BonoboUIComponent *ui, + const char *container_path, + const char *label, + GdkPixbuf *pixbuf); +void nautilus_bonobo_add_menu_separator (BonoboUIComponent *ui, + const char *path); +void nautilus_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui, + const char *container_path); +void nautilus_bonobo_set_label_for_toolitem_and_command (BonoboUIComponent *ui, + const char *toolitem_path, + const char *command_path, + const char *label_with_underscore); +void nautilus_bonobo_set_icon (BonoboUIComponent *ui, + const char *path, + const char *icon_relative_path); +void nautilus_bonobo_add_extension_item_command (BonoboUIComponent *ui, + NautilusMenuItem *item); +void nautilus_bonobo_add_extension_item (BonoboUIComponent *ui, + const char *path, + NautilusMenuItem *item); +void nautilus_bonobo_add_extension_toolbar_item (BonoboUIComponent *ui, + const char *path, + NautilusMenuItem *item); +void nautilus_bonobo_register_activation_shortcut (const char *iid, + NautilusBonoboCreateObject create_object_callback, + gpointer callback_data); +void nautilus_bonobo_unregister_activation_shortcut (const char *iid); +NautilusBonoboActivationHandle *nautilus_bonobo_activate_from_id (const char *iid, + NautilusBonoboActivationCallback callback, + gpointer callback_data); +void nautilus_bonobo_activate_cancel (NautilusBonoboActivationHandle *handle); +Bonobo_RegistrationResult nautilus_bonobo_activation_register_for_display (const char *iid, + Bonobo_Unknown ref); + + #endif /* NAUTILUS_BONOBO_EXTENSIONS_H */ diff --git a/libnautilus-private/nautilus-column-chooser.c b/libnautilus-private/nautilus-column-chooser.c new file mode 100644 index 000000000..74f0ee3e3 --- /dev/null +++ b/libnautilus-private/nautilus-column-chooser.c @@ -0,0 +1,652 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-column-chooser.h - A column chooser widget + + Copyright (C) 2004 Novell, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the column COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Dave Camp <dave@ximian.com> +*/ + +#include <config.h> +#include "nautilus-column-chooser.h" + +#include <string.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-macros.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkcellrenderertext.h> +#include <gtk/gtkcellrenderertoggle.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtkhseparator.h> +#include <gtk/gtkscrolledwindow.h> +#include <gtk/gtktreeselection.h> +#include <gtk/gtktreeview.h> +#include <gtk/gtkvbox.h> +#include <libgnome/gnome-i18n.h> + +#include "nautilus-column-utilities.h" + +struct _NautilusColumnChooserDetails +{ + GtkTreeView *view; + GtkListStore *store; + + GtkWidget *move_up_button; + GtkWidget *move_down_button; + GtkWidget *show_button; + GtkWidget *hide_button; + GtkWidget *use_default_button; +}; + +enum { + COLUMN_VISIBLE, + COLUMN_LABEL, + COLUMN_NAME, + NUM_COLUMNS +}; + +enum { + CHANGED, + USE_DEFAULT, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL]; + +static void nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class); +static void nautilus_column_chooser_init (NautilusColumnChooser *chooser); +static void nautilus_column_chooser_destroy (GtkObject *object); +static void nautilus_column_chooser_finalize (GObject *object); + +EEL_CLASS_BOILERPLATE (NautilusColumnChooser, nautilus_column_chooser, GTK_TYPE_HBOX); + +static void +nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class) +{ + G_OBJECT_CLASS (chooser_class)->finalize = nautilus_column_chooser_finalize; + GTK_OBJECT_CLASS (chooser_class)->destroy = nautilus_column_chooser_destroy; + + signals[CHANGED] = g_signal_new + ("changed", + G_TYPE_FROM_CLASS (chooser_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NautilusColumnChooserClass, + changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[USE_DEFAULT] = g_signal_new + ("use_default", + G_TYPE_FROM_CLASS (chooser_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NautilusColumnChooserClass, + use_default), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (chooser_class, sizeof (NautilusColumnChooserDetails)); +} + +static void +update_buttons (NautilusColumnChooser *chooser) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection (chooser->details->view); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + gboolean visible; + gboolean top; + gboolean bottom; + GtkTreePath *first; + GtkTreePath *path; + + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), + &iter, + COLUMN_VISIBLE, &visible, + -1); + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (chooser->details->store), + &iter); + first = gtk_tree_path_new_first (); + + top = (gtk_tree_path_compare (path, first) == 0); + + gtk_tree_path_free (path); + gtk_tree_path_free (first); + + bottom = !gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), + &iter); + + gtk_widget_set_sensitive (chooser->details->move_up_button, + !top); + gtk_widget_set_sensitive (chooser->details->move_down_button, + !bottom); + gtk_widget_set_sensitive (chooser->details->show_button, + !visible); + gtk_widget_set_sensitive (chooser->details->hide_button, + visible); + } else { + gtk_widget_set_sensitive (chooser->details->move_up_button, + FALSE); + gtk_widget_set_sensitive (chooser->details->move_down_button, + FALSE); + gtk_widget_set_sensitive (chooser->details->show_button, + FALSE); + gtk_widget_set_sensitive (chooser->details->hide_button, + FALSE); + } +} + +static void +list_changed (NautilusColumnChooser *chooser) +{ + update_buttons (chooser); + g_signal_emit (chooser, signals[CHANGED], 0); +} + +static void +visible_toggled_callback (GtkCellRendererToggle *cell, + char *path_string, + gpointer user_data) +{ + NautilusColumnChooser *chooser; + GtkTreePath *path; + GtkTreeIter iter; + gboolean visible; + + chooser = NAUTILUS_COLUMN_CHOOSER (user_data); + + path = gtk_tree_path_new_from_string (path_string); + gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), + &iter, path); + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), + &iter, COLUMN_VISIBLE, &visible, -1); + gtk_list_store_set (chooser->details->store, + &iter, COLUMN_VISIBLE, !visible, -1); + gtk_tree_path_free (path); + list_changed (chooser); +} + +static void +selection_changed_callback (GtkTreeSelection *selection, gpointer user_data) +{ + update_buttons (NAUTILUS_COLUMN_CHOOSER (user_data)); +} + +static void +row_deleted_callback (GtkTreeModel *model, + GtkTreePath *path, + gpointer user_data) +{ + list_changed (NAUTILUS_COLUMN_CHOOSER (user_data)); +} + +static void +add_tree_view (NautilusColumnChooser *chooser) +{ + GtkWidget *scrolled; + GtkWidget *view; + GtkListStore *store; + GtkCellRenderer *cell; + GtkTreeSelection *selection; + + view = gtk_tree_view_new (); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); + + store = gtk_list_store_new (NUM_COLUMNS, + G_TYPE_BOOLEAN, + G_TYPE_STRING, + G_TYPE_STRING); + + gtk_tree_view_set_model (GTK_TREE_VIEW (view), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); + g_signal_connect (selection, "changed", + G_CALLBACK (selection_changed_callback), chooser); + + cell = gtk_cell_renderer_toggle_new (); + + g_signal_connect (G_OBJECT (cell), "toggled", + G_CALLBACK (visible_toggled_callback), chooser); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), + -1, NULL, + cell, + "active", COLUMN_VISIBLE, + NULL); + + cell = gtk_cell_renderer_text_new (); + + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), + -1, NULL, + cell, + "text", COLUMN_LABEL, + NULL); + + chooser->details->view = GTK_TREE_VIEW (view); + chooser->details->store = store; + + gtk_widget_show (view); + + scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_widget_show (GTK_WIDGET (scrolled)); + + gtk_container_add (GTK_CONTAINER (scrolled), view); + gtk_box_pack_start (GTK_BOX (chooser), scrolled, TRUE, TRUE, 0); +} + +static void +set_selection_visible (NautilusColumnChooser *chooser, gboolean visible) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (chooser->details->view); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + gtk_list_store_set (chooser->details->store, + &iter, + COLUMN_VISIBLE, visible, + -1); + } + + list_changed (chooser); +} + +static void +move_up_clicked_callback (GtkWidget *button, gpointer user_data) +{ + NautilusColumnChooser *chooser; + GtkTreeIter iter; + GtkTreeSelection *selection; + + chooser = NAUTILUS_COLUMN_CHOOSER (user_data); + + selection = gtk_tree_view_get_selection (chooser->details->view); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + GtkTreePath *path; + GtkTreeIter prev; + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (chooser->details->store), &iter); + gtk_tree_path_prev (path); + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), &prev, path)) { + gtk_list_store_move_before (chooser->details->store, + &iter, + &prev); + } + gtk_tree_path_free (path); + } + + list_changed (chooser); +} + +static void +move_down_clicked_callback (GtkWidget *button, gpointer user_data) +{ + NautilusColumnChooser *chooser; + GtkTreeIter iter; + GtkTreeSelection *selection; + + chooser = NAUTILUS_COLUMN_CHOOSER (user_data); + + selection = gtk_tree_view_get_selection (chooser->details->view); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + GtkTreeIter next; + + next = iter; + + if (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &next)) { + gtk_list_store_move_after (chooser->details->store, + &iter, + &next); + } + } + + list_changed (chooser); +} + +static void +show_clicked_callback (GtkWidget *button, gpointer user_data) +{ + set_selection_visible (NAUTILUS_COLUMN_CHOOSER (user_data), TRUE); +} + +static void +hide_clicked_callback (GtkWidget *button, gpointer user_data) +{ + set_selection_visible (NAUTILUS_COLUMN_CHOOSER (user_data), FALSE); +} + +static void +use_default_clicked_callback (GtkWidget *button, gpointer user_data) +{ + g_signal_emit (NAUTILUS_COLUMN_CHOOSER (user_data), + signals[USE_DEFAULT], 0); +} + +static void +add_buttons (NautilusColumnChooser *chooser) +{ + GtkWidget *box; + GtkWidget *separator; + + box = gtk_vbox_new (FALSE, 8); + gtk_widget_show (box); + + chooser->details->move_up_button = gtk_button_new_with_mnemonic ("Move _Up"); + g_signal_connect (chooser->details->move_up_button, + "clicked", G_CALLBACK (move_up_clicked_callback), + chooser); + gtk_widget_show (chooser->details->move_up_button); + gtk_widget_set_sensitive (chooser->details->move_up_button, FALSE); + gtk_box_pack_start (GTK_BOX (box), chooser->details->move_up_button, + FALSE, FALSE, 0); + + chooser->details->move_down_button = gtk_button_new_with_mnemonic ("Move _Down"); + g_signal_connect (chooser->details->move_down_button, + "clicked", G_CALLBACK (move_down_clicked_callback), + chooser); + gtk_widget_show (chooser->details->move_down_button); + gtk_widget_set_sensitive (chooser->details->move_down_button, FALSE); + gtk_box_pack_start (GTK_BOX (box), chooser->details->move_down_button, + FALSE, FALSE, 0); + + chooser->details->show_button = gtk_button_new_with_mnemonic ("_Show"); + g_signal_connect (chooser->details->show_button, + "clicked", G_CALLBACK (show_clicked_callback), + chooser); + + gtk_widget_set_sensitive (chooser->details->show_button, FALSE); + gtk_widget_show (chooser->details->show_button); + gtk_box_pack_start (GTK_BOX (box), chooser->details->show_button, + FALSE, FALSE, 0); + + chooser->details->hide_button = gtk_button_new_with_mnemonic ("_Hide"); + g_signal_connect (chooser->details->hide_button, + "clicked", G_CALLBACK (hide_clicked_callback), + chooser); + gtk_widget_set_sensitive (chooser->details->hide_button, FALSE); + gtk_widget_show (chooser->details->hide_button); + gtk_box_pack_start (GTK_BOX (box), chooser->details->hide_button, + FALSE, FALSE, 0); + + separator = gtk_hseparator_new (); + gtk_widget_show (separator); + gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, 0); + + chooser->details->use_default_button = gtk_button_new_with_mnemonic ("_Use Default"); + g_signal_connect (chooser->details->use_default_button, + "clicked", G_CALLBACK (use_default_clicked_callback), + chooser); + gtk_widget_show (chooser->details->use_default_button); + gtk_box_pack_start (GTK_BOX (box), chooser->details->use_default_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX (chooser), box, + FALSE, FALSE, 0); +} + +static void +populate_tree (NautilusColumnChooser *chooser) +{ + GList *columns; + GList *l; + + columns = nautilus_get_all_columns (); + + for (l = columns; l != NULL; l = l->next) { + GtkTreeIter iter; + NautilusColumn *column; + char *name; + char *label; + + column = NAUTILUS_COLUMN (l->data); + + g_object_get (G_OBJECT (column), + "name", &name, "label", &label, + NULL); + + gtk_list_store_append (chooser->details->store, &iter); + gtk_list_store_set (chooser->details->store, &iter, + COLUMN_VISIBLE, FALSE, + COLUMN_LABEL, label, + COLUMN_NAME, name, + -1); + + g_free (name); + g_free (label); + } + + nautilus_column_list_free (columns); +} + +static void +nautilus_column_chooser_init (NautilusColumnChooser *chooser) +{ + chooser->details = G_TYPE_INSTANCE_GET_PRIVATE ((chooser), NAUTILUS_TYPE_COLUMN_CHOOSER, NautilusColumnChooserDetails); + + g_object_set (G_OBJECT (chooser), + "homogeneous", FALSE, + "spacing", 8, + NULL); + + add_tree_view (chooser); + add_buttons (chooser); + + populate_tree (chooser); + + g_signal_connect (chooser->details->store, "row_deleted", + G_CALLBACK (row_deleted_callback), chooser); +} + +static void +nautilus_column_chooser_destroy (GtkObject *object) +{ + NautilusColumnChooser *chooser; + + chooser = NAUTILUS_COLUMN_CHOOSER (object); +} + +static void +nautilus_column_chooser_finalize (GObject *object) +{ +} + +static void +set_visible_columns (NautilusColumnChooser *chooser, + GList *visible_columns) +{ + GtkTreeIter iter; + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store), + &iter)) { + do { + char *name; + gboolean visible; + + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), + &iter, + COLUMN_NAME, &name, + -1); + + visible = (eel_g_str_list_index (visible_columns, name) != -1); + + gtk_list_store_set (chooser->details->store, + &iter, + COLUMN_VISIBLE, visible, + -1); + g_free (name); + + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter)); + } +} + +static GList * +get_column_names (NautilusColumnChooser *chooser, gboolean only_visible) +{ + + GList *ret; + GtkTreeIter iter; + + ret = NULL; + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store), + &iter)) { + do { + char *name; + gboolean visible; + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), + &iter, + COLUMN_VISIBLE, &visible, + COLUMN_NAME, &name, + -1); + if (!only_visible || visible) { + /* give ownership to the list */ + ret = g_list_prepend (ret, name); + } + + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), &iter)); + } + + return g_list_reverse (ret); +} + +static gboolean +get_column_iter (NautilusColumnChooser *chooser, + NautilusColumn *column, + GtkTreeIter *iter) +{ + char *column_name; + + g_object_get (NAUTILUS_COLUMN (column), "name", &column_name, NULL); + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->details->store), + iter)) { + do { + char *name; + + + gtk_tree_model_get (GTK_TREE_MODEL (chooser->details->store), + iter, + COLUMN_NAME, &name, + -1); + if (!strcmp (name, column_name)) { + g_free (column_name); + g_free (name); + return TRUE; + } + + g_free (name); + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->details->store), iter)); + } + g_free (column_name); + return FALSE; +} + +static void +set_column_order (NautilusColumnChooser *chooser, + GList *column_order) + +{ + GList *columns; + GList *l; + GtkTreePath *path; + + columns = nautilus_get_all_columns (); + columns = nautilus_sort_columns (columns, column_order); + + g_signal_handlers_block_by_func (chooser->details->store, + G_CALLBACK (row_deleted_callback), + chooser); + + path = gtk_tree_path_new_first (); + for (l = columns; l != NULL; l = l->next) { + GtkTreeIter iter; + + if (get_column_iter (chooser, NAUTILUS_COLUMN (l->data), &iter)) { + GtkTreeIter before; + if (path) { + gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->details->store), + &before, path); + gtk_list_store_move_after (chooser->details->store, + &iter, &before); + gtk_tree_path_next (path); + + } else { + gtk_list_store_move_after (chooser->details->store, + &iter, NULL); + } + } + } + gtk_tree_path_free (path); + g_signal_handlers_unblock_by_func (chooser->details->store, + G_CALLBACK (row_deleted_callback), + chooser); + + nautilus_column_list_free (columns); +} + +void +nautilus_column_chooser_set_settings (NautilusColumnChooser *chooser, + GList *visible_columns, + GList *column_order) +{ + g_return_if_fail (NAUTILUS_IS_COLUMN_CHOOSER (chooser)); + g_return_if_fail (visible_columns != NULL); + g_return_if_fail (column_order != NULL); + + set_visible_columns (chooser, visible_columns); + set_column_order (chooser, column_order); + + list_changed (chooser); +} + +void +nautilus_column_chooser_get_settings (NautilusColumnChooser *chooser, + GList **visible_columns, + GList **column_order) +{ + g_return_if_fail (NAUTILUS_IS_COLUMN_CHOOSER (chooser)); + g_return_if_fail (visible_columns != NULL); + g_return_if_fail (column_order != NULL); + + *visible_columns = get_column_names (chooser, TRUE); + *column_order = get_column_names (chooser, FALSE); +} + +GtkWidget * +nautilus_column_chooser_new (void) +{ + return g_object_new (NAUTILUS_TYPE_COLUMN_CHOOSER, NULL); +} + + + diff --git a/libnautilus-private/nautilus-column-chooser.h b/libnautilus-private/nautilus-column-chooser.h new file mode 100644 index 000000000..677f15280 --- /dev/null +++ b/libnautilus-private/nautilus-column-chooser.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-column-choose.h - A column chooser widget + + Copyright (C) 2004 Novell, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the column COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Dave Camp <dave@ximian.com> +*/ + +#ifndef NAUTILUS_COLUMN_CHOOSER_H +#define NAUTILUS_COLUMN_CHOOSER_H + +#include <gtk/gtkhbox.h> + +#define NAUTILUS_TYPE_COLUMN_CHOOSER (nautilus_column_chooser_get_type ()) +#define NAUTILUS_COLUMN_CHOOSER(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_COLUMN_CHOOSER, NautilusColumnChooser)) +#define NAUTILUS_COLUMN_CHOOSER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_COLUMN_CHOOSER, NautilusColumnChooserClass)) +#define NAUTILUS_IS_COLUMN_CHOOSER(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_COLUMN_CHOOSER)) +#define NAUTILUS_IS_COLUMN_CHOOSER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_COLUMN_CHOOSER)) + +typedef struct _NautilusColumnChooserDetails NautilusColumnChooserDetails; + +typedef struct { + GtkHBox parent; + + NautilusColumnChooserDetails *details; +} NautilusColumnChooser; + +typedef struct { + GtkHBoxClass parent_slot; + + void (*changed) (NautilusColumnChooser *chooser); + void (*use_default) (NautilusColumnChooser *chooser); +} NautilusColumnChooserClass; + +GType nautilus_column_chooser_get_type (void); +GtkWidget *nautilus_column_chooser_new (void); +void nautilus_column_chooser_set_settings (NautilusColumnChooser *chooser, + GList *visible_columns, + GList *column_order); +void nautilus_column_chooser_get_settings (NautilusColumnChooser *chooser, + GList **visible_columns, + GList **column_order); + + +#endif /* NAUTILUS_COLUMN_CHOOSER_H */ diff --git a/libnautilus-private/nautilus-column-utilities.c b/libnautilus-private/nautilus-column-utilities.c new file mode 100644 index 000000000..a233db721 --- /dev/null +++ b/libnautilus-private/nautilus-column-utilities.c @@ -0,0 +1,228 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-column-utilities.h - Utilities related to column specifications + + Copyright (C) 2004 Novell, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the column COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Dave Camp <dave@ximian.com> +*/ + +#include <config.h> +#include "nautilus-column-utilities.h" + +#include <string.h> +#include <eel/eel-glib-extensions.h> +#include <libgnome/gnome-i18n.h> +#include <libnautilus-extension/nautilus-column-provider.h> +#include <libnautilus-private/nautilus-module.h> + +static GList * +get_builtin_columns (void) +{ + GList *columns; + + columns = g_list_append (NULL, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "name", + "attribute", "name", + "label", _("Name"), + "description", _("The name and icon of the file."), + NULL)); + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "size", + "attribute", "size", + "label", _("Size"), + "description", _("The size of the file."), + "xalign", 1.0, + NULL)); + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "type", + "attribute", "type", + "label", _("Type"), + "description", _("The type of the file."), + NULL)); + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "date_modified", + "attribute", "date_modified", + "label", _("Date Modified"), + "description", _("The date the file was modified."), + NULL)); + + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "date_accessed", + "attribute", "date_accessed", + "label", _("Date Accessed"), + "description", _("The date the file was accessed."), + NULL)); + + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "owner", + "attribute", "owner", + "label", _("Owner"), + "description", _("The owner of the file."), + NULL)); + + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "group", + "attribute", "group", + "label", _("Group"), + "description", _("The group of the file."), + NULL)); + + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "permissions", + "attribute", "permissions", + "label", _("Permissions"), + "description", _("The permissions of the file."), + NULL)); + + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "octal_permissions", + "attribute", "octal_permissions", + "label", _("Octal Permissions"), + "description", _("The permissions of the file, in octal notation."), + NULL)); + + columns = g_list_append (columns, + g_object_new (NAUTILUS_TYPE_COLUMN, + "name", "mime_type", + "attribute", "mime_type", + "label", _("MIME Type"), + "description", _("The mime type of the file."), + NULL)); + return columns; +} + +static GList * +get_extension_columns (void) +{ + GList *columns; + GList *providers; + GList *l; + + providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_COLUMN_PROVIDER); + + columns = NULL; + + for (l = providers; l != NULL; l = l->next) { + NautilusColumnProvider *provider; + GList *provider_columns; + + provider = NAUTILUS_COLUMN_PROVIDER (l->data); + provider_columns = nautilus_column_provider_get_columns (provider); + columns = g_list_concat (columns, provider_columns); + } + + nautilus_module_extension_list_free (providers); + + return columns; +} + +GList * +nautilus_get_all_columns (void) +{ + static GList *columns = NULL; + + if (!columns) { + columns = g_list_concat (get_builtin_columns (), + get_extension_columns ()); + } + + return nautilus_column_list_copy (columns); +} + +GList * +nautilus_column_list_copy (GList *columns) +{ + GList *ret; + GList *l; + + ret = g_list_copy (columns); + + for (l = ret; l != NULL; l = l->next) { + g_object_ref (l->data); + } + + return ret; +} + +void +nautilus_column_list_free (GList *columns) +{ + GList *l; + + for (l = columns; l != NULL; l = l->next) { + g_object_unref (l->data); + } + + g_list_free (columns); +} + +static int +column_compare (NautilusColumn *a, NautilusColumn *b, GList *column_order) +{ + int index_a; + int index_b; + char *name; + + g_object_get (G_OBJECT (a), "name", &name, NULL); + index_a = eel_g_str_list_index (column_order, name); + g_free (name); + + g_object_get (G_OBJECT (b), "name", &name, NULL); + index_b = eel_g_str_list_index (column_order, name); + g_free (name); + + if (index_a == index_b) { + int ret; + char *label_a; + char *label_b; + + g_object_get (G_OBJECT (a), "label", &label_a, NULL); + g_object_get (G_OBJECT (b), "label", &label_b, NULL); + ret = strcmp (label_a, label_b); + g_free (a); + g_free (b); + + return ret; + } else if (index_a == -1) { + return 1; + } else if (index_b == -1) { + return -1; + } else { + return index_a - index_b; + } +} + +GList * +nautilus_sort_columns (GList *columns, + GList *column_order) +{ + return g_list_sort_with_data (columns, + (GCompareDataFunc)column_compare, + column_order); +} + diff --git a/libnautilus-private/nautilus-column-utilities.h b/libnautilus-private/nautilus-column-utilities.h new file mode 100644 index 000000000..48611db6c --- /dev/null +++ b/libnautilus-private/nautilus-column-utilities.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-column-utilities.h - Utilities related to column specifications + + Copyright (C) 2004 Novell, Inc. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the column COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Dave Camp <dave@ximian.com> +*/ + +#ifndef NAUTILUS_COLUMN_UTILITIES_H +#define NAUTILUS_COLUMN_UTILITIES_H + +#include <libnautilus-extension/nautilus-column.h> + +GList *nautilus_get_all_columns (void); +GList *nautilus_column_list_copy (GList *columns); +void nautilus_column_list_free (GList *columns); + +GList *nautilus_sort_columns (GList *columns, + GList *column_order); + + +#endif /* NAUTILUS_COLUMN_UTILITIES_H */ diff --git a/libnautilus-private/nautilus-directory-async.c b/libnautilus-private/nautilus-directory-async.c index 343dd4db3..ab6394dd7 100644 --- a/libnautilus-private/nautilus-directory-async.c +++ b/libnautilus-private/nautilus-directory-async.c @@ -32,6 +32,7 @@ #include "nautilus-file-utilities.h" #include "nautilus-global-preferences.h" #include "nautilus-link.h" +#include "nautilus-marshal.h" #include "nautilus-metafile.h" #include "nautilus-search-uri.h" #include <eel/eel-glib-extensions.h> @@ -94,6 +95,13 @@ typedef struct { Request request; } Monitor; +typedef struct { + NautilusDirectory *directory; + NautilusInfoProvider *provider; + NautilusOperationHandle *handle; + NautilusOperationResult result; +} InfoProviderResponse; + typedef gboolean (* RequestCheck) (const Request *); typedef gboolean (* FileCheck) (NautilusFile *); @@ -127,8 +135,12 @@ static gboolean file_needs_high_priority_work_done (NautilusDirectory *directory NautilusFile *file); static gboolean file_needs_low_priority_work_done (NautilusDirectory *directory, NautilusFile *file); +static gboolean file_needs_extension_work_done (NautilusDirectory *directory, + NautilusFile *file); static void move_file_to_low_priority_queue (NautilusDirectory *directory, NautilusFile *file); +static void move_file_to_extension_queue (NautilusDirectory *directory, + NautilusFile *file); void @@ -571,6 +583,8 @@ nautilus_directory_set_up_request (Request *request, request->metafile |= (file_attributes & NAUTILUS_FILE_ATTRIBUTE_METADATA) != FALSE; + + request->extension_info = (file_attributes & NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO) != FALSE; } static void @@ -1748,6 +1762,17 @@ wants_link_info (const Request *request) return request->link_info; } +static gboolean +lacks_extension_info (NautilusFile *file) +{ + return file->details->pending_info_providers != NULL; +} + +static gboolean +wants_extension_info (const Request *request) +{ + return request->extension_info; +} static gboolean has_problem (NautilusDirectory *directory, NautilusFile *file, FileCheck problem) @@ -3136,6 +3161,153 @@ link_info_start (NautilusDirectory *directory, } static void +extension_info_cancel (NautilusDirectory *directory) +{ + if (directory->details->extension_info_in_progress != NULL) { + nautilus_info_provider_cancel_update + (directory->details->extension_info_provider, + directory->details->extension_info_in_progress); + + directory->details->extension_info_in_progress = NULL; + directory->details->extension_info_file = NULL; + directory->details->extension_info_provider = NULL; + + async_job_end (directory, "extension info"); + } +} + +static void +extension_info_stop (NautilusDirectory *directory) +{ + if (directory->details->extension_info_in_progress != NULL) { + NautilusFile *file; + + file = directory->details->extension_info_file; + if (file != NULL) { + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (file->details->directory == directory); + if (is_needy (file, lacks_extension_info, wants_extension_info)) { + return; + } + } + + /* The info is not wanted, so stop it. */ + extension_info_cancel (directory); + } +} + +static void +finish_info_provider (NautilusDirectory *directory, + NautilusFile *file, + NautilusInfoProvider *provider) +{ + file->details->pending_info_providers = + g_list_remove (file->details->pending_info_providers, + provider); + g_object_unref (provider); + + nautilus_directory_async_state_changed (directory); + + if (file->details->pending_info_providers == NULL) { + nautilus_file_info_providers_done (file); + } +} + + +static gboolean +info_provider_idle_callback (gpointer user_data) +{ + InfoProviderResponse *response; + NautilusDirectory *directory; + + response = user_data; + directory = response->directory; + + if (response->handle != directory->details->extension_info_in_progress + || response->provider != directory->details->extension_info_provider) { + g_warning ("Unexpected plugin response. This probably indicates a bug in a Nautilus extension: handle=%p", response->handle); + } else { + NautilusFile *file; + async_job_end (directory, "extension info"); + + file = directory->details->extension_info_file; + + directory->details->extension_info_file = NULL; + directory->details->extension_info_provider = NULL; + directory->details->extension_info_in_progress = NULL; + + finish_info_provider (directory, file, response->provider); + } + + return FALSE; +} + +static void +info_provider_callback (NautilusInfoProvider *provider, + NautilusOperationHandle *handle, + NautilusOperationResult result, + gpointer user_data) +{ + InfoProviderResponse *response; + + response = g_new0 (InfoProviderResponse, 1); + response->provider = provider; + response->handle = handle; + response->result = result; + response->directory = NAUTILUS_DIRECTORY (user_data); + + g_idle_add (info_provider_idle_callback, response); +} + +static void +extension_info_start (NautilusDirectory *directory, + NautilusFile *file) +{ + NautilusInfoProvider *provider; + NautilusOperationResult result; + NautilusOperationHandle *handle; + GClosure *update_complete; + + if (directory->details->extension_info_in_progress != NULL) { + return; + } + + if (!is_needy (file, lacks_extension_info, wants_extension_info)) { + return; + } + + if (!async_job_start (directory, "extension info")) { + return; + } + + provider = file->details->pending_info_providers->data; + + update_complete = g_cclosure_new (G_CALLBACK (info_provider_callback), + directory, + NULL); + g_closure_set_marshal (update_complete, + nautilus_marshal_VOID__POINTER_ENUM); + + result = nautilus_info_provider_update_file_info + (provider, + NAUTILUS_FILE_INFO (file), + update_complete, + &handle); + + g_closure_unref (update_complete); + + if (result == NAUTILUS_OPERATION_COMPLETE || + result == NAUTILUS_OPERATION_FAILED) { + finish_info_provider (directory, file, provider); + async_job_end (directory, "extension info"); + } else { + directory->details->extension_info_in_progress = handle; + directory->details->extension_info_provider = provider; + directory->details->extension_info_file = file; + } +} + +static void start_or_stop_io (NautilusDirectory *directory) { NautilusFile *file; @@ -3150,6 +3322,7 @@ start_or_stop_io (NautilusDirectory *directory) mime_list_stop (directory); top_left_stop (directory); link_info_stop (directory); + extension_info_stop (directory); /* Take files that are all done off the queue. */ while (!nautilus_file_queue_is_empty (directory->details->high_priority_queue)) { @@ -3177,6 +3350,20 @@ start_or_stop_io (NautilusDirectory *directory) top_left_start (directory, file); return; } else { + move_file_to_extension_queue (directory, file); + + } + } + + /* Low priority queue must be empty */ + while (!nautilus_file_queue_is_empty (directory->details->extension_queue)) { + file = nautilus_file_queue_head (directory->details->extension_queue); + + if (file_needs_extension_work_done (directory, file)) { + /* Start getting attributes if possible */ + extension_info_start (directory, file); + return; + } else { nautilus_directory_remove_file_from_work_queue (directory, file); } @@ -3228,6 +3415,7 @@ nautilus_directory_cancel (NautilusDirectory *directory) link_info_cancel (directory); mime_list_cancel (directory); top_left_cancel (directory); + extension_info_cancel (directory); /* We aren't waiting for anything any more. */ if (waiting_directories != NULL) { @@ -3322,6 +3510,10 @@ cancel_loading_attributes (NautilusDirectory *directory, if (request.link_info) { link_info_cancel (directory); } + + if (request.extension_info) { + extension_info_cancel (directory); + } /* FIXME bugzilla.gnome.org 45064: implement cancelling metadata when we implement invalidating metadata */ @@ -3407,11 +3599,23 @@ file_needs_low_priority_work_done (NautilusDirectory *directory, } static gboolean +file_needs_extension_work_done (NautilusDirectory *directory, + NautilusFile *file) +{ + if (is_needy (file, lacks_extension_info, wants_extension_info)) { + return TRUE; + } + + return FALSE; +} + +static gboolean file_needs_work_done (NautilusDirectory *directory, NautilusFile *file) { return (file_needs_high_priority_work_done (directory, file) || - file_needs_low_priority_work_done (directory, file)); + file_needs_low_priority_work_done (directory, file) || + file_needs_extension_work_done (directory, file)); } @@ -3451,6 +3655,8 @@ nautilus_directory_remove_file_from_work_queue (NautilusDirectory *directory, file); nautilus_file_queue_remove (directory->details->low_priority_queue, file); + nautilus_file_queue_remove (directory->details->extension_queue, + file); } @@ -3458,15 +3664,32 @@ static void move_file_to_low_priority_queue (NautilusDirectory *directory, NautilusFile *file) { + /* Must add before removing to avoid ref underflow */ + nautilus_file_queue_enqueue (directory->details->low_priority_queue, + file); + nautilus_file_queue_remove (directory->details->high_priority_queue, + file); + if (!file_needs_low_priority_work_done (directory, file)) { - nautilus_file_queue_remove (directory->details->high_priority_queue, + move_file_to_extension_queue (directory, file); + + return; + } +} + +static void +move_file_to_extension_queue (NautilusDirectory *directory, + NautilusFile *file) +{ + if (!file_needs_extension_work_done (directory, file)) { + nautilus_file_queue_remove (directory->details->low_priority_queue, file); return; } /* Must add before removing to avoid ref underflow */ - nautilus_file_queue_enqueue (directory->details->low_priority_queue, + nautilus_file_queue_enqueue (directory->details->extension_queue, file); - nautilus_file_queue_remove (directory->details->high_priority_queue, + nautilus_file_queue_remove (directory->details->low_priority_queue, file); } diff --git a/libnautilus-private/nautilus-directory-private.h b/libnautilus-private/nautilus-directory-private.h index fc4cd5d72..9dc3bae98 100644 --- a/libnautilus-private/nautilus-directory-private.h +++ b/libnautilus-private/nautilus-directory-private.h @@ -33,6 +33,7 @@ #include <libnautilus-private/nautilus-metafile-server.h> #include <libnautilus-private/nautilus-monitor.h> #include <libnautilus/nautilus-idle-queue.h> +#include <libnautilus-extension/nautilus-info-provider.h> #include <libxml/tree.h> typedef struct LinkInfoReadState LinkInfoReadState; @@ -53,6 +54,7 @@ struct NautilusDirectoryDetails /* Queues of files needing some I/O done. */ NautilusFileQueue *high_priority_queue; NautilusFileQueue *low_priority_queue; + NautilusFileQueue *extension_queue; /* These lists are going to be pretty short. If we think they * are going to get big, we can use hash tables instead. @@ -100,6 +102,10 @@ struct NautilusDirectoryDetails NautilusFile *get_info_file; GnomeVFSAsyncHandle *get_info_in_progress; + NautilusFile *extension_info_file; + NautilusInfoProvider *extension_info_provider; + NautilusOperationHandle *extension_info_in_progress; + TopLeftTextReadState *top_left_read_state; LinkInfoReadState *link_info_read_state; @@ -119,6 +125,7 @@ typedef struct { gboolean metafile; gboolean mime_list; gboolean top_left_text; + gboolean extension_info; } Request; NautilusDirectory *nautilus_directory_get_existing (const char *uri); diff --git a/libnautilus-private/nautilus-directory.c b/libnautilus-private/nautilus-directory.c index 0ee12c3ac..9a8e5913f 100644 --- a/libnautilus-private/nautilus-directory.c +++ b/libnautilus-private/nautilus-directory.c @@ -135,6 +135,7 @@ nautilus_directory_init (gpointer object, gpointer klass) directory->details->file_hash = g_hash_table_new (g_str_hash, g_str_equal); directory->details->high_priority_queue = nautilus_file_queue_new (); directory->details->low_priority_queue = nautilus_file_queue_new (); + directory->details->extension_queue = nautilus_file_queue_new (); directory->details->idle_queue = nautilus_idle_queue_new (); directory->details->hidden_file_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -209,6 +210,7 @@ nautilus_directory_finalize (GObject *object) nautilus_file_queue_destroy (directory->details->high_priority_queue); nautilus_file_queue_destroy (directory->details->low_priority_queue); + nautilus_file_queue_destroy (directory->details->extension_queue); nautilus_idle_queue_destroy (directory->details->idle_queue); g_assert (directory->details->directory_load_in_progress == NULL); g_assert (directory->details->count_in_progress == NULL); @@ -1023,6 +1025,7 @@ nautilus_directory_notify_files_changed (GList *uris) file->details->file_info_is_up_to_date = FALSE; file->details->top_left_text_is_up_to_date = FALSE; file->details->link_info_is_up_to_date = FALSE; + nautilus_file_invalidate_extension_info_internal (file); hash_table_list_prepend (changed_lists, file->details->directory, diff --git a/libnautilus-private/nautilus-file-attributes.h b/libnautilus-private/nautilus-file-attributes.h index 38e1da94f..ba02bd426 100644 --- a/libnautilus-private/nautilus-file-attributes.h +++ b/libnautilus-private/nautilus-file-attributes.h @@ -43,6 +43,7 @@ typedef enum { NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT = 1 << 10, NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME = 1 << 11, NAUTILUS_FILE_ATTRIBUTE_VOLUMES = 1 << 12, + NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO = 1 << 13, } NautilusFileAttributes; #endif /* NAUTILUS_FILE_ATTRIBUTES_H */ diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h index 36f94e5e6..9f3b1da37 100644 --- a/libnautilus-private/nautilus-file-private.h +++ b/libnautilus-private/nautilus-file-private.h @@ -93,7 +93,18 @@ struct NautilusFileDetails /* We use this to cache automatic emblems and emblem keywords to speed up compare_by_emblems. */ NautilusFileSortByEmblemCache *compare_by_emblem_cache; - + + /* NautilusInfoProviders that need to be run for this file */ + GList *pending_info_providers; + + /* Emblems provided by extensions */ + GList *extension_emblems; + GList *pending_extension_emblems; + + /* Attributes provided by extensions */ + GHashTable *extension_attributes; + GHashTable *pending_extension_attributes; + /* boolean fields: bitfield to save space, since there can be many NautilusFile objects. */ @@ -173,13 +184,15 @@ gboolean nautilus_file_should_get_top_left_text (NautilusFile /* Mark specified attributes for this file out of date without canceling current * I/O or kicking off new I/O. */ -void nautilus_file_invalidate_attributes_internal (NautilusFile *file, - NautilusFileAttributes file_attributes); -NautilusFileAttributes nautilus_file_get_all_attributes (void); -gboolean nautilus_file_is_self_owned (NautilusFile *file); -void nautilus_file_invalidate_count_and_mime_list (NautilusFile *file); -gboolean nautilus_file_rename_in_progress (NautilusFile *file); -GnomeVFSFileInfo * nautilus_file_peek_vfs_file_info (NautilusFile *file); +void nautilus_file_invalidate_attributes_internal (NautilusFile *file, + NautilusFileAttributes file_attributes); +NautilusFileAttributes nautilus_file_get_all_attributes (void); +gboolean nautilus_file_is_self_owned (NautilusFile *file); +void nautilus_file_invalidate_count_and_mime_list (NautilusFile *file); +gboolean nautilus_file_rename_in_progress (NautilusFile *file); +GnomeVFSFileInfo * nautilus_file_peek_vfs_file_info (NautilusFile *file); +void nautilus_file_invalidate_extension_info_internal (NautilusFile *file); +void nautilus_file_info_providers_done (NautilusFile *file); /* Thumbnailing: */ diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c index dc6141723..1ea79d4c0 100644 --- a/libnautilus-private/nautilus-file.c +++ b/libnautilus-private/nautilus-file.c @@ -39,6 +39,7 @@ #include "nautilus-link.h" #include "nautilus-link-desktop-file.h" #include "nautilus-metadata.h" +#include "nautilus-module.h" #include "nautilus-thumbnails.h" #include "nautilus-trash-directory.h" #include "nautilus-trash-file.h" @@ -59,6 +60,7 @@ #include <libgnomevfs/gnome-vfs-volume.h> #include <libgnomevfs/gnome-vfs-volume-monitor.h> #include <libgnomevfs/gnome-vfs-drive.h> +#include <libnautilus-extension/nautilus-file-info.h> #include <libxml/parser.h> #include <pwd.h> #include <stdlib.h> @@ -110,24 +112,62 @@ enum { static guint signals[LAST_SIGNAL]; -static GHashTable *symbolic_links; - -static char * nautilus_file_get_owner_as_string (NautilusFile *file, - gboolean include_real_name); -static char * nautilus_file_get_type_as_string (NautilusFile *file); -static gboolean update_info_and_name (NautilusFile *file, - GnomeVFSFileInfo *info); -static char * nautilus_file_get_display_name_nocopy (NautilusFile *file); -static char * nautilus_file_get_display_name_collation_key (NautilusFile *file); +static GObjectClass *parent_class = NULL; +static GHashTable *symbolic_links; -GNOME_CLASS_BOILERPLATE (NautilusFile, nautilus_file, - GObject, G_TYPE_OBJECT) +static void nautilus_file_instance_init (NautilusFile *file); +static void nautilus_file_class_init (NautilusFileClass *class); +static void nautilus_file_info_iface_init (NautilusFileInfoIface *iface); +static char * nautilus_file_get_owner_as_string (NautilusFile *file, + gboolean include_real_name); +static char * nautilus_file_get_type_as_string (NautilusFile *file); +static gboolean update_info_and_name (NautilusFile *file, + GnomeVFSFileInfo *info); +static char * nautilus_file_get_display_name_nocopy (NautilusFile *file); +static char * nautilus_file_get_display_name_collation_key (NautilusFile *file); + +GType +nautilus_file_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusFileClass), + NULL, + NULL, + (GClassInitFunc) nautilus_file_class_init, + NULL, + NULL, + sizeof (NautilusFile), + 0, + (GInstanceInitFunc) nautilus_file_instance_init, + }; + + static const GInterfaceInfo file_info_iface_info = { + (GInterfaceInitFunc) nautilus_file_info_iface_init, + NULL, + NULL + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "NautilusFile", + &info, 0); + g_type_add_interface_static (type, + NAUTILUS_TYPE_FILE_INFO, + &file_info_iface_info); + } + + return type; +} static void nautilus_file_instance_init (NautilusFile *file) { file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NAUTILUS_TYPE_FILE, NautilusFileDetails); + + nautilus_file_invalidate_extension_info_internal (file); } static NautilusFile * @@ -459,10 +499,20 @@ finalize (GObject *object) eel_g_list_free_deep (file->details->mime_list); + eel_g_list_free_deep (file->details->pending_extension_emblems); + eel_g_list_free_deep (file->details->extension_emblems); + + if (file->details->pending_extension_attributes) { + g_hash_table_destroy (file->details->pending_extension_attributes); + } + + if (file->details->extension_attributes) { + g_hash_table_destroy (file->details->extension_attributes); + } + G_OBJECT_CLASS (parent_class)->finalize (object); } - NautilusFile * nautilus_file_ref (NautilusFile *file) { @@ -2040,16 +2090,27 @@ compare_by_full_path (NautilusFile *file_1, NautilusFile *file_2) static int nautilus_file_compare_for_sort_internal (NautilusFile *file_1, NautilusFile *file_2, - NautilusFileSortType sort_type) + gboolean directories_first) { int compare; GnomeVFSDrive *drive1, *drive2; GnomeVFSVolume *volume1, *volume2; - if (file_1 == file_2) { - return 0; + gboolean is_directory_1, is_directory_2; + + if (directories_first) { + is_directory_1 = nautilus_file_is_directory (file_1); + is_directory_2 = nautilus_file_is_directory (file_2); + + if (is_directory_1 && !is_directory_2) { + return -1; + } + + if (is_directory_2 && !is_directory_1) { + return +1; + } } - + /* Always sort drives/volumes separately: */ if (file_1->details->has_drive != file_2->details->has_drive) { if (file_1->details->has_drive) { @@ -2082,53 +2143,8 @@ nautilus_file_compare_for_sort_internal (NautilusFile *file_1, return compare; } } - - switch (sort_type) { - case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME: - compare = compare_by_display_name (file_1, file_2); - if (compare != 0) { - return compare; - } - return compare_by_directory_name (file_1, file_2); - case NAUTILUS_FILE_SORT_BY_DIRECTORY: - return compare_by_full_path (file_1, file_2); - case NAUTILUS_FILE_SORT_BY_SIZE: - /* Compare directory sizes ourselves, then if necessary - * use GnomeVFS to compare file sizes. - */ - compare = compare_by_size (file_1, file_2); - if (compare != 0) { - return compare; - } - return compare_by_full_path (file_1, file_2); - case NAUTILUS_FILE_SORT_BY_TYPE: - /* GnomeVFS doesn't know about our special text for certain - * mime types, so we handle the mime-type sorting ourselves. - */ - compare = compare_by_type (file_1, file_2); - if (compare != 0) { - return compare; - } - return compare_by_full_path (file_1, file_2); - case NAUTILUS_FILE_SORT_BY_MTIME: - compare = compare_by_modification_time (file_1, file_2); - if (compare != 0) { - return compare; - } - return compare_by_full_path (file_1, file_2); - case NAUTILUS_FILE_SORT_BY_EMBLEMS: - /* GnomeVFS doesn't know squat about our emblems, so - * we handle comparing them here, before falling back - * to tie-breakers. - */ - compare = compare_by_emblems (file_1, file_2); - if (compare != 0) { - return compare; - } - return compare_by_full_path (file_1, file_2); - default: - g_return_val_if_reached (0); - } + + return 0; } /** @@ -2154,27 +2170,135 @@ nautilus_file_compare_for_sort (NautilusFile *file_1, gboolean reversed) { int result; - gboolean is_directory_1, is_directory_2; - if (directories_first) { - is_directory_1 = nautilus_file_is_directory (file_1); - is_directory_2 = nautilus_file_is_directory (file_2); - - if (is_directory_1 && !is_directory_2) { - return -1; + if (file_1 == file_2) { + return 0; + } + + result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first); + + if (result == 0) { + switch (sort_type) { + case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME: + result = compare_by_display_name (file_1, file_2); + if (result == 0) { + result = compare_by_directory_name (file_1, file_2); + } + break; + case NAUTILUS_FILE_SORT_BY_DIRECTORY: + result = compare_by_full_path (file_1, file_2); + break; + case NAUTILUS_FILE_SORT_BY_SIZE: + /* Compare directory sizes ourselves, then if necessary + * use GnomeVFS to compare file sizes. + */ + result = compare_by_size (file_1, file_2); + if (result == 0) { + result = compare_by_full_path (file_1, file_2); + } + break; + case NAUTILUS_FILE_SORT_BY_TYPE: + /* GnomeVFS doesn't know about our special text for certain + * mime types, so we handle the mime-type sorting ourselves. + */ + result = compare_by_type (file_1, file_2); + if (result == 0) { + result = compare_by_full_path (file_1, file_2); + } + break; + case NAUTILUS_FILE_SORT_BY_MTIME: + result = compare_by_modification_time (file_1, file_2); + if (result == 0) { + result = compare_by_full_path (file_1, file_2); + } + break; + case NAUTILUS_FILE_SORT_BY_EMBLEMS: + /* GnomeVFS doesn't know squat about our emblems, so + * we handle comparing them here, before falling back + * to tie-breakers. + */ + result = compare_by_emblems (file_1, file_2); + if (result == 0) { + result = compare_by_full_path (file_1, file_2); + } + default: + g_return_val_if_reached (0); } + } - if (is_directory_2 && !is_directory_1) { - return +1; - } + if (reversed) { + result = -result; } - result = nautilus_file_compare_for_sort_internal (file_1, file_2, sort_type); + return result; +} + +int +nautilus_file_compare_for_sort_by_attribute (NautilusFile *file_1, + NautilusFile *file_2, + const char *attribute, + gboolean directories_first, + gboolean reversed) +{ + int result; + + if (file_1 == file_2) { + return 0; + } + + /* Convert certain attributes into NautilusFileSortTypes and use + * nautilus_file_compare_for_sort() + */ + if (attribute == NULL || !strcmp (attribute, "name")) { + return nautilus_file_compare_for_sort (file_1, file_2, + NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, + directories_first, + reversed); + } else if (!strcmp (attribute, "size")) { + return nautilus_file_compare_for_sort (file_1, file_2, + NAUTILUS_FILE_SORT_BY_SIZE, + directories_first, + reversed); + } else if (!strcmp (attribute, "type")) { + return nautilus_file_compare_for_sort (file_1, file_2, + NAUTILUS_FILE_SORT_BY_TYPE, + directories_first, + reversed); + } else if (!strcmp (attribute, "modification_date") || !strcmp (attribute, "date_modified")) { + return nautilus_file_compare_for_sort (file_1, file_2, + NAUTILUS_FILE_SORT_BY_MTIME, + directories_first, + reversed); + } else if (!strcmp (attribute, "emblems")) { + return nautilus_file_compare_for_sort (file_1, file_2, + NAUTILUS_FILE_SORT_BY_EMBLEMS, + directories_first, + reversed); + } + + /* it is a normal attribute, compare by strings */ + + result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first); + + if (result == 0) { + char *value_1; + char *value_2; + + value_1 = nautilus_file_get_string_attribute (file_1, + attribute); + value_2 = nautilus_file_get_string_attribute (file_2, + attribute); + + result = strcmp (value_1, value_2); + + g_free (value_1); + g_free (value_2); + } if (reversed) { result = -result; } - + return result; } @@ -4318,6 +4442,8 @@ nautilus_file_get_deep_directory_count_as_string (NautilusFile *file) char * nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name) { + char *extension_attribute; + /* FIXME bugzilla.gnome.org 40646: * Use hash table and switch statement or function pointers for speed? */ @@ -4389,7 +4515,18 @@ nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_na if (strcmp (attribute_name, "free_space") == 0) { return nautilus_file_get_volume_free_space (file); } - return NULL; + + extension_attribute = NULL; + + if (file->details->pending_extension_attributes) { + extension_attribute = g_hash_table_lookup (file->details->pending_extension_attributes, attribute_name); + } + + if (extension_attribute == NULL && file->details->extension_attributes) { + extension_attribute = g_hash_table_lookup (file->details->extension_attributes, attribute_name); + } + + return g_strdup (extension_attribute); } /** @@ -4689,7 +4826,10 @@ nautilus_file_get_keywords (NautilusFile *file) /* Put all the keywords into a list. */ keywords = nautilus_file_get_metadata_list (file, "keyword", "name"); - + + keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->extension_emblems)); + keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->pending_extension_emblems)); + return sort_keyword_list_and_remove_duplicates (keywords); } @@ -5274,7 +5414,6 @@ invalidate_directory_count (NautilusFile *file) file->details->directory_count_is_up_to_date = FALSE; } - static void invalidate_deep_counts (NautilusFile *file) { @@ -5306,6 +5445,19 @@ invalidate_link_info (NautilusFile *file) } void +nautilus_file_invalidate_extension_info_internal (NautilusFile *file) +{ + file->details->pending_info_providers = + nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_INFO_PROVIDER); + if (!file->details->pending_extension_attributes) { + file->details->pending_extension_attributes = + g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)g_free); + } +} + +void nautilus_file_invalidate_attributes_internal (NautilusFile *file, NautilusFileAttributes file_attributes) { @@ -5343,6 +5495,9 @@ nautilus_file_invalidate_attributes_internal (NautilusFile *file, if (request.link_info) { invalidate_link_info (file); } + if (request.extension_info) { + nautilus_file_invalidate_extension_info_internal (file); + } /* FIXME bugzilla.gnome.org 45075: implement invalidating metadata */ } @@ -5633,6 +5788,8 @@ nautilus_extract_top_left_text (const char *text, static void nautilus_file_class_init (NautilusFileClass *class) { + parent_class = g_type_class_peek_parent (class); + G_OBJECT_CLASS (class)->finalize = finalize; signals[CHANGED] = @@ -5656,6 +5813,79 @@ nautilus_file_class_init (NautilusFileClass *class) g_type_class_add_private (class, sizeof (NautilusFileDetails)); } +static GnomeVFSFileInfo * +nautilus_file_get_vfs_file_info (NautilusFile *file) +{ + return gnome_vfs_file_info_dup (file->details->info); +} + +static void +nautilus_file_add_emblem (NautilusFile *file, + const char *emblem_name) +{ + if (file->details->pending_info_providers) { + file->details->pending_extension_emblems = g_list_prepend (file->details->pending_extension_emblems, + g_strdup (emblem_name)); + } else { + file->details->extension_emblems = g_list_prepend (file->details->extension_emblems, + g_strdup (emblem_name)); + } + + nautilus_file_changed (file); +} + +static void +nautilus_file_add_string_attribute (NautilusFile *file, + const char *attribute_name, + const char *value) +{ + if (file->details->pending_info_providers) { + g_hash_table_insert (file->details->pending_extension_attributes, + g_strdup (attribute_name), + g_strdup (value)); + } else { + g_hash_table_insert (file->details->extension_attributes, + g_strdup (attribute_name), + g_strdup (value)); + } + + nautilus_file_changed (file); +} + +void +nautilus_file_info_providers_done (NautilusFile *file) +{ + eel_g_list_free_deep (file->details->extension_emblems); + file->details->extension_emblems = file->details->pending_extension_emblems; + file->details->pending_extension_emblems = NULL; + + if (file->details->extension_attributes) { + g_hash_table_destroy (file->details->extension_attributes); + } + + file->details->extension_attributes = file->details->pending_extension_attributes; + file->details->pending_extension_attributes = NULL; + + nautilus_file_changed (file); +} + +static void +nautilus_file_info_iface_init (NautilusFileInfoIface *iface) +{ + iface->is_gone = nautilus_file_is_gone; + iface->get_name = nautilus_file_get_name; + iface->get_uri = nautilus_file_get_uri; + iface->get_parent_uri = nautilus_file_get_parent_uri; + iface->get_uri_scheme = nautilus_file_get_uri_scheme; + iface->get_mime_type = nautilus_file_get_mime_type; + iface->is_mime_type = nautilus_file_is_mime_type; + iface->is_directory = nautilus_file_is_directory; + iface->get_vfs_file_info = nautilus_file_get_vfs_file_info; + iface->add_emblem = nautilus_file_add_emblem; + iface->get_string_attribute = nautilus_file_get_string_attribute; + iface->add_string_attribute = nautilus_file_add_string_attribute; +} + #if !defined (NAUTILUS_OMIT_SELF_CHECK) void diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h index 22971972e..c945fd391 100644 --- a/libnautilus-private/nautilus-file.h +++ b/libnautilus-private/nautilus-file.h @@ -286,6 +286,11 @@ int nautilus_file_compare_for_sort (Nautilu NautilusFileSortType sort_type, gboolean directories_first, gboolean reversed); +int nautilus_file_compare_for_sort_by_attribute (NautilusFile *file_1, + NautilusFile *file_2, + const char *attribute, + gboolean directories_first, + gboolean reversed); int nautilus_file_compare_display_name (NautilusFile *file_1, const char *pattern); diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c index 29fb25dc4..1342ce774 100644 --- a/libnautilus-private/nautilus-global-preferences.c +++ b/libnautilus-private/nautilus-global-preferences.c @@ -213,21 +213,6 @@ static EelEnumerationEntry standard_font_size_entries[] = { { NULL } }; -static EelEnumerationEntry icon_captions_enum_entries[] = { - { "size", N_("size"), 0 }, - { "type", N_("type"), 1 }, - { "date_modified", N_("date modified"), 2 }, - { "date_changed", N_("date changed"), 3 }, - { "date_accessed", N_("date accessed"), 4 }, - { "owner", N_("owner"), 5 }, - { "group", N_("group"), 6 }, - { "permissions", N_("permissions"), 7 }, - { "octal_permissions", N_("octal permissions"), 8 }, - { "mime_type", N_("MIME type"), 9 }, - { "none", N_("none"), 10 }, - { NULL } -}; - /* These enumerations are used in the preferences dialog to * populate widgets and route preferences changes between the * storage (GConf) and the displayed values. @@ -240,7 +225,6 @@ static EelEnumerationInfo enumerations[] = { { "default_zoom_level", default_zoom_level_enum_entries }, { "executable_text_activation", executable_text_activation_enum_entries }, { "file_size", file_size_enum_entries }, - { "icon_captions", icon_captions_enum_entries }, { "search_bar_type", search_bar_type_enum_entries }, { "speed_tradeoff", speed_tradeoff_enum_entries }, { "standard_font_size", standard_font_size_entries }, diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h index 176f01ce3..754b1d4f5 100644 --- a/libnautilus-private/nautilus-global-preferences.h +++ b/libnautilus-private/nautilus-global-preferences.h @@ -123,6 +123,8 @@ enum #define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_IN_REVERSE_ORDER "list_view/default_sort_in_reverse_order" #define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_ORDER "list_view/default_sort_order" #define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL "list_view/default_zoom_level" +#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS "list_view/default_visible_columns" +#define NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER "list_view/default_column_order" /* News panel */ #define NAUTILUS_PREFERENCES_NEWS_MAX_ITEMS "news/max_items" diff --git a/libnautilus-private/nautilus-marshal.list b/libnautilus-private/nautilus-marshal.list index c0d617827..3261b785f 100644 --- a/libnautilus-private/nautilus-marshal.list +++ b/libnautilus-private/nautilus-marshal.list @@ -13,3 +13,4 @@ VOID:POINTER,STRING VOID:STRING,STRING VOID:POINTER,POINTER,POINTER,INT,INT,INT VOID:POINTER,STRING,UINT,INT,INT +VOID:POINTER,ENUM diff --git a/libnautilus-private/nautilus-metadata.h b/libnautilus-private/nautilus-metadata.h index 06a4014a7..710d82c0f 100644 --- a/libnautilus-private/nautilus-metadata.h +++ b/libnautilus-private/nautilus-metadata.h @@ -58,6 +58,9 @@ #define NAUTILUS_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL "list_view_zoom_level" #define NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN "list_view_sort_column" #define NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED "list_view_sort_reversed" +#define NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS "list_view_visible_columns" +#define NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER "list_view_column_order" +#define NAUTILUS_METADATA_SUBKEY_COLUMNS "columns" #define NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY "window_geometry" #define NAUTILUS_METADATA_KEY_WINDOW_SCROLL_POSITION "window_scroll_position" diff --git a/libnautilus-private/nautilus-module.c b/libnautilus-private/nautilus-module.c new file mode 100644 index 000000000..0edd200c2 --- /dev/null +++ b/libnautilus-private/nautilus-module.c @@ -0,0 +1,258 @@ +/* + * nautilus-module.h - Interface to nautilus extensions + * + * Copyright (C) 2003 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Dave Camp <dave@ximian.com> + * + */ + +#include <config.h> +#include "nautilus-module.h" + +#include <eel/eel-gtk-macros.h> +#include <gmodule.h> +#include <libgnome/gnome-macros.h> + +#define NAUTILUS_TYPE_MODULE (nautilus_module_get_type ()) +#define NAUTILUS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_MODULE, NautilusModule)) +#define NAUTILUS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_MODULE, NautilusModule)) +#define NAUTILUS_IS_MODULE(obj) (G_TYPE_INSTANCE_CHECK_TYPE ((obj), NAUTILUS_TYPE_MODULE)) +#define NAUTILUS_IS_MODULE_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_MODULE)) + +typedef struct _NautilusModule NautilusModule; +typedef struct _NautilusModuleClass NautilusModuleClass; + +struct _NautilusModule { + GTypeModule parent; + + GModule *library; + + char *path; + + void (*initialize) (GTypeModule *module); + void (*shutdown) (void); + + void (*list_types) (const GType **types, + int *num_types); + +}; + +struct _NautilusModuleClass { + GTypeModuleClass parent; +}; + +static GType nautilus_module_get_type (void); + +static GList *module_objects = NULL; + +GNOME_CLASS_BOILERPLATE (NautilusModule, + nautilus_module, + GTypeModule, + G_TYPE_TYPE_MODULE); + +static gboolean +nautilus_module_load (GTypeModule *gmodule) +{ + NautilusModule *module; + + module = NAUTILUS_MODULE (gmodule); + + module->library = g_module_open (module->path, 0); + + if (!module->library) { + g_warning (g_module_error ()); + return FALSE; + } + + if (!g_module_symbol (module->library, + "nautilus_module_initialize", + (gpointer *)&module->initialize) || + !g_module_symbol (module->library, + "nautilus_module_shutdown", + (gpointer *)&module->shutdown) || + !g_module_symbol (module->library, + "nautilus_module_list_types", + (gpointer *)&module->list_types)) { + + g_warning (g_module_error ()); + g_module_close (module->library); + + return FALSE; + } + + module->initialize (gmodule); + + return TRUE; +} + +static void +nautilus_module_unload (GTypeModule *gmodule) +{ + NautilusModule *module; + + module = NAUTILUS_MODULE (gmodule); + + module->shutdown (); + + g_module_close (module->library); + + module->initialize = NULL; + module->shutdown = NULL; + module->list_types = NULL; +} + +static void +nautilus_module_finalize (GObject *object) +{ + NautilusModule *module; + + module = NAUTILUS_MODULE (object); + + g_free (module->path); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +nautilus_module_instance_init (NautilusModule *module) +{ +} + +static void +nautilus_module_class_init (NautilusModuleClass *class) +{ + G_OBJECT_CLASS (class)->finalize = nautilus_module_finalize; + G_TYPE_MODULE_CLASS (class)->load = nautilus_module_load; + G_TYPE_MODULE_CLASS (class)->unload = nautilus_module_unload; +} + +static void +module_object_weak_notify (gpointer user_data, GObject *object) +{ + module_objects = g_list_remove (module_objects, object); +} + +static void +add_module_objects (NautilusModule *module) +{ + const GType *types; + int num_types; + int i; + + module->list_types (&types, &num_types); + + for (i = 0; i < num_types; i++) { + nautilus_module_add_type (types[i]); + } +} + +static NautilusModule * +nautilus_module_load_file (const char *filename) +{ + NautilusModule *module; + + module = g_object_new (NAUTILUS_TYPE_MODULE, NULL); + module->path = g_strdup (filename); + + if (g_type_module_use (G_TYPE_MODULE (module))) { + add_module_objects (module); + g_type_module_unuse (G_TYPE_MODULE (module)); + return module; + } else { + g_object_unref (module); + return NULL; + } +} + +static void +load_module_dir (const char *dirname) +{ + GDir *dir; + + dir = g_dir_open (dirname, 0, NULL); + + if (dir) { + const char *name; + + while ((name = g_dir_read_name (dir))) { + if (g_str_has_suffix (name, "." G_MODULE_SUFFIX)) { + char *filename; + + filename = g_build_filename (dirname, + name, + NULL); + nautilus_module_load_file (filename); + } + } + + g_dir_close (dir); + } +} + +void +nautilus_module_init (void) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + initialized = TRUE; + + load_module_dir (NAUTILUS_EXTENSIONDIR); + } +} + +GList * +nautilus_module_get_extensions_for_type (GType type) +{ + GList *l; + GList *ret = NULL; + + for (l = module_objects; l != NULL; l = l->next) { + if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data), + type)) { + g_object_ref (l->data); + ret = g_list_prepend (ret, l->data); + } + } + + return ret; +} + +void +nautilus_module_extension_list_free (GList *extensions) +{ + GList *l; + + for (l = extensions; l != NULL; l = l->next) { + g_object_unref (l->data); + } + g_list_free (extensions); +} + +void +nautilus_module_add_type (GType type) +{ + GObject *object; + + object = g_object_new (type, NULL); + g_object_weak_ref (object, + (GWeakNotify)module_object_weak_notify, + NULL); + + module_objects = g_list_prepend (module_objects, object); +} diff --git a/libnautilus-private/nautilus-module.h b/libnautilus-private/nautilus-module.h new file mode 100644 index 000000000..8c26b73e1 --- /dev/null +++ b/libnautilus-private/nautilus-module.h @@ -0,0 +1,42 @@ +/* + * nautilus-module.h - Interface to nautilus extensions + * + * Copyright (C) 2003 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Dave Camp <dave@ximian.com> + * + */ + +#ifndef NAUTILUS_MODULE_H +#define NAUTILUS_MODULE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void nautilus_module_init (void); +GList *nautilus_module_get_extensions_for_type (GType type); +void nautilus_module_extension_list_free (GList *list); + + +/* Add a type to the module interface - allows nautilus to add its own modules + * without putting them in separate shared libraries */ +void nautilus_module_add_type (GType type); + +G_END_DECLS + +#endif |