diff options
68 files changed, 6565 insertions, 1039 deletions
@@ -1,3 +1,299 @@ +2004-01-11 Dave Camp <dave@ximian.com> + + * Merged from nautilus-extensions-branch. + +2004-01-11 Dave Camp <dave@ximian.com> + + * libnautilus-extension/nautilus-column.c: + * libnautilus-extension/nautilus-column.h: + * libnautilus-extension/nautilus-menu-item.c: + * libnautilus-extension/nautilus-menu-item.h: + * libnautilus-extension/nautilus-property-page.c: + * libnautilus-extension/nautilus-property-page.h: + * libnautilus-private/nautilus-bonobo-extensions.c: + (get_extension_menu_item_xml), + (nautilus_bonobo_add_extension_item_command), + (get_extension_toolbar_item_xml): + * libnautilus-private/nautilus-column-chooser.c: (populate_tree), + (get_column_iter): + * libnautilus-private/nautilus-column-utilities.c: + (column_compare): + * src/file-manager/fm-list-model.c: (fm_list_model_get_value), + (fm_list_model_get_sort_column_id_from_attribute), + (fm_list_model_get_attribute_from_sort_column_id), + (fm_list_model_get_column_number): + * src/file-manager/fm-list-view.c: (apply_column_order): + * src/file-manager/fm-properties-window.c: + (append_extension_pages): + * src/nautilus-file-management-properties.c: + (create_icon_caption_menu): Removed the piles of accessors, + use gobject properties instead. + +2004-01-10 Dave Camp <dave@ximian.com> + + * libnautilus-extension/Makefile.am: + * libnautilus-extension/nautilus-column-provider.c: + (nautilus_column_provider_base_init), + (nautilus_column_provider_get_type), + (nautilus_column_provider_get_columns): + * libnautilus-extension/nautilus-column-provider.h: + * libnautilus-extension/nautilus-column.c: (nautilus_column_new), + (nautilus_column_get_name), (nautilus_column_get_attribute), + (nautilus_column_set_attribute), (nautilus_column_get_label), + (nautilus_column_set_label), (nautilus_column_get_description), + (nautilus_column_set_description), (nautilus_column_get_property), + (nautilus_column_set_property), (nautilus_column_finalize), + (nautilus_column_instance_init), (nautilus_column_class_init), + (nautilus_column_get_type): + * libnautilus-extension/nautilus-column.h: + * libnautilus-extension/nautilus-file-info.c: + (nautilus_file_info_get_string_attribute), + (nautilus_file_info_add_string_attribute): + * libnautilus-extension/nautilus-file-info.h: + * libnautilus-private/Makefile.am: + * libnautilus-private/apps_nautilus_preferences.schemas.in: + * libnautilus-private/nautilus-column-chooser.c: + (nautilus_column_chooser_class_init), (update_buttons), + (list_changed), (visible_toggled_callback), + (selection_changed_callback), (row_deleted_callback), + (add_tree_view), (set_selection_visible), + (move_up_clicked_callback), (move_down_clicked_callback), + (show_clicked_callback), (hide_clicked_callback), + (use_default_clicked_callback), (add_buttons), (populate_tree), + (nautilus_column_chooser_init), (nautilus_column_chooser_destroy), + (nautilus_column_chooser_finalize), (set_visible_columns), + (get_column_names), (get_column_iter), (set_column_order), + (nautilus_column_chooser_set_settings), + (nautilus_column_chooser_get_settings), + (nautilus_column_chooser_new): + * libnautilus-private/nautilus-column-chooser.h: + * libnautilus-private/nautilus-column-utilities.c: + (get_builtin_columns), (get_extension_columns), + (nautilus_get_all_columns), (nautilus_column_list_copy), + (nautilus_column_list_free), (column_compare), + (nautilus_sort_columns): + * libnautilus-private/nautilus-column-utilities.h: + * libnautilus-private/nautilus-file-private.h: + * libnautilus-private/nautilus-file.c: + (nautilus_file_instance_init), (finalize), + (nautilus_file_compare_for_sort_internal), + (nautilus_file_compare_for_sort), + (nautilus_file_compare_for_sort_by_attribute), + (nautilus_file_get_string_attribute), + (nautilus_file_invalidate_extension_info_internal), + (nautilus_file_add_string_attribute), + (nautilus_file_info_providers_done), + (nautilus_file_info_iface_init): + * libnautilus-private/nautilus-file.h: + * libnautilus-private/nautilus-global-preferences.c: + * libnautilus-private/nautilus-global-preferences.h: + * libnautilus-private/nautilus-metadata.h: + * src/file-manager/Makefile.am: + * src/file-manager/fm-list-model.c: (fm_list_model_get_n_columns), + (fm_list_model_get_column_type), (fm_list_model_get_value), + (fm_list_model_compare_func), (fm_list_model_get_sort_column_id), + (fm_list_model_set_sort_column_id), + (fm_list_model_get_sort_column_id_from_attribute), + (fm_list_model_get_attribute_from_sort_column_id), + (fm_list_model_add_column), (fm_list_model_get_column_number), + (fm_list_model_finalize), (fm_list_model_init): + * src/file-manager/fm-list-model.h: + * src/file-manager/fm-list-view.c: (sort_column_changed_callback), + (apply_visible_columns_foreach), (apply_visible_columns), + (apply_column_order), (create_and_set_up_tree_view), + (get_visible_columns), + (set_visible_columns_from_metadata_and_preferences), + (get_column_order), + (set_column_order_from_metadata_and_preferences), + (set_sort_order_from_metadata_and_preferences), + (fm_list_view_begin_loading), (column_editor_response_callback), + (column_chooser_changed_callback), + (column_chooser_set_from_settings), + (column_chooser_use_default_callback), (create_column_editor), + (visible_columns_callback), (fm_list_view_merge_menus), + (fm_list_view_update_menus), (fm_list_view_reset_to_defaults), + (fm_list_view_scale_font_size), + (default_visible_columns_changed_callback), + (default_column_order_changed_callback), (fm_list_view_dispose), + (fm_list_view_finalize), (fm_list_view_class_init), + (fm_list_view_instance_init): + * src/nautilus-file-management-properties-main.c: (main): + * src/nautilus-file-management-properties.c: + (columns_changed_callback), (create_icon_caption_menu), + (icon_captions_changed_callback), (update_caption_option_menu), + (update_icon_captions_from_gconf), + (nautilus_file_management_properties_dialog_setup_icon_caption_page + ), (set_columns_from_gconf), (use_default_callback), + (nautilus_file_management_properties_dialog_setup_list_column_page) + , (nautilus_file_management_properties_dialog_setup): + * src/nautilus-file-management-properties.glade: + + Added the ability to export column descriptions from extensions, + added column editing to the list view. + +2003-12-10 Dave Camp <dave@ximian.com> + + * libnautilus-extension/nautilus-file-info.c: + (nautilus_file_info_get_uri_scheme): + * libnautilus-extension/nautilus-file-info.h: + * libnautilus-private/nautilus-file.c: + (nautilus_file_info_iface_init): Added a + nautilus_file_info_get_uri_scheme convenience function. + * libnautilus-extension/nautilus-menu-item.h: + * libnautilus-extension/nautilus-menu-item.c: + (nautilus_menu_item_get_property), + (nautilus_menu_item_set_property), + (nautilus_menu_item_class_init): Added a priority text property. + * libnautilus-extension/nautilus-menu-provider.h: + * libnautilus-extension/nautilus-menu-provider.c: + (nautilus_menu_provider_get_file_items): Pass in the GtkWindow, + so that callbacks can parent dialogs appropriately. + (nautilus_menu_provider_get_background_items), + (nautilus_menu_provider_get_toolbar_items): New functions. + * libnautilus-private/nautilus-bonobo-extensions.h: + * libnautilus-private/nautilus-bonobo-extensions.c: + (get_extension_menu_item_xml), (extension_action_callback), + (nautilus_bonobo_add_extension_item_command), + (nautilus_bonobo_add_extension_item), + (get_extension_toolbar_item_xml), + (nautilus_bonobo_add_extension_toolbar_item): Move the extension + menu/toolbar stuff here. + * src/file-manager/fm-bonobo-provider.c: + (fm_bonobo_provider_get_file_items): Updated for new API. + * src/file-manager/fm-directory-view.c: (add_extension_menu_items), + (get_all_extension_menu_items), (reset_extension_actions_menu): Use + new nautilus-bonobo-extensions helpers. + * src/nautilus-shell-ui.xml: + * src/file-manager/nautilus-directory-view-ui.xml: + * src/nautilus-navigation-window-ui.xml: Move stuff around. + * src/nautilus-window.c: (ui_idle_handler), (real_merge_menus_2), + (nautilus_window_constructed), (nautilus_window_class_init): + * src/nautilus-window.h: + * src/nautilus-navigation-window.c: (real_merge_menus_2), + (nautilus_navigation_window_class_init): Move part two of the + menu merging to a virtual function. + * src/nautilus-window-manage-views.c: (update_for_new_location): + * src/nautilus-window-menus.c: + (nautilus_window_initialize_menus_part_1), (get_extension_menus), + (nautilus_window_load_extension_menus): Load background menu items + from the extensions. + * src/nautilus-window-private.h: + * src/nautilus-window-toolbars.c: (get_extension_toolbar_items), + (nautilus_navigation_window_load_extension_toolbar_items): + Load toolbar items from the extensions + +2003-11-28 Dave Camp <dave@ximian.com> + + * libnautilus-extension/Makefile.am: + * libnautilus-extension/nautilus-extension-i18n.h: New file. + * libnautilus-extension/nautilus-info-provider.h: + * libnautilus-extension/nautilus-file-info.h: + * libnautilus-extension/nautilus-file-info.c: + (nautilus_file_info_list_copy), (nautilus_file_info_list_free): New + functions. + * libnautilus-extension/nautilus-menu-item.c: + * libnautilus-extension/nautilus-menu-item.h: + * libnautilus-extension/nautilus-menu-provider.c: + * libnautilus-extension/nautilus-menu-provider.h: New files, + allow extensions to provide context menu items. + * libnautilus-extension/nautilus-property-page-provider.c: + * libnautilus-extension/nautilus-property-page-provider.h: + * libnautilus-extension/nautilus-property-page.c: + * libnautilus-extension/nautilus-property-page.h: New files, + allow extensions to provider property pages. + * libnautilus-private/nautilus-module.h: + * libnautilus-private/nautilus-module.c: (add_module_objects), + (nautilus_module_load_file), + (nautilus_module_get_extensions_for_type), + (nautilus_module_extension_list_free), (nautilus_module_add_type): + New functions. + * src/file-manager/Makefile.am: + * src/file-manager/fm-bonobo-provider.c: + (bonobo_mime_action_data_new), (bonobo_mime_action_data_free), + (bonobo_mime_action_activate_callback), + (bonobo_mime_action_callback), + (bonobo_mime_action_menu_data_destroy_callback), + (no_locale_at_end), (get_bonobo_menu_verb_names), + (can_handle_multiple_files), (get_menu_items_for_server), + (fm_bonobo_provider_get_file_items), + (fm_bonobo_provider_menu_provider_iface_init), + (bonobo_page_error_message), (get_uri_list), + (bonobo_page_activate_callback), (fm_bonobo_provider_get_pages), + (fm_bonobo_provider_property_page_provider_iface_init), + (fm_bonobo_provider_instance_init), + (fm_bonobo_provider_class_init), (fm_bonobo_provider_get_type): + * src/file-manager/fm-bonobo-provider.h: Moved the bonobo context + menu and property pages here. Export them through the extension + interface. + * src/file-manager/fm-directory-view.c: + (extension_action_callback), (add_extension_menu_items), + (get_all_extension_menu_items), (reset_extension_actions_menu), + (real_update_menus): Get context menu items from extensions. + * src/file-manager/fm-properties-window.c: (clear_extension_pages), + (refresh_extension_pages), (properties_window_update), + (append_extension_pages), (create_properties_window): Get property + pages from extensions. + * src/nautilus-application.c: (finish_startup): Add the + bonobo provider to the extension manager. + +2003-11-20 Dave Camp <dave@ximian.com> + + * Makefile.am: + * configure.in: + * libnautilus-extension/Makefile.am: + * libnautilus-extension/libnautilus-extension.pc.in: + * libnautilus-extension/nautilus-extension-types.c: + * libnautilus-extension/nautilus-extension-types.h: + * libnautilus-extension/nautilus-file-info.c: + * libnautilus-extension/nautilus-file-info.h: + * libnautilus-extension/nautilus-info-provider.c: + * libnautilus-extension/nautilus-info-provider.h: + New library for nautilus extensions. + + * libnautilus-private/nautilus-marshal.list: + * libnautilus-private/Makefile.am: + * libnautilus-private/nautilus-directory-async.c: + (nautilus_directory_set_up_request), (lacks_extension_info), + (wants_extension_info), (extension_info_cancel), + (extension_info_stop), (finish_info_provider), + (info_provider_idle_callback), (info_provider_callback), + (extension_info_start), (start_or_stop_io), + (nautilus_directory_cancel), (cancel_loading_attributes), + (file_needs_extension_work_done), (file_needs_work_done), + (nautilus_directory_remove_file_from_work_queue), + (move_file_to_low_priority_queue), (move_file_to_extension_queue): + * libnautilus-private/nautilus-directory-private.h: + * libnautilus-private/nautilus-directory.c: + (nautilus_directory_init), (nautilus_directory_finalize), + (nautilus_directory_notify_files_changed): + Add a third queue for extension info, that runs after the high + and low priority queues. + + * libnautilus-private/nautilus-file-attributes.h: + * libnautilus-private/nautilus-file-operations.c: + * libnautilus-private/nautilus-file-private.h: + * libnautilus-private/nautilus-file.c: + (nautilus_file_invalidate_extension_info_internal), + (nautilus_file_invalidate_attributes_internal): + + * libnautilus-private/nautilus-file.c: + (nautilus_file_get_type), (nautilus_file_instance_init), + (nautilus_file_get_keywords), (nautilus_file_get_type), + (nautilus_file_class_init), (nautilus_file_get_vfs_file_info), + (nautilus_file_add_emblem), (nautilus_file_info_providers_done), + (nautilus_file_info_iface_init): Implement the NautilusFileInfo + interface for extensions to use. + + * libnautilus-private/nautilus-module.c: (nautilus_module_load), + * libnautilus-private/nautilus-module.h: + Module loading code. + + * src/file-manager/fm-directory-view.c: (finish_loading): + Request extension info. + + * src/nautilus-application.c: (finish_startup): Initialize the + module interface. + 2004-01-11 Alexander Larsson <alexl@redhat.com> * libnautilus-private/nautilus-file.c (nautilus_file_get_activation_uri): diff --git a/Makefile.am b/Makefile.am index fe4e9e70a..321f8665e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ DESKTOP_SETTINGS_FILES= \ SUBDIRS = \ libnautilus \ + libnautilus-extension \ cut-n-paste-code \ libbackground \ libnautilus-private \ diff --git a/configure.in b/configure.in index f3198853d..6e1cf0122 100644 --- a/configure.in +++ b/configure.in @@ -325,6 +325,13 @@ AC_SUBST(LIBNAUTILUS_LIBS) LIBNAUTILUS_IDL_INCLUDES="`$PKG_CONFIG --variable=idldir $LIBNAUTILUS_MODULES | $srcdir/add-include-prefix`" AC_SUBST(LIBNAUTILUS_IDL_INCLUDES) +dnl libnautilus-extension +LIBNAUTILUS_EXTENSION_MODULES="glib-2.0 gtk+-2.0 gnome-vfs-2.0" +LIBNAUTILUS_EXTENSION_CFLAGS="`$PKG_CONFIG --cflags $LIBNAUTILUS_EXTENSION_MODULES`" +AC_SUBST(LIBNAUTILUS_EXTENSION_CFLAGS) +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 libbonoboui-2.0 esound gnome-desktop-2.0 $EXTRA_CORE_MODULES" CORE_CFLAGS="`$PKG_CONFIG --cflags $CORE_MODULES` $x_cflags" @@ -408,6 +415,8 @@ libnautilus-adapter/Makefile libnautilus-private/Makefile libnautilus/Makefile libnautilus/libnautilus.pc +libnautilus-extension/Makefile +libnautilus-extension/libnautilus-extension.pc nautilus.spec po/Makefile.in src/Makefile diff --git a/libnautilus-extension/Makefile.am b/libnautilus-extension/Makefile.am new file mode 100644 index 000000000..743f691d8 --- /dev/null +++ b/libnautilus-extension/Makefile.am @@ -0,0 +1,50 @@ +include $(top_srcdir)/Makefile.shared + +lib_LTLIBRARIES=libnautilus-extension.la + +INCLUDES=\ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(LIBNAUTILUS_EXTENSION_CFLAGS) \ + $(DISABLE_DEPRECATED_CFLAGS) \ + -DDATADIR=\""$(datadir)"\" \ + $(NULL) + +libnautilus_extension_la_LDFLAGS=\ + -version-info 1:0:0 \ + $(LIBNAUTILUS_EXTENSION_LIBS) \ + -no-undefined \ + $(NULL) + +libnautilus_extension_includedir=$(includedir)/nautilus/libnautilus-extension + +libnautilus_extension_include_HEADERS= \ + nautilus-column.h \ + nautilus-column-provider.h \ + nautilus-extension-types.h \ + nautilus-file-info.h \ + nautilus-menu-item.h \ + nautilus-menu-provider.h \ + nautilus-property-page.h \ + nautilus-property-page-provider.h \ + nautilus-info-provider.h \ + $(NULL) + +libnautilus_extension_la_SOURCES= \ + nautilus-column.c \ + nautilus-column-provider.c \ + nautilus-extension-types.c \ + nautilus-file-info.c \ + nautilus-menu-item.c \ + nautilus-menu-provider.c \ + nautilus-property-page.c \ + nautilus-property-page-provider.c \ + nautilus-info-provider.c \ + $(NULL) + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA=libnautilus-extension.pc + +EXTRA_DIST = \ + libnautilus-extension.pc.in \ + $(NULL) diff --git a/libnautilus-extension/libnautilus-extension.pc.in b/libnautilus-extension/libnautilus-extension.pc.in new file mode 100644 index 000000000..5286e9b9b --- /dev/null +++ b/libnautilus-extension/libnautilus-extension.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libnautilus-extension +Description: A library to create Nautilus view extensions +Version: @VERSION@ +Requires: glib-2.0 gtk+-2.0 gnome-vfs-2.0 +Libs: -L${libdir} -lnautilus-extension +Cflags: -I${includedir}/nautilus diff --git a/libnautilus-extension/nautilus-column-provider.c b/libnautilus-extension/nautilus-column-provider.c new file mode 100644 index 000000000..eff660ad0 --- /dev/null +++ b/libnautilus-extension/nautilus-column-provider.c @@ -0,0 +1,72 @@ +/* + * nautilus-column-provider.c - Interface for Nautilus extensions + * that provide column specifications. + * + * 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-column-provider.h" + +#include <glib-object.h> + +static void +nautilus_column_provider_base_init (gpointer g_class) +{ +} + +GType +nautilus_column_provider_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusColumnProviderIface), + nautilus_column_provider_base_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "NautilusColumnProvider", + &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} + +GList * +nautilus_column_provider_get_columns (NautilusColumnProvider *provider) +{ + g_return_val_if_fail (NAUTILUS_IS_COLUMN_PROVIDER (provider), NULL); + g_return_val_if_fail (NAUTILUS_COLUMN_PROVIDER_GET_IFACE (provider)->get_columns != NULL, NULL); + + return NAUTILUS_COLUMN_PROVIDER_GET_IFACE (provider)->get_columns + (provider); +} + + diff --git a/libnautilus-extension/nautilus-column-provider.h b/libnautilus-extension/nautilus-column-provider.h new file mode 100644 index 000000000..630e88ac4 --- /dev/null +++ b/libnautilus-extension/nautilus-column-provider.h @@ -0,0 +1,60 @@ +/* + * nautilus-column-provider.h - Interface for Nautilus extensions that + * provide column descriptions. + * + * 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> + * + */ + +/* This interface is implemented by Nautilus extensions that want to + * add columns to the list view and details to the icon view. + * Extensions are asked for a list of columns to display. Each + * returned column refers to a string attribute which can be filled in + * by NautilusInfoProvider */ + +#ifndef NAUTILUS_COLUMN_PROVIDER_H +#define NAUTILUS_COLUMN_PROVIDER_H + +#include <glib-object.h> +#include "nautilus-extension-types.h" +#include "nautilus-column.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_COLUMN_PROVIDER (nautilus_column_provider_get_type ()) +#define NAUTILUS_COLUMN_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_COLUMN_PROVIDER, NautilusColumnProvider)) +#define NAUTILUS_IS_COLUMN_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_COLUMN_PROVIDER)) +#define NAUTILUS_COLUMN_PROVIDER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NAUTILUS_TYPE_COLUMN_PROVIDER, NautilusColumnProviderIface)) + +typedef struct _NautilusColumnProvider NautilusColumnProvider; +typedef struct _NautilusColumnProviderIface NautilusColumnProviderIface; + +struct _NautilusColumnProviderIface { + GTypeInterface g_iface; + + GList *(*get_columns) (NautilusColumnProvider *provider); +}; + +/* Interface Functions */ +GType nautilus_column_provider_get_type (void); +GList *nautilus_column_provider_get_columns (NautilusColumnProvider *provider); + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-column.c b/libnautilus-extension/nautilus-column.c new file mode 100644 index 000000000..1679f0ca8 --- /dev/null +++ b/libnautilus-extension/nautilus-column.c @@ -0,0 +1,237 @@ +/* + * nautilus-column.c - Info columns exported by NautilusColumnProvider + * objects. + * + * 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-column.h" +#include "nautilus-extension-i18n.h" + +enum { + PROP_0, + PROP_NAME, + PROP_ATTRIBUTE, + PROP_LABEL, + PROP_DESCRIPTION, + PROP_XALIGN, + LAST_PROP +}; + +struct _NautilusColumnDetails { + char *name; + char *attribute; + char *label; + char *description; + float xalign; +}; + +NautilusColumn * +nautilus_column_new (const char *name, + const char *attribute, + const char *label, + const char *description) +{ + NautilusColumn *column; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (attribute != NULL, NULL); + g_return_val_if_fail (label != NULL, NULL); + g_return_val_if_fail (description != NULL, NULL); + + column = g_object_new (NAUTILUS_TYPE_COLUMN, + "name", name, + "attribute", attribute, + "label", label, + "description", description, + NULL); + + return column; +} + +static void +nautilus_column_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusColumn *column; + + column = NAUTILUS_COLUMN (object); + + switch (param_id) { + case PROP_NAME : + g_value_set_string (value, column->details->name); + break; + case PROP_ATTRIBUTE : + g_value_set_string (value, column->details->attribute); + break; + case PROP_LABEL : + g_value_set_string (value, column->details->label); + break; + case PROP_DESCRIPTION : + g_value_set_string (value, column->details->description); + break; + case PROP_XALIGN : + g_value_set_float (value, column->details->xalign); + break; + default : + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_column_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + NautilusColumn *column; + + column = NAUTILUS_COLUMN (object); + + switch (param_id) { + case PROP_NAME : + g_free (column->details->name); + column->details->name = g_strdup (g_value_get_string (value)); + g_object_notify (object, "name"); + break; + case PROP_ATTRIBUTE : + g_free (column->details->attribute); + column->details->attribute = g_strdup (g_value_get_string (value)); + g_object_notify (object, "attribute"); + break; + case PROP_LABEL : + g_free (column->details->label); + column->details->label = g_strdup (g_value_get_string (value)); + g_object_notify (object, "label"); + break; + case PROP_DESCRIPTION : + g_free (column->details->description); + column->details->description = g_strdup (g_value_get_string (value)); + g_object_notify (object, "description"); + break; + case PROP_XALIGN : + column->details->xalign = g_value_get_float (value); + g_object_notify (object, "xalign"); + break; + default : + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_column_finalize (GObject *object) +{ + NautilusColumn *column; + + column = NAUTILUS_COLUMN (object); + + g_free (column->details->name); + g_free (column->details->attribute); + g_free (column->details->label); + g_free (column->details->description); + + g_free (column->details); +} + +static void +nautilus_column_instance_init (NautilusColumn *column) +{ + column->details = g_new0 (NautilusColumnDetails, 1); + column->details->xalign = 0.0; +} + +static void +nautilus_column_class_init (NautilusColumnClass *class) +{ + G_OBJECT_CLASS (class)->finalize = nautilus_column_finalize; + G_OBJECT_CLASS (class)->get_property = nautilus_column_get_property; + G_OBJECT_CLASS (class)->set_property = nautilus_column_set_property; + + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_NAME, + g_param_spec_string ("name", + _("Name"), + _("Name of the column"), + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_ATTRIBUTE, + g_param_spec_string ("attribute", + _("Attribute"), + _("The attribute name to display"), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_LABEL, + g_param_spec_string ("label", + _("Label"), + _("Label to display in the column"), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_DESCRIPTION, + g_param_spec_string ("description", + _("Description"), + _("A user-visible description of the column"), + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_XALIGN, + g_param_spec_float ("xalign", + _("xalign"), + _("The x-alignment of the column"), + 0.0, + 1.0, + 0.0, + G_PARAM_READWRITE)); +} + +GType +nautilus_column_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusColumnClass), + NULL, + NULL, + (GClassInitFunc)nautilus_column_class_init, + NULL, + NULL, + sizeof (NautilusColumn), + 0, + (GInstanceInitFunc)nautilus_column_instance_init + }; + + type = g_type_register_static + (G_TYPE_OBJECT, + "NautilusColumn", + &info, 0); + } + + return type; +} diff --git a/libnautilus-extension/nautilus-column.h b/libnautilus-extension/nautilus-column.h new file mode 100644 index 000000000..8ad627a9b --- /dev/null +++ b/libnautilus-extension/nautilus-column.h @@ -0,0 +1,71 @@ +/* + * nautilus-column.h - Info columns exported by + * NautilusColumnProvider objects. + * + * 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_COLUMN_H +#define NAUTILUS_COLUMN_H + +#include <glib-object.h> +#include "nautilus-extension-types.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_COLUMN (nautilus_column_get_type()) +#define NAUTILUS_COLUMN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_COLUMN, NautilusColumn)) +#define NAUTILUS_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_COLUMN, NautilusColumnClass)) +#define NAUTILUS_INFO_IS_COLUMN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_COLUMN)) +#define NAUTILUS_INFO_IS_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NAUTILUS_TYPE_COLUMN)) +#define NAUTILUS_COLUMN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NAUTILUS_TYPE_COLUMN, NautilusColumnClass)) + +typedef struct _NautilusColumn NautilusColumn; +typedef struct _NautilusColumnDetails NautilusColumnDetails; +typedef struct _NautilusColumnClass NautilusColumnClass; + +struct _NautilusColumn { + GObject parent; + + NautilusColumnDetails *details; +}; + +struct _NautilusColumnClass { + GObjectClass parent; +}; + +GType nautilus_column_get_type (void); +NautilusColumn * nautilus_column_new (const char *name, + const char *attribute, + const char *label, + const char *description); + +/* NautilusColumn has the following properties: + * name (string) - the identifier for the column + * attribute (string) - the file attribute to be displayed in the + * column + * label (string) - the user-visible label for the column + * description (string) - a user-visible description of the column + * xalign (float) - x-alignment of the column + */ + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-extension-i18n.h b/libnautilus-extension/nautilus-extension-i18n.h new file mode 100644 index 000000000..97fa0ab4c --- /dev/null +++ b/libnautilus-extension/nautilus-extension-i18n.h @@ -0,0 +1,24 @@ +#ifndef NAUTILUS_EXTENSION_I18N_H +#define NAUTILUS_EXTENSION_I18N_H + +#include "config.h" + +#ifdef ENABLE_NLS +#include<libintl.h> +#define _(String) dgettext(GETTEXT_PACKAGE,String) +#ifdef gettext_noop +#define N_(String) gettext_noop(String) +#else +#define N_(String) (String) +#endif +#else /* NLS is disabled */ +#define _(String) (String) +#define N_(String) (String) +#define textdomain(String) (String) +#define gettext(String) (String) +#define dgettext(Domain,String) (String) +#define dcgettext(Domain,String,Type) (String) +#define bindtextdomain(Domain,Directory) (Domain) +#endif + +#endif diff --git a/libnautilus-extension/nautilus-extension-types.c b/libnautilus-extension/nautilus-extension-types.c new file mode 100644 index 000000000..ee815fc10 --- /dev/null +++ b/libnautilus-extension/nautilus-extension-types.c @@ -0,0 +1,57 @@ +/* + * nautilus-extension-types.c - Type definitions for 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-extension-types.h" + + +GType +nautilus_operation_result_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GEnumValue values[] = { + { + NAUTILUS_OPERATION_COMPLETE, + "NAUTILUS_OPERATION_COMPLETE", + "complete", + }, + { + NAUTILUS_OPERATION_FAILED, + "NAUTILUS_OPERATION_FAILED", + "failed", + }, + { + NAUTILUS_OPERATION_IN_PROGRESS, + "NAUTILUS_OPERATION_IN_PROGRESS", + "in_progress", + }, + { 0, NULL, NULL } + }; + + type = g_enum_register_static ("NautilusOperationResult", + values); + } + + return type; +} diff --git a/libnautilus-extension/nautilus-extension-types.h b/libnautilus-extension/nautilus-extension-types.h new file mode 100644 index 000000000..806d17118 --- /dev/null +++ b/libnautilus-extension/nautilus-extension-types.h @@ -0,0 +1,67 @@ +/* + * nautilus-info-provider.h - Type definitions for 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> + * + */ + +/* This interface is implemented by Nautilus extensions that want to + * provide information about files. Extensions are called when Nautilus + * needs information about a file. They are passed a NautilusFileInfo + * object which should be filled with relevant information */ + +#ifndef NAUTILUS_EXTENSION_TYPES_H +#define NAUTILUS_EXTENSION_TYPES_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_OPERATION_RESULT (nautilus_operation_result_get_type ()) + +/* Handle for asynchronous interfaces. These are opaque handles that must + * be unique within an extension object. These are returned by operations + * that return NAUTILUS_OPERATION_IN_PROGRESS */ +typedef struct _NautilusOperationHandle NautilusOperationHandle; + +typedef enum { + /* Returned if the call succeeded, and the extension is done + * with the request */ + NAUTILUS_OPERATION_COMPLETE, + + /* Returned if the call failed */ + NAUTILUS_OPERATION_FAILED, + + /* Returned if the extension has begun an async operation. + * If this is returned, the extension must set the handle + * parameter and call the callback closure when the + * operation is complete. */ + NAUTILUS_OPERATION_IN_PROGRESS, +} NautilusOperationResult; + +GType nautilus_operation_result_get_type (void); + +void nautilus_module_initialize (GTypeModule *module); +void nautilus_module_shutdown (void); +void nautilus_module_list_types (const GType **types, + int *num_types); + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-file-info.c b/libnautilus-extension/nautilus-file-info.c new file mode 100644 index 000000000..e245de9d7 --- /dev/null +++ b/libnautilus-extension/nautilus-file-info.c @@ -0,0 +1,202 @@ +/* + * nautilus-file-info.c - Information about a file + * + * 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. + * + */ + +#include <config.h> +#include "nautilus-file-info.h" + + +GList * +nautilus_file_info_list_copy (GList *files) +{ + GList *ret; + GList *l; + + ret = g_list_copy (files); + for (l = ret; l != NULL; l = l->next) { + g_object_ref (G_OBJECT (l->data)); + } + + return ret; +} + +void +nautilus_file_info_list_free (GList *files) +{ + GList *l; + + for (l = files; l != NULL; l = l->next) { + g_object_unref (G_OBJECT (l->data)); + } + + g_list_free (files); +} + +static void +nautilus_file_info_base_init (gpointer g_class) +{ +} + +GType +nautilus_file_info_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusFileInfoIface), + nautilus_file_info_base_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "NautilusFileInfo", + &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} + +gboolean +nautilus_file_info_is_gone (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), FALSE); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->is_gone != NULL, FALSE); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->is_gone (file); +} + +char * +nautilus_file_info_get_name (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_name != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_name (file); +} + +char * +nautilus_file_info_get_uri (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_uri != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_uri (file); +} + +char * +nautilus_file_info_get_parent_uri (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_uri != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_parent_uri (file); +} + +char * +nautilus_file_info_get_uri_scheme (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_uri_scheme != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_uri_scheme (file); +} + +char * +nautilus_file_info_get_mime_type (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_mime_type != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_mime_type (file); +} + +gboolean +nautilus_file_info_is_mime_type (NautilusFileInfo *file, + const char *mime_type) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), FALSE); + g_return_val_if_fail (mime_type != NULL, FALSE); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->is_mime_type != NULL, FALSE); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->is_mime_type (file, + mime_type); +} + +gboolean +nautilus_file_info_is_directory (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), FALSE); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->is_directory != NULL, FALSE); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->is_directory (file); +} + +GnomeVFSFileInfo * +nautilus_file_info_get_vfs_file_info (NautilusFileInfo *file) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_vfs_file_info != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_vfs_file_info (file); +} + +void +nautilus_file_info_add_emblem (NautilusFileInfo *file, + const char *emblem_name) +{ + g_return_if_fail (NAUTILUS_IS_FILE_INFO (file)); + g_return_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_vfs_file_info != NULL); + + NAUTILUS_FILE_INFO_GET_IFACE (file)->add_emblem (file, emblem_name); +} + +char * +nautilus_file_info_get_string_attribute (NautilusFileInfo *file, + const char *attribute_name) +{ + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (file), NULL); + g_return_val_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->get_string_attribute != NULL, NULL); + g_return_val_if_fail (attribute_name != NULL, NULL); + + return NAUTILUS_FILE_INFO_GET_IFACE (file)->get_string_attribute + (file, attribute_name); +} + +void +nautilus_file_info_add_string_attribute (NautilusFileInfo *file, + const char *attribute_name, + const char *value) +{ + g_return_if_fail (NAUTILUS_IS_FILE_INFO (file)); + g_return_if_fail (NAUTILUS_FILE_INFO_GET_IFACE (file)->add_string_attribute != NULL); + g_return_if_fail (attribute_name != NULL); + g_return_if_fail (value != NULL); + + NAUTILUS_FILE_INFO_GET_IFACE (file)->add_string_attribute + (file, attribute_name, value); +} diff --git a/libnautilus-extension/nautilus-file-info.h b/libnautilus-extension/nautilus-file-info.h new file mode 100644 index 000000000..49d7d588b --- /dev/null +++ b/libnautilus-extension/nautilus-file-info.h @@ -0,0 +1,113 @@ +/* + * nautilus-file-info.h - Information about a file + * + * 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. + * + */ + +/* NautilusFileInfo is an interface to the NautilusFile object. It + * provides access to the asynchronous data in the NautilusFile. + * Extensions are passed objects of this type for operations. */ + +#ifndef NAUTILUS_FILE_INFO_H +#define NAUTILUS_FILE_INFO_H + +#include <glib-object.h> +#include <libgnomevfs/gnome-vfs-file-info.h> + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_FILE_INFO (nautilus_file_info_get_type ()) +#define NAUTILUS_FILE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_FILE_INFO, NautilusFileInfo)) +#define NAUTILUS_IS_FILE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_FILE_INFO)) +#define NAUTILUS_FILE_INFO_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NAUTILUS_TYPE_FILE_INFO, NautilusFileInfoIface)) + + +#ifndef NAUTILUS_FILE_DEFINED +#define NAUTILUS_FILE_DEFINED +/* Using NautilusFile for the vtable to make implementing this in + * NautilusFile easier */ +typedef struct NautilusFile NautilusFile; +#endif + +typedef NautilusFile NautilusFileInfo; +typedef struct _NautilusFileInfoIface NautilusFileInfoIface; + + +struct _NautilusFileInfoIface +{ + gboolean (*is_gone) (NautilusFileInfo *file); + + char * (*get_name) (NautilusFileInfo *file); + char * (*get_uri) (NautilusFileInfo *file); + char * (*get_parent_uri) (NautilusFileInfo *file); + char * (*get_uri_scheme) (NautilusFileInfo *file); + + char * (*get_mime_type) (NautilusFileInfo *file); + gboolean (*is_mime_type) (NautilusFileInfo *file, + const char *mime_Type); + gboolean (*is_directory) (NautilusFileInfo *file); + + GnomeVFSFileInfo *(*get_vfs_file_info) (NautilusFileInfo *file); + + void (*add_emblem) (NautilusFileInfo *file, + const char *emblem_name); + char * (*get_string_attribute) (NautilusFileInfo *file, + const char *attribute_name); + void (*add_string_attribute) (NautilusFileInfo *file, + const char *attribute_name, + const char *value); +}; + +GList *nautilus_file_info_list_copy (GList *files); +void nautilus_file_info_list_free (GList *files); +GType nautilus_file_info_get_type (void); + +/* Return true if the file has been deleted */ +gboolean nautilus_file_info_is_gone (NautilusFileInfo *file); + +/* Name and Location */ +char * nautilus_file_info_get_name (NautilusFileInfo *file); +char * nautilus_file_info_get_uri (NautilusFileInfo *file); +char * nautilus_file_info_get_parent_uri (NautilusFileInfo *file); +char * nautilus_file_info_get_uri_scheme (NautilusFileInfo *file); + +/* File Type */ +char * nautilus_file_info_get_mime_type (NautilusFileInfo *file); +gboolean nautilus_file_info_is_mime_type (NautilusFileInfo *file, + const char *mime_type); +gboolean nautilus_file_info_is_directory (NautilusFileInfo *file); + + + +/* Other File Info */ +GnomeVFSFileInfo *nautilus_file_info_get_vfs_file_info (NautilusFileInfo *file); + + + +/* Modifying the NautilusFileInfo */ +void nautilus_file_info_add_emblem (NautilusFileInfo *file, + const char *emblem_name); +char * nautilus_file_info_get_string_attribute (NautilusFileInfo *file, + const char *attribute_name); +void nautilus_file_info_add_string_attribute (NautilusFileInfo *file, + const char *attribute_name, + const char *value); + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-info-provider.c b/libnautilus-extension/nautilus-info-provider.c new file mode 100644 index 000000000..942245190 --- /dev/null +++ b/libnautilus-extension/nautilus-info-provider.c @@ -0,0 +1,120 @@ +/* + * nautilus-info-provider.c - Interface for Nautilus extensions that + * provide info about files. + * + * 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-info-provider.h" + +#include <glib-object.h> + +static void +nautilus_info_provider_base_init (gpointer g_class) +{ +} + +GType +nautilus_info_provider_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusInfoProviderIface), + nautilus_info_provider_base_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "NautilusInfoProvider", + &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} + +NautilusOperationResult +nautilus_info_provider_update_file_info (NautilusInfoProvider *provider, + NautilusFileInfo *file, + GClosure *update_complete, + NautilusOperationHandle **handle) +{ + g_return_val_if_fail (NAUTILUS_IS_INFO_PROVIDER (provider), + NAUTILUS_OPERATION_FAILED); + g_return_val_if_fail (NAUTILUS_INFO_PROVIDER_GET_IFACE (provider)->update_file_info != NULL, + NAUTILUS_OPERATION_FAILED); + g_return_val_if_fail (update_complete != NULL, + NAUTILUS_OPERATION_FAILED); + g_return_val_if_fail (handle != NULL, NAUTILUS_OPERATION_FAILED); + + return NAUTILUS_INFO_PROVIDER_GET_IFACE (provider)->update_file_info + (provider, file, update_complete, handle); +} + +void +nautilus_info_provider_cancel_update (NautilusInfoProvider *provider, + NautilusOperationHandle *handle) +{ + g_return_if_fail (NAUTILUS_IS_INFO_PROVIDER (provider)); + g_return_if_fail (NAUTILUS_INFO_PROVIDER_GET_IFACE (provider)->cancel_update != NULL); + g_return_if_fail (NAUTILUS_INFO_PROVIDER_GET_IFACE (provider)->cancel_update != NULL); + g_return_if_fail (handle != NULL); + + NAUTILUS_INFO_PROVIDER_GET_IFACE (provider)->cancel_update (provider, + handle); +} + +void +nautilus_info_provider_update_complete_invoke (GClosure *update_complete, + NautilusInfoProvider *provider, + NautilusOperationHandle *handle, + NautilusOperationResult result) +{ + GValue args[3] = { { 0, } }; + GValue return_val = { 0, }; + + g_return_if_fail (update_complete != NULL); + g_return_if_fail (NAUTILUS_IS_INFO_PROVIDER (provider)); + + g_value_init (&args[0], NAUTILUS_TYPE_INFO_PROVIDER); + g_value_init (&args[1], G_TYPE_POINTER); + g_value_init (&args[2], NAUTILUS_TYPE_OPERATION_RESULT); + + g_value_set_object (&args[0], provider); + g_value_set_pointer (&args[1], handle); + g_value_set_enum (&args[2], result); + + g_closure_invoke (update_complete, &return_val, 3, args, NULL); + + g_value_unset (&args[0]); + g_value_unset (&args[1]); + g_value_unset (&args[2]); +} + + diff --git a/libnautilus-extension/nautilus-info-provider.h b/libnautilus-extension/nautilus-info-provider.h new file mode 100644 index 000000000..ded7748d0 --- /dev/null +++ b/libnautilus-extension/nautilus-info-provider.h @@ -0,0 +1,82 @@ +/* + * nautilus-info-provider.h - Interface for Nautilus extensions that + * provide info about files. + * + * 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> + * + */ + +/* This interface is implemented by Nautilus extensions that want to + * provide information about files. Extensions are called when Nautilus + * needs information about a file. They are passed a NautilusFileInfo + * object which should be filled with relevant information */ + +#ifndef NAUTILUS_INFO_PROVIDER_H +#define NAUTILUS_INFO_PROVIDER_H + +#include <glib-object.h> +#include "nautilus-extension-types.h" +#include "nautilus-file-info.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_INFO_PROVIDER (nautilus_info_provider_get_type ()) +#define NAUTILUS_INFO_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_INFO_PROVIDER, NautilusInfoProvider)) +#define NAUTILUS_IS_INFO_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_INFO_PROVIDER)) +#define NAUTILUS_INFO_PROVIDER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NAUTILUS_TYPE_INFO_PROVIDER, NautilusInfoProviderIface)) + +typedef struct _NautilusInfoProvider NautilusInfoProvider; +typedef struct _NautilusInfoProviderIface NautilusInfoProviderIface; + +typedef void (*NautilusInfoProviderUpdateComplete) (NautilusInfoProvider *provider, + NautilusOperationHandle *handle, + NautilusOperationResult result, + gpointer user_data); + +struct _NautilusInfoProviderIface { + GTypeInterface g_iface; + + NautilusOperationResult (*update_file_info) (NautilusInfoProvider *provider, + NautilusFileInfo *file, + GClosure *update_complete, + NautilusOperationHandle **handle); + void (*cancel_update) (NautilusInfoProvider *provider, + NautilusOperationHandle *handle); +}; + +/* Interface Functions */ +GType nautilus_info_provider_get_type (void); +NautilusOperationResult nautilus_info_provider_update_file_info (NautilusInfoProvider *provider, + NautilusFileInfo *file, + GClosure *update_complete, + NautilusOperationHandle **handle); +void nautilus_info_provider_cancel_update (NautilusInfoProvider *provider, + NautilusOperationHandle *handle); + + + +/* Helper functions for implementations */ +void nautilus_info_provider_update_complete_invoke (GClosure *update_complete, + NautilusInfoProvider *provider, + NautilusOperationHandle *handle, + NautilusOperationResult result); + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-menu-item.c b/libnautilus-extension/nautilus-menu-item.c new file mode 100644 index 000000000..83a26e26e --- /dev/null +++ b/libnautilus-extension/nautilus-menu-item.c @@ -0,0 +1,274 @@ +/* + * nautilus-menu-item.c - Menu items exported by NautilusMenuProvider + * objects. + * + * 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-menu-item.h" +#include "nautilus-extension-i18n.h" + +enum { + ACTIVATE, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_NAME, + PROP_LABEL, + PROP_TIP, + PROP_ICON, + PROP_SENSITIVE, + PROP_PRIORITY, + LAST_PROP +}; + +struct _NautilusMenuItemDetails { + char *name; + char *label; + char *tip; + char *icon; + gboolean sensitive; + gboolean priority; +}; + +static guint signals[LAST_SIGNAL]; + +NautilusMenuItem * +nautilus_menu_item_new (const char *name, + const char *label, + const char *tip, + const char *icon) +{ + NautilusMenuItem *item; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (label != NULL, NULL); + g_return_val_if_fail (tip != NULL, NULL); + + item = g_object_new (NAUTILUS_TYPE_MENU_ITEM, + "name", name, + "label", label, + "tip", tip, + "icon", icon, + NULL); + + return item; +} + +void +nautilus_menu_item_activate (NautilusMenuItem *item) +{ + g_signal_emit (item, signals[ACTIVATE], 0); +} + +static void +nautilus_menu_item_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusMenuItem *item; + + item = NAUTILUS_MENU_ITEM (object); + + switch (param_id) { + case PROP_NAME : + g_value_set_string (value, item->details->name); + break; + case PROP_LABEL : + g_value_set_string (value, item->details->label); + break; + case PROP_TIP : + g_value_set_string (value, item->details->tip); + break; + case PROP_ICON : + g_value_set_string (value, item->details->icon); + break; + case PROP_SENSITIVE : + g_value_set_boolean (value, item->details->sensitive); + break; + case PROP_PRIORITY : + g_value_set_boolean (value, item->details->priority); + break; + default : + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_menu_item_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + NautilusMenuItem *item; + + item = NAUTILUS_MENU_ITEM (object); + + switch (param_id) { + case PROP_NAME : + g_free (item->details->name); + item->details->name = g_strdup (g_value_get_string (value)); + g_object_notify (object, "name"); + break; + case PROP_LABEL : + g_free (item->details->label); + item->details->label = g_strdup (g_value_get_string (value)); + g_object_notify (object, "label"); + break; + case PROP_TIP : + g_free (item->details->tip); + item->details->tip = g_strdup (g_value_get_string (value)); + g_object_notify (object, "tip"); + break; + case PROP_ICON : + g_free (item->details->icon); + item->details->icon = g_strdup (g_value_get_string (value)); + g_object_notify (object, "icon"); + break; + case PROP_SENSITIVE : + item->details->sensitive = g_value_get_boolean (value); + g_object_notify (object, "sensitive"); + break; + case PROP_PRIORITY : + item->details->priority = g_value_get_boolean (value); + g_object_notify (object, "priority"); + break; + default : + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_menu_item_finalize (GObject *object) +{ + NautilusMenuItem *item; + + item = NAUTILUS_MENU_ITEM (object); + + g_free (item->details->name); + g_free (item->details->label); + g_free (item->details->tip); + g_free (item->details->icon); + + g_free (item->details); +} + +static void +nautilus_menu_item_instance_init (NautilusMenuItem *item) +{ + item->details = g_new0 (NautilusMenuItemDetails, 1); + item->details->sensitive = TRUE; +} + +static void +nautilus_menu_item_class_init (NautilusMenuItemClass *class) +{ + G_OBJECT_CLASS (class)->finalize = nautilus_menu_item_finalize; + G_OBJECT_CLASS (class)->get_property = nautilus_menu_item_get_property; + G_OBJECT_CLASS (class)->set_property = nautilus_menu_item_set_property; + + signals[ACTIVATE] = + g_signal_new ("activate", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NautilusMenuItemClass, + activate), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_NAME, + g_param_spec_string ("name", + _("Name"), + _("Name of the item"), + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_LABEL, + g_param_spec_string ("label", + _("Label"), + _("Label to display to the user"), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_TIP, + g_param_spec_string ("tip", + _("Tip"), + _("Tooltip for the menu item"), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_ICON, + g_param_spec_string ("icon", + _("Icon"), + _("Name of the icon to display in the menu item"), + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", + _("Sensitive"), + _("Whether the menu item is sensitive"), + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_PRIORITY, + g_param_spec_boolean ("priority", + _("Priority"), + _("Show priority text in toolbars"), + TRUE, + G_PARAM_READWRITE)); +} + +GType +nautilus_menu_item_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusMenuItemClass), + NULL, + NULL, + (GClassInitFunc)nautilus_menu_item_class_init, + NULL, + NULL, + sizeof (NautilusMenuItem), + 0, + (GInstanceInitFunc)nautilus_menu_item_instance_init + }; + + type = g_type_register_static + (G_TYPE_OBJECT, + "NautilusMenuItem", + &info, 0); + } + + return type; +} + diff --git a/libnautilus-extension/nautilus-menu-item.h b/libnautilus-extension/nautilus-menu-item.h new file mode 100644 index 000000000..be443d0b3 --- /dev/null +++ b/libnautilus-extension/nautilus-menu-item.h @@ -0,0 +1,77 @@ +/* + * nautilus-menu-item.h - Menu items exported by NautilusMenuProvider + * objects. + * + * 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_MENU_ITEM_H +#define NAUTILUS_MENU_ITEM_H + +#include <glib-object.h> +#include "nautilus-extension-types.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_MENU_ITEM (nautilus_menu_item_get_type()) +#define NAUTILUS_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_MENU_ITEM, NautilusMenuItem)) +#define NAUTILUS_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_MENU_ITEM, NautilusMenuItemClass)) +#define NAUTILUS_MENU_IS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_MENU_ITEM)) +#define NAUTILUS_MENU_IS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NAUTILUS_TYPE_MENU_ITEM)) +#define NAUTILUS_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NAUTILUS_TYPE_MENU_ITEM, NautilusMenuItemClass)) + +typedef struct _NautilusMenuItem NautilusMenuItem; +typedef struct _NautilusMenuItemDetails NautilusMenuItemDetails; +typedef struct _NautilusMenuItemClass NautilusMenuItemClass; + +struct _NautilusMenuItem { + GObject parent; + + NautilusMenuItemDetails *details; +}; + +struct _NautilusMenuItemClass { + GObjectClass parent; + + void (*activate) (NautilusMenuItem *item); +}; + +GType nautilus_menu_item_get_type (void); +NautilusMenuItem *nautilus_menu_item_new (const char *name, + const char *label, + const char *tip, + const char *icon); + +void nautilus_menu_item_activate (NautilusMenuItem *item); + +/* NautilusMenuItem has the following properties: + * name (string) - the identifier for the menu item + * label (string) - the user-visible label of the menu item + * tip (string) - the tooltip of the menu item + * icon (string) - the name of the icon to display in the menu item + * sensitive (boolean) - whether the menu item is sensitive or not + * priority (boolean) - used for toolbar items, whether to show priority + * text. + */ + + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-menu-provider.c b/libnautilus-extension/nautilus-menu-provider.c new file mode 100644 index 000000000..956c5ec0e --- /dev/null +++ b/libnautilus-extension/nautilus-menu-provider.c @@ -0,0 +1,110 @@ +/* + * nautilus-property-page-provider.c - Interface for Nautilus extensions + * that provide context menu items + * for files. + * + * 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-menu-provider.h" + +#include <glib-object.h> + +static void +nautilus_menu_provider_base_init (gpointer g_class) +{ +} + +GType +nautilus_menu_provider_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusMenuProviderIface), + nautilus_menu_provider_base_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "NautilusMenuProvider", + &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} + +GList * +nautilus_menu_provider_get_file_items (NautilusMenuProvider *provider, + GtkWidget *window, + GList *files) +{ + g_return_val_if_fail (NAUTILUS_IS_MENU_PROVIDER (provider), NULL); + + if (NAUTILUS_MENU_PROVIDER_GET_IFACE (provider)->get_file_items) { + return NAUTILUS_MENU_PROVIDER_GET_IFACE (provider)->get_file_items + (provider, window, files); + } else { + return NULL; + } +} + +GList * +nautilus_menu_provider_get_background_items (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *current_folder) +{ + g_return_val_if_fail (NAUTILUS_IS_MENU_PROVIDER (provider), NULL); + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (current_folder), NULL); + + if (NAUTILUS_MENU_PROVIDER_GET_IFACE (provider)->get_background_items) { + return NAUTILUS_MENU_PROVIDER_GET_IFACE (provider)->get_background_items + (provider, window, current_folder); + } else { + return NULL; + } +} + +GList * +nautilus_menu_provider_get_toolbar_items (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *current_folder) +{ + g_return_val_if_fail (NAUTILUS_IS_MENU_PROVIDER (provider), NULL); + g_return_val_if_fail (NAUTILUS_IS_FILE_INFO (current_folder), NULL); + + if (NAUTILUS_MENU_PROVIDER_GET_IFACE (provider)->get_toolbar_items) { + return NAUTILUS_MENU_PROVIDER_GET_IFACE (provider)->get_toolbar_items + (provider, window, current_folder); + } else { + return NULL; + } +} + + diff --git a/libnautilus-extension/nautilus-menu-provider.h b/libnautilus-extension/nautilus-menu-provider.h new file mode 100644 index 000000000..a7a9a2470 --- /dev/null +++ b/libnautilus-extension/nautilus-menu-provider.h @@ -0,0 +1,77 @@ +/* + * nautilus-menu-provider.h - Interface for Nautilus extensions that + * provide context menu items. + * + * 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> + * + */ + +/* This interface is implemented by Nautilus extensions that want to + * add context menu entries to files. Extensions are called when + * Nautilus constructs the context menu for a file. They are passed a + * list of NautilusFileInfo objects which holds the current selection */ + +#ifndef NAUTILUS_MENU_PROVIDER_H +#define NAUTILUS_MENU_PROVIDER_H + +#include <glib-object.h> +#include <gtk/gtkwidget.h> +#include "nautilus-extension-types.h" +#include "nautilus-file-info.h" +#include "nautilus-menu-item.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_MENU_PROVIDER (nautilus_menu_provider_get_type ()) +#define NAUTILUS_MENU_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_MENU_PROVIDER, NautilusMenuProvider)) +#define NAUTILUS_IS_MENU_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_MENU_PROVIDER)) +#define NAUTILUS_MENU_PROVIDER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NAUTILUS_TYPE_MENU_PROVIDER, NautilusMenuProviderIface)) + +typedef struct _NautilusMenuProvider NautilusMenuProvider; +typedef struct _NautilusMenuProviderIface NautilusMenuProviderIface; + +struct _NautilusMenuProviderIface { + GTypeInterface g_iface; + + GList *(*get_file_items) (NautilusMenuProvider *provider, + GtkWidget *window, + GList *files); + GList *(*get_background_items) (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *current_folder); + GList *(*get_toolbar_items) (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *current_folder); +}; + +/* Interface Functions */ +GType nautilus_menu_provider_get_type (void); +GList *nautilus_menu_provider_get_file_items (NautilusMenuProvider *provider, + GtkWidget *window, + GList *files); +GList *nautilus_menu_provider_get_background_items (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *current_folder); +GList *nautilus_menu_provider_get_toolbar_items (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *current_folder); + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-property-page-provider.c b/libnautilus-extension/nautilus-property-page-provider.c new file mode 100644 index 000000000..90e6b5594 --- /dev/null +++ b/libnautilus-extension/nautilus-property-page-provider.c @@ -0,0 +1,74 @@ +/* + * nautilus-property-page-provider.c - Interface for Nautilus extensions + * that provide property pages for + * files. + * + * 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-property-page-provider.h" + +#include <glib-object.h> + +static void +nautilus_property_page_provider_base_init (gpointer g_class) +{ +} + +GType +nautilus_property_page_provider_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusPropertyPageProviderIface), + nautilus_property_page_provider_base_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "NautilusPropertyPageProvider", + &info, 0); + g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); + } + + return type; +} + +GList * +nautilus_property_page_provider_get_pages (NautilusPropertyPageProvider *provider, + GList *files) +{ + g_return_val_if_fail (NAUTILUS_IS_PROPERTY_PAGE_PROVIDER (provider), NULL); + g_return_val_if_fail (NAUTILUS_PROPERTY_PAGE_PROVIDER_GET_IFACE (provider)->get_pages != NULL, NULL); + + return NAUTILUS_PROPERTY_PAGE_PROVIDER_GET_IFACE (provider)->get_pages + (provider, files); +} + + diff --git a/libnautilus-extension/nautilus-property-page-provider.h b/libnautilus-extension/nautilus-property-page-provider.h new file mode 100644 index 000000000..56eada183 --- /dev/null +++ b/libnautilus-extension/nautilus-property-page-provider.h @@ -0,0 +1,63 @@ +/* + * nautilus-property-page-provider.h - Interface for Nautilus extensions + * that provide property pages. + * + * 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> + * + */ + +/* This interface is implemented by Nautilus extensions that want to + * add property page to property dialogs. Extensions are called when + * Nautilus needs property pages for a selection. They are passed a + * list of NautilusFileInfo objects for which information should + * be displayed */ + +#ifndef NAUTILUS_PROPERTY_PAGE_PROVIDER_H +#define NAUTILUS_PROPERTY_PAGE_PROVIDER_H + +#include <glib-object.h> +#include "nautilus-extension-types.h" +#include "nautilus-file-info.h" +#include "nautilus-property-page.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER (nautilus_property_page_provider_get_type ()) +#define NAUTILUS_PROPERTY_PAGE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER, NautilusPropertyPageProvider)) +#define NAUTILUS_IS_PROPERTY_PAGE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER)) +#define NAUTILUS_PROPERTY_PAGE_PROVIDER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER, NautilusPropertyPageProviderIface)) + +typedef struct _NautilusPropertyPageProvider NautilusPropertyPageProvider; +typedef struct _NautilusPropertyPageProviderIface NautilusPropertyPageProviderIface; + +struct _NautilusPropertyPageProviderIface { + GTypeInterface g_iface; + + GList *(*get_pages) (NautilusPropertyPageProvider *provider, + GList *files); +}; + +/* Interface Functions */ +GType nautilus_property_page_provider_get_type (void); +GList *nautilus_property_page_provider_get_pages (NautilusPropertyPageProvider *provider, + GList *files); + +G_END_DECLS + +#endif diff --git a/libnautilus-extension/nautilus-property-page.c b/libnautilus-extension/nautilus-property-page.c new file mode 100644 index 000000000..e27a82b44 --- /dev/null +++ b/libnautilus-extension/nautilus-property-page.c @@ -0,0 +1,221 @@ +/* + * nautilus-property-page.h - Property pages exported by + * NautilusPropertyProvider objects. + * + * 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-property-page.h" + +#include "nautilus-extension-i18n.h" + +enum { + PROP_0, + PROP_NAME, + PROP_LABEL, + PROP_PAGE, + LAST_PROP +}; + + +struct _NautilusPropertyPageDetails { + char *name; + GtkWidget *label; + GtkWidget *page; +}; + +NautilusPropertyPage * +nautilus_property_page_new (const char *name, + GtkWidget *label, + GtkWidget *page_widget) +{ + NautilusPropertyPage *page; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (label != NULL && GTK_IS_WIDGET (label), NULL); + g_return_val_if_fail (page_widget != NULL && GTK_IS_WIDGET (page_widget), + NULL); + + page = g_object_new (NAUTILUS_TYPE_PROPERTY_PAGE, + "name", name, + "label", label, + "page", page_widget, + NULL); + + return page; +} + +static void +nautilus_property_page_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusPropertyPage *page; + + page = NAUTILUS_PROPERTY_PAGE (object); + + switch (param_id) { + case PROP_NAME : + g_value_set_string (value, page->details->name); + break; + case PROP_LABEL : + g_value_set_object (value, page->details->label); + break; + case PROP_PAGE : + g_value_set_object (value, page->details->page); + break; + default : + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_property_page_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + NautilusPropertyPage *page; + + page = NAUTILUS_PROPERTY_PAGE (object); + + switch (param_id) { + case PROP_NAME : + g_free (page->details->name); + page->details->name = g_strdup (g_value_get_string (value)); + g_object_notify (object, "name"); + break; + case PROP_LABEL : + if (page->details->label) { + g_object_unref (page->details->label); + } + + page->details->label = g_object_ref (g_value_get_object (value)); + g_object_notify (object, "label"); + break; + case PROP_PAGE : + if (page->details->page) { + g_object_unref (page->details->page); + } + + page->details->page = g_object_ref (g_value_get_object (value)); + g_object_notify (object, "page"); + break; + default : + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_property_page_dispose (GObject *object) +{ + NautilusPropertyPage *page; + + page = NAUTILUS_PROPERTY_PAGE (object); + + if (page->details->label) { + g_object_unref (page->details->label); + page->details->label = NULL; + } + if (page->details->page) { + g_object_unref (page->details->page); + page->details->page = NULL; + } +} + +static void +nautilus_property_page_finalize (GObject *object) +{ + NautilusPropertyPage *page; + + page = NAUTILUS_PROPERTY_PAGE (object); + + g_free (page->details->name); + + g_free (page->details); +} + +static void +nautilus_property_page_instance_init (NautilusPropertyPage *page) +{ + page->details = g_new0 (NautilusPropertyPageDetails, 1); +} + +static void +nautilus_property_page_class_init (NautilusPropertyPageClass *class) +{ + G_OBJECT_CLASS (class)->finalize = nautilus_property_page_finalize; + G_OBJECT_CLASS (class)->dispose = nautilus_property_page_dispose; + G_OBJECT_CLASS (class)->get_property = nautilus_property_page_get_property; + G_OBJECT_CLASS (class)->set_property = nautilus_property_page_set_property; + + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_NAME, + g_param_spec_string ("name", + _("Name"), + _("Name of the page"), + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_LABEL, + g_param_spec_object ("label", + _("Label"), + _("Label widget to display in the notebook tab"), + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (class), + PROP_PAGE, + g_param_spec_object ("page", + _("Page"), + _("Widget for the property page"), + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); +} + +GType +nautilus_property_page_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (NautilusPropertyPageClass), + NULL, + NULL, + (GClassInitFunc)nautilus_property_page_class_init, + NULL, + NULL, + sizeof (NautilusPropertyPage), + 0, + (GInstanceInitFunc)nautilus_property_page_instance_init + }; + + type = g_type_register_static + (G_TYPE_OBJECT, + "NautilusPropertPage", + &info, 0); + } + + return type; +} diff --git a/libnautilus-extension/nautilus-property-page.h b/libnautilus-extension/nautilus-property-page.h new file mode 100644 index 000000000..944bd2390 --- /dev/null +++ b/libnautilus-extension/nautilus-property-page.h @@ -0,0 +1,70 @@ +/* + * nautilus-property-page.h - Property pages exported by + * NautilusPropertyProvider objects. + * + * 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_PROPERTY_PAGE_H +#define NAUTILUS_PROPERTY_PAGE_H + +#include <glib-object.h> +#include <gtk/gtkwidget.h> +#include "nautilus-extension-types.h" + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_PROPERTY_PAGE (nautilus_property_page_get_type()) +#define NAUTILUS_PROPERTY_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_PROPERTY_PAGE, NautilusPropertyPage)) +#define NAUTILUS_PROPERTY_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_PROPERTY_PAGE, NautilusPropertyPageClass)) +#define NAUTILUS_PROPERTY_IS_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_PROPERTY_PAGE)) +#define NAUTILUS_PROPERTY_IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NAUTILUS_TYPE_PROPERTY_PAGE)) +#define NAUTILUS_PROPERTY_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NAUTILUS_TYPE_PROPERTY_PAGE, NautilusPropertyPageClass)) + +typedef struct _NautilusPropertyPage NautilusPropertyPage; +typedef struct _NautilusPropertyPageDetails NautilusPropertyPageDetails; +typedef struct _NautilusPropertyPageClass NautilusPropertyPageClass; + +struct _NautilusPropertyPage +{ + GObject parent; + + NautilusPropertyPageDetails *details; +}; + +struct _NautilusPropertyPageClass +{ + GObjectClass parent; +}; + +GType nautilus_property_page_get_type (void); +NautilusPropertyPage *nautilus_property_page_new (const char *name, + GtkWidget *label, + GtkWidget *page); + +/* NautilusPropertyPage has the following properties: + * name (string) - the identifier for the property page + * label (widget) - the user-visible label of the property page + * page (widget) - the property page to display + */ + +G_END_DECLS + +#endif 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 diff --git a/src/file-manager/Makefile.am b/src/file-manager/Makefile.am index 614dcaa03..a45a4ad5b 100644 --- a/src/file-manager/Makefile.am +++ b/src/file-manager/Makefile.am @@ -15,6 +15,7 @@ INCLUDES = \ libnautilus_file_manager_la_SOURCES= \ + fm-bonobo-provider.c \ fm-desktop-icon-view.c \ fm-directory-view.c \ fm-error-reporting.c \ @@ -27,6 +28,7 @@ libnautilus_file_manager_la_SOURCES= \ nautilus-indexing-info.c \ fm-tree-model.c \ fm-tree-view.c \ + fm-bonobo-provider.h \ fm-desktop-icon-view.h \ fm-directory-view.h \ fm-error-reporting.h \ diff --git a/src/file-manager/fm-bonobo-provider.c b/src/file-manager/fm-bonobo-provider.c new file mode 100644 index 000000000..fcc985f71 --- /dev/null +++ b/src/file-manager/fm-bonobo-provider.c @@ -0,0 +1,629 @@ +/* + * fm-bonobo-provider.h - Bonobo API support + * + * Copyright (C) 2002 James Willcox + * 2003 Novell, Inc. + * + * This library 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 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 General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: James Willcox <james@gnome.org> + * Dave Camp <dave@ximian.com> + * + */ + +/* This object exports the bonobo context menus and property pages + * using the new extension interface. */ + +#include <config.h> +#include "fm-bonobo-provider.h" + +#include <string.h> + +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-exception.h> +#include <bonobo/bonobo-property-bag-client.h> +#include <bonobo/bonobo-ui-util.h> +#include <bonobo/bonobo-widget.h> +#include <bonobo/bonobo-window.h> +#include <bonobo/bonobo-zoomable.h> +#include <eel/eel-glib-extensions.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkimage.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkmessagedialog.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkvbox.h> +#include <libgnome/gnome-i18n.h> +#include <libgnomeui/gnome-uidefs.h> +#include <libnautilus-extension/nautilus-extension-types.h> +#include <libnautilus-extension/nautilus-file-info.h> +#include <libnautilus-extension/nautilus-menu-provider.h> +#include <libnautilus-extension/nautilus-property-page-provider.h> +#include <libnautilus-private/nautilus-mime-actions.h> +#include <libnautilus-private/nautilus-view-identifier.h> + +typedef struct { + char *id; + char *verb; + CORBA_sequence_CORBA_string *uri_list; +} BonoboMimeActionData; + + +typedef struct { + GList *files; + GtkWidget *vbox; + char *view_name; +} ActivationData; + +static void fm_bonobo_provider_instance_init (FMBonoboProvider *provider); +static void fm_bonobo_provider_class_init (FMBonoboProviderClass *class); + +static GObjectClass *parent_class; + +static BonoboMimeActionData * +bonobo_mime_action_data_new (const char *id, const char *verb, GList *files) +{ + BonoboMimeActionData *data; + CORBA_sequence_CORBA_string *uri_list; + int i; + + data = g_new (BonoboMimeActionData, 1); + data->id = g_strdup (id); + data->verb = g_strdup (verb); + + /* convert the GList of files into a CORBA sequence */ + + uri_list = CORBA_sequence_CORBA_string__alloc (); + uri_list->_maximum = g_list_length (files); + uri_list->_length = uri_list->_maximum; + uri_list->_buffer = CORBA_sequence_CORBA_string_allocbuf (uri_list->_length); + + for (i=0; files; files = files->next, i++) + { + NautilusFile *file; + char *uri; + + file = files->data; + uri = nautilus_file_get_uri (file); + + uri_list->_buffer[i] = CORBA_string_dup ((char*)uri); + + g_free (uri); + } + + CORBA_sequence_set_release (uri_list, CORBA_TRUE); + data->uri_list = uri_list; + + + return data; +} + +static void +bonobo_mime_action_data_free (BonoboMimeActionData *data) +{ + g_free (data->id); + g_free (data->verb); + g_free (data); +} + +static void +bonobo_mime_action_activate_callback (CORBA_Object obj, + const char *error_reason, + gpointer user_data) +{ + Bonobo_Listener listener; + CORBA_Environment ev; + BonoboMimeActionData *data; + CORBA_any any; + + data = user_data; + + if (obj == CORBA_OBJECT_NIL) { + GtkWidget *dialog; + + /* FIXME: make an error message that is not so lame */ + dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Could not complete specified action: %s"), error_reason); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_widget_show (dialog); + return; + } + + CORBA_exception_init (&ev); + + listener = Bonobo_Unknown_queryInterface (obj, + "IDL:Bonobo/Listener:1.0", + &ev); + + if (!BONOBO_EX (&ev)) { + any._type = TC_CORBA_sequence_CORBA_string; + any._value = data->uri_list; + Bonobo_Listener_event (listener, data->verb, &any, &ev); + bonobo_object_release_unref (listener, &ev); + } else { + GtkWidget *dialog; + + /* FIXME: make an error message that is not so lame */ + dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Could not complete specified action.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_widget_show (dialog); + } + +} + +static void +bonobo_mime_action_callback (NautilusMenuItem *item, + gpointer callback_data) +{ + BonoboMimeActionData *data; + + data = callback_data; + + bonobo_activation_activate_from_id_async (data->id, 0, + bonobo_mime_action_activate_callback, + data, NULL); + +} + +static void +bonobo_mime_action_menu_data_destroy_callback (gpointer data, GClosure *closure) +{ + bonobo_mime_action_data_free ((BonoboMimeActionData *)data); +} + +static gboolean +no_locale_at_end (const char *str) +{ + int len; + + len = strlen (str); + if (len > 3 && + str[len-3] == '-' && + g_ascii_isalpha (str[len-2]) && + g_ascii_isalpha (str[len-1])) { + return FALSE; + } + if (len > 6 && + str[len-6] == '-' && + g_ascii_isalpha (str[len-5]) && + g_ascii_isalpha (str[len-4]) && + str[len-3] == '_' && + g_ascii_isalpha (str[len-2]) && + g_ascii_isalpha (str[len-1])) { + return FALSE; + } + return TRUE; +} + +static GList * +get_bonobo_menu_verb_names (Bonobo_ServerInfo *info) +{ + GList *l; + unsigned int i; + int offset; + + offset = strlen ("nautilusverb:"); + + l = NULL; + for (i = 0; i < info->props._length; i++) { + + /* look for properties that start with "nautilusverb:". The + * part following the colon is the verb name + */ + if (strstr (info->props._buffer[i].name, "nautilusverb:") && + no_locale_at_end (info->props._buffer[i].name)) { + l = g_list_prepend (l, + g_strdup (&info->props._buffer[i].name[offset])); + } + } + + return l; +} + +static gboolean +can_handle_multiple_files (Bonobo_ServerInfo *info) +{ + Bonobo_ActivationProperty *prop; + + prop = bonobo_server_info_prop_find (info, "nautilus:can_handle_multiple_files"); + return prop->v._u.value_boolean; +} + +static GList * +get_menu_items_for_server (Bonobo_ServerInfo *info, + GList *verb_names, + GList *files) +{ + GList *items; + GList *l; + const GList *langs; + GSList *langs_cpy; + + langs = gnome_i18n_get_language_list ("LANG"); + langs_cpy = NULL; + /* copy it to a singly linked list since bonobo wants that...sigh */ + for (; langs; langs = langs->next) { + langs_cpy = g_slist_append (langs_cpy, langs->data); + } + + items = NULL; + + /* build the commands */ + for (l = verb_names; l; l = l->next) { + NautilusMenuItem *item; + BonoboMimeActionData *data; + char *verb; + char *prop_name; + const char *label; + const char *icon_name; + GClosure *closure; + + verb = l->data; + + prop_name = g_strdup_printf ("nautilusverb:%s", verb); + label = bonobo_server_info_prop_lookup (info, prop_name, + langs_cpy); + g_free (prop_name); + + prop_name = g_strdup_printf ("nautilusverbicon:%s", verb); + icon_name = bonobo_server_info_prop_lookup (info, prop_name, + langs_cpy); + g_free (prop_name); + if (!icon_name) { + icon_name = bonobo_server_info_prop_lookup (info, "nautilus:icon", + langs_cpy); + } + + data = bonobo_mime_action_data_new (info->iid, + verb, files); + closure = g_cclosure_new + (G_CALLBACK (bonobo_mime_action_callback), + data, + bonobo_mime_action_menu_data_destroy_callback); + + item = nautilus_menu_item_new (verb, + label, + "", /* no tip for bonobo items */ + icon_name); + g_signal_connect_data (item, "activate", + G_CALLBACK (bonobo_mime_action_callback), + data, + bonobo_mime_action_menu_data_destroy_callback, + 0); + items = g_list_prepend (items, item); + } + items = g_list_reverse (items); + + g_slist_free (langs_cpy); + + /* if it doesn't handle multiple files, disable the menu items */ + if ((g_list_length (files) > 1) && + (can_handle_multiple_files (info) == FALSE)) { + GList *l; + + for (l = items; l != NULL; l = l->next) { + g_object_set (l->data, "sensitive", FALSE, NULL); + } + } + + return items; +} + +static GList * +fm_bonobo_provider_get_file_items (NautilusMenuProvider *provider, + GtkWidget *window, + GList *selection) +{ + GList *components; + GList *items; + GList *l; + + components = nautilus_mime_get_popup_components_for_files (selection); + + items = NULL; + for (l = components; l; l = l->next) { + Bonobo_ServerInfo *info; + GList *verb_names; + + info = l->data; + verb_names = get_bonobo_menu_verb_names (info); + items = g_list_concat (items, + get_menu_items_for_server (info, verb_names, selection)); + eel_g_list_free_deep (verb_names); + + } + + if (components != NULL) { + gnome_vfs_mime_component_list_free (components); + } + + return items; +} + +static void +fm_bonobo_provider_menu_provider_iface_init (NautilusMenuProviderIface *iface) +{ + iface->get_file_items = fm_bonobo_provider_get_file_items; +} + +static GtkWidget * +bonobo_page_error_message (const char *view_name, + const char *msg) +{ + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *image; + + hbox = gtk_hbox_new (FALSE, GNOME_PAD); + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, + GTK_ICON_SIZE_DIALOG); + + msg = g_strdup_printf ("There was an error while trying to create the view named `%s': %s", view_name, msg); + label = gtk_label_new (msg); + + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_widget_show_all (hbox); + + return hbox; +} + +static CORBA_sequence_CORBA_string * +get_uri_list (GList *file_list) +{ + CORBA_sequence_CORBA_string *uri_list; + GList *l; + int i; + + uri_list = CORBA_sequence_CORBA_string__alloc (); + uri_list->_maximum = g_list_length (file_list); + uri_list->_length = uri_list->_maximum; + uri_list->_buffer = CORBA_sequence_CORBA_string_allocbuf (uri_list->_length); + for (i = 0, l = file_list; l != NULL; i++, l = l->next) { + char *uri; + + uri = nautilus_file_get_uri (NAUTILUS_FILE (l->data)); + uri_list->_buffer[i] = CORBA_string_dup (uri); + g_free (uri); + } + + return uri_list; +} + +static void +bonobo_page_activate_callback (CORBA_Object obj, + const char *error_reason, + gpointer user_data) +{ + ActivationData *data; + GtkWidget *widget; + CORBA_Environment ev; + + data = (ActivationData *)user_data; + + CORBA_exception_init (&ev); + widget = NULL; + + if (obj != CORBA_OBJECT_NIL) { + Bonobo_Control control; + Bonobo_PropertyBag pb; + GList *keys; + + control = Bonobo_Unknown_queryInterface + (obj, "IDL:Bonobo/Control:1.0", &ev); + + pb = Bonobo_Control_getProperties (control, &ev); + + if (!BONOBO_EX (&ev)) { + gboolean new_property; + + keys = bonobo_pbclient_get_keys (pb, NULL); + new_property = FALSE; + if (g_list_find_custom (keys, "uris", (GCompareFunc)strcmp)) { + new_property = TRUE; + } + bonobo_pbclient_free_keys (keys); + + if (new_property) { + /* Set the 'uris' property. */ + CORBA_sequence_CORBA_string *uri_list; + BonoboArg *arg; + + uri_list = get_uri_list (data->files); + arg = bonobo_arg_new (TC_CORBA_sequence_CORBA_string); + arg->_value = uri_list; + bonobo_pbclient_set_value_async (pb, "uris", arg, &ev); + bonobo_arg_release (arg); + } else { + /* Set the 'URI' property. */ + BonoboArg *arg; + char *uri; + + if (data->files->next != NULL) { + g_warning ("Multifile property page does not support the 'uris' property"); + bonobo_object_release_unref (pb, NULL); + bonobo_object_release_unref (control, NULL); + return; + } + + uri = nautilus_file_info_get_uri (NAUTILUS_FILE_INFO (data->files->data)); + + arg = bonobo_arg_new (BONOBO_ARG_STRING); + BONOBO_ARG_SET_STRING (arg, uri); + bonobo_pbclient_set_value_async (pb, "URI", arg, &ev); + bonobo_arg_release (arg); + g_free (uri); + } + + bonobo_object_release_unref (pb, NULL); + + if (!BONOBO_EX (&ev)) { + widget = bonobo_widget_new_control_from_objref + (control, CORBA_OBJECT_NIL); + bonobo_object_release_unref (control, &ev); + } + } + } + + if (widget == NULL) { + widget = bonobo_page_error_message (data->view_name, + error_reason); + } + + gtk_container_add (GTK_CONTAINER (data->vbox), widget); + gtk_widget_show (widget); + + g_free (data->view_name); + g_free (data); +} + +static GList * +fm_bonobo_provider_get_pages (NautilusPropertyPageProvider *provider, + GList *files) +{ + GList *all_components, *l; + GList *components; + CORBA_Environment ev; + GList *pages; + + /* find all the property pages for this file */ + all_components = nautilus_mime_get_property_components_for_files + (files); + + /* filter out property pages that don't support multiple files */ + if (files->next) { + components = NULL; + for (l = all_components; l != NULL; l = l->next) { + if (can_handle_multiple_files (l->data)) { + components = g_list_prepend (components, + l->data); + } + } + components = g_list_reverse (components); + g_list_free (all_components); + } else { + components = all_components; + } + + CORBA_exception_init (&ev); + + pages = NULL; + + l = components; + while (l != NULL) { + NautilusViewIdentifier *view_id; + Bonobo_ServerInfo *server; + ActivationData *data; + GtkWidget *vbox; + NautilusPropertyPage *page; + + server = l->data; + l = l->next; + + view_id = nautilus_view_identifier_new_from_property_page (server); + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (vbox), + GNOME_PAD); + gtk_widget_show (vbox); + + page = nautilus_property_page_new (view_id->iid, + gtk_label_new (view_id->name), + vbox); + + pages = g_list_prepend (pages, page); + + data = g_new (ActivationData, 1); + data->files = nautilus_file_info_list_copy (files); + data->vbox = vbox; + data->view_name = g_strdup (view_id->name); + + bonobo_activation_activate_from_id_async + (view_id->iid, + 0, bonobo_page_activate_callback, + data, &ev); + } + + return g_list_reverse (pages); +} + +static void +fm_bonobo_provider_property_page_provider_iface_init (NautilusPropertyPageProviderIface *iface) +{ + iface->get_pages = fm_bonobo_provider_get_pages; +} + +static void +fm_bonobo_provider_instance_init (FMBonoboProvider *provider) +{ +} + +static void +fm_bonobo_provider_class_init (FMBonoboProviderClass *class) +{ + parent_class = g_type_class_peek_parent (class); +} + +GType +fm_bonobo_provider_get_type (void) +{ + static GType provider_type = 0; + + if (!provider_type) { + static const GTypeInfo type_info = { + sizeof (FMBonoboProviderClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) fm_bonobo_provider_class_init, + NULL, + NULL, + sizeof (FMBonoboProvider), + 0, + (GInstanceInitFunc) fm_bonobo_provider_instance_init, + }; + + static const GInterfaceInfo menu_provider_iface_info = { + (GInterfaceInitFunc) fm_bonobo_provider_menu_provider_iface_init, + NULL, + NULL + }; + + static const GInterfaceInfo property_page_provider_iface_info = { + (GInterfaceInitFunc) fm_bonobo_provider_property_page_provider_iface_init, + NULL, + NULL + }; + + provider_type = g_type_register_static (G_TYPE_OBJECT, + "FMBonoboProvider", + &type_info, 0); + + g_type_add_interface_static (provider_type, + NAUTILUS_TYPE_MENU_PROVIDER, + &menu_provider_iface_info); + g_type_add_interface_static (provider_type, + NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER, + &property_page_provider_iface_info); + } + + return provider_type; +} + diff --git a/src/file-manager/fm-bonobo-provider.h b/src/file-manager/fm-bonobo-provider.h new file mode 100644 index 000000000..10d7be1c0 --- /dev/null +++ b/src/file-manager/fm-bonobo-provider.h @@ -0,0 +1,51 @@ +/* + * fm-bonobo-provider.h - Bonobo API support + * + * Copyright (C) 2002 James Willcox + * 2003 Novell, Inc. + * + * This library 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 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 General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Dave Camp <dave@ximian.com> + * James Willcox <james@gnome.org> + * + */ + +#ifndef FM_BONOBO_PROVIDER_H +#define FM_BONOBO_PROVIDER_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define FM_TYPE_BONOBO_PROVIDER (fm_bonobo_provider_get_type ()) +#define FM_BONOBO_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FM_TYPE_BONOBO_PROVIDER, FMBonoboProvider)) +#define FM_IS_BONOBO_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), FM_TYPE_BONOBO_PROVIDER)) +typedef struct _FMBonoboProvider FMBonoboProvider; +typedef struct _FMBonoboProviderClass FMBonoboProviderClass; + +struct _FMBonoboProvider { + GObject parent_slot; +}; + +struct _FMBonoboProviderClass { + GObjectClass parent_slot; +}; + +GType fm_bonobo_provider_get_type (void); + +G_END_DECLS + +#endif diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index 4de21aff9..336a8fad7 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -69,6 +69,7 @@ #include <libgnomevfs/gnome-vfs-utils.h> #include <libnautilus-private/nautilus-recent.h> #include <libegg/egg-screen-exec.h> +#include <libnautilus-extension/nautilus-menu-provider.h> #include <libnautilus-private/nautilus-bonobo-extensions.h> #include <libnautilus-private/nautilus-desktop-icon-file.h> #include <libnautilus-private/nautilus-desktop-directory.h> @@ -83,6 +84,7 @@ #include <libnautilus-private/nautilus-link.h> #include <libnautilus-private/nautilus-metadata.h> #include <libnautilus-private/nautilus-mime-actions.h> +#include <libnautilus-private/nautilus-module.h> #include <libnautilus-private/nautilus-program-choosing.h> #include <libnautilus-private/nautilus-trash-directory.h> #include <libnautilus-private/nautilus-trash-monitor.h> @@ -157,7 +159,8 @@ #define FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_SEPARATOR "/menu/File/New Items Placeholder/New Documents/After New Documents" #define FM_DIRECTORY_VIEW_MENU_PATH_CUT_FILES "/menu/Edit/Cut" #define FM_DIRECTORY_VIEW_MENU_PATH_COPY_FILES "/menu/Edit/Copy" -#define FM_DIRECTORY_VIEW_MENU_PATH_PASTE_FILES "/menu/File/Paste" +#define FM_DIRECTORY_VIEW_MENU_PATH_PASTE_FILES "/menu/Edit/Paste" +#define FM_DIRECTORY_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER "/menu/Edit/Extension Actions" #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND "/popups/background" #define FM_DIRECTORY_VIEW_POPUP_PATH_SELECTION "/popups/selection" @@ -177,7 +180,7 @@ #define FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_SEPARATOR "/popups/selection/Open Placeholder/Scripts/After Scripts" #define FM_DIRECTORY_VIEW_POPUP_PATH_OPEN_WITH "/popups/selection/Open Placeholder/Open With" #define FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS "/popups/selection/Open Placeholder/Scripts" -#define FM_DIRECTORY_VIEW_POPUP_PATH_MIME_ACTIONS "/popups/selection/Mime Actions" +#define FM_DIRECTORY_VIEW_POPUP_PATH_EXTENSION_ACTIONS "/popups/selection/Extension Actions" #define MAX_MENU_LEVELS 5 @@ -286,12 +289,6 @@ typedef struct { gboolean cancelled; } ActivateParameters; -typedef struct { - char *id; - char *verb; - CORBA_sequence_CORBA_string *uri_list; -} BonoboMimeActionData; - enum { GNOME_COPIED_FILES }; @@ -3846,308 +3843,27 @@ reset_bonobo_open_with_menu (FMDirectoryView *view, GList *selection) sensitive); } -static BonoboMimeActionData * -bonobo_mime_action_data_new (const char *id, const char *verb, GList *files) -{ - BonoboMimeActionData *data; - CORBA_sequence_CORBA_string *uri_list; - int i; - - data = g_new (BonoboMimeActionData, 1); - data->id = g_strdup (id); - data->verb = g_strdup (verb); - - - /* convert the GList of files into a CORBA sequence */ - - uri_list = CORBA_sequence_CORBA_string__alloc (); - uri_list->_maximum = g_list_length (files); - uri_list->_length = uri_list->_maximum; - uri_list->_buffer = CORBA_sequence_CORBA_string_allocbuf (uri_list->_length); - - for (i=0; files; files = files->next, i++) - { - NautilusFile *file; - char *uri; - - file = files->data; - uri = nautilus_file_get_uri (file); - - uri_list->_buffer[i] = CORBA_string_dup ((char*)uri); - - g_free (uri); - } - - CORBA_sequence_set_release (uri_list, CORBA_TRUE); - data->uri_list = uri_list; - - - return data; -} - static void -bonobo_mime_action_data_free (BonoboMimeActionData *data) -{ - g_free (data->id); - g_free (data->verb); - g_free (data); -} - - -static void -bonobo_mime_action_activate_callback (CORBA_Object obj, - const char *error_reason, - gpointer user_data) -{ - Bonobo_Listener listener; - CORBA_Environment ev; - BonoboMimeActionData *data; - CORBA_any any; - - data = user_data; - - if (obj == CORBA_OBJECT_NIL) { - GtkWidget *dialog; - - /* FIXME: make an error message that is not so lame */ - dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Could not complete specified action: %s"), error_reason); - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_widget_destroy), NULL); - gtk_widget_show (dialog); - return; - } - - CORBA_exception_init (&ev); - - listener = Bonobo_Unknown_queryInterface (obj, - "IDL:Bonobo/Listener:1.0", - &ev); - - if (!BONOBO_EX (&ev)) { - any._type = TC_CORBA_sequence_CORBA_string; - any._value = data->uri_list; - Bonobo_Listener_event (listener, data->verb, &any, &ev); - bonobo_object_release_unref (listener, &ev); - } else { - GtkWidget *dialog; - - /* FIXME: make an error message that is not so lame */ - dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Could not complete specified action.")); - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_widget_destroy), NULL); - gtk_widget_show (dialog); - } - -} - - -static void -bonobo_mime_action_callback (BonoboUIComponent *component, - gpointer callback_data, const char *path) -{ - BonoboMimeActionData *data; - - data = callback_data; - - bonobo_activation_activate_from_id_async (data->id, 0, - bonobo_mime_action_activate_callback, - data, NULL); - -} - -static void -bonobo_mime_action_menu_data_destroy_callback (gpointer data, GClosure *closure) -{ - bonobo_mime_action_data_free ((BonoboMimeActionData *)data); -} - -static gboolean -can_handle_multiple_files (Bonobo_ServerInfo *info) -{ - Bonobo_ActivationProperty *prop; - - prop = bonobo_server_info_prop_find (info, "nautilus:can_handle_multiple_files"); - return prop->v._u.value_boolean; -} - -static void -add_bonobo_menu_ui_and_verbs (FMDirectoryView *view, GList *files, - Bonobo_ServerInfo *info, GList *verb_names) +add_extension_menu_items (FMDirectoryView *view, + GList *files, + GList *menu_items) { GList *l; - GString *ui_xml; - const GList *langs; - GSList *langs_cpy; - char *ui_xml_str; - - g_return_if_fail (verb_names != NULL); - - langs = gnome_i18n_get_language_list ("LANG"); - langs_cpy = NULL; - /* copy it to a singly linked list since bonobo wants that...sigh */ - for (; langs; langs = langs->next) { - langs_cpy = g_slist_append (langs_cpy, langs->data); - } - - ui_xml = g_string_new ("<Root><commands>"); - - /* build the commands */ - for (l = verb_names; l; l = l->next) { - const char *label; - char *prop_name; - char *verb; - - verb = l->data; - - prop_name = g_strdup_printf ("nautilusverb:%s", verb); - label = bonobo_server_info_prop_lookup (info, prop_name, - langs_cpy); - g_free (prop_name); - - g_string_append_printf (ui_xml, "<cmd name=\"%s\" label=\"%s\"/>", verb, label); - } - - ui_xml = g_string_append (ui_xml, "</commands><popups><popup name=\"selection\"><placeholder name=\"Mime Actions\"><separator/>"); - - /* build the UI */ - for (l = verb_names; l; l = l->next) { - char *verb = l->data; - char *icon_attribute_name; - const char *icon_name; - char *pixbuf_data; - GdkPixbuf *pixbuf; - - g_string_append_printf (ui_xml, - "<menuitem name=\"%s\" verb=\"%s\"", - verb, verb); - - icon_attribute_name = g_strdup_printf ("nautilusverbicon:%s", - verb); - icon_name = bonobo_server_info_prop_lookup (info, - icon_attribute_name, - langs_cpy); - g_free (icon_attribute_name); - if (!icon_name) { - icon_name = bonobo_server_info_prop_lookup (info, "nautilus:icon", - langs_cpy); - } - - if (icon_name) { - pixbuf = nautilus_icon_factory_get_pixbuf_from_name - (icon_name, - 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_slist_free (langs_cpy); - - ui_xml = g_string_append (ui_xml, "</placeholder></popup></popups></Root>"); - ui_xml_str = g_string_free (ui_xml, FALSE); - - bonobo_ui_component_set (view->details->ui, "/", - ui_xml_str, NULL); - g_free (ui_xml_str); - - /* if it doesn't handle multiple files, disable the menu items */ - if ((g_list_length (files) > 1) && - (can_handle_multiple_files (info) == FALSE)) { - - for (; verb_names; verb_names = verb_names->next) { - char *path = g_strdup_printf ("/commands/%s", - (char *)verb_names->data); - bonobo_ui_component_set_prop (view->details->ui, - path, - "sensitive", - "0", NULL); - g_free (path); - } - - /* no reason to continue */ - return; - } - - /* add the verbs */ - for (l = verb_names; l; l = l->next) { - const char *verb; - BonoboMimeActionData *data; - GClosure *closure; - - verb = l->data; + for (l = menu_items; l; l = l->next) { + NautilusMenuItem *item; - data = bonobo_mime_action_data_new (info->iid, - verb, files); - closure = g_cclosure_new - (G_CALLBACK (bonobo_mime_action_callback), - data, - bonobo_mime_action_menu_data_destroy_callback); - bonobo_ui_component_add_verb_full - (view->details->ui, - data->verb, - closure); - } - -} - -static gboolean -no_locale_at_end (const char *str) -{ - int len; - - len = strlen (str); - if (len > 3 && - str[len-3] == '-' && - g_ascii_isalpha (str[len-2]) && - g_ascii_isalpha (str[len-1])) { - return FALSE; - } - if (len > 6 && - str[len-6] == '-' && - g_ascii_isalpha (str[len-5]) && - g_ascii_isalpha (str[len-4]) && - str[len-3] == '_' && - g_ascii_isalpha (str[len-2]) && - g_ascii_isalpha (str[len-1])) { - return FALSE; - } - return TRUE; -} - -static GList * -get_bonobo_menu_verb_names (Bonobo_ServerInfo *info) -{ - GList *l; - unsigned int i; - int offset; - - offset = strlen ("nautilusverb:"); - - l = NULL; - for (i = 0; i < info->props._length; i++) { - - /* look for properties that start with "nautilusverb:". The - * part following the colon is the verb name - */ - if (strstr (info->props._buffer[i].name, "nautilusverb:") && - no_locale_at_end (info->props._buffer[i].name)) { - l = g_list_prepend (l, - g_strdup (&info->props._buffer[i].name[offset])); - } + item = NAUTILUS_MENU_ITEM (l->data); + + nautilus_bonobo_add_extension_item_command (view->details->ui, + item); + + nautilus_bonobo_add_extension_item (view->details->ui, + FM_DIRECTORY_VIEW_POPUP_PATH_EXTENSION_ACTIONS, + item); + nautilus_bonobo_add_extension_item (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER, + item); } - - return l; } static gboolean @@ -4191,46 +3907,62 @@ get_unique_files (GList *selection) return g_list_reverse (result); } -static void -reset_bonobo_mime_actions_menu (FMDirectoryView *view, GList *selection) +static GList * +get_all_extension_menu_items (GtkWidget *window, + GList *selection) { - gboolean sensitive; - GList *components, *l, *unique_selection; - - /* Clear any previous inserted items in the mime actions placeholder */ - nautilus_bonobo_remove_menu_items_and_commands - (view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_MIME_ACTIONS); + GList *items; + GList *providers; + GList *l; + + providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); + items = NULL; - sensitive = TRUE; + for (l = providers; l != NULL; l = l->next) { + NautilusMenuProvider *provider; + GList *file_items; - /* only query for the unique files so we can reduce oaf traffic */ - unique_selection = get_unique_files (selection); + provider = NAUTILUS_MENU_PROVIDER (l->data); + file_items = nautilus_menu_provider_get_file_items (provider, + window, + selection); + items = g_list_concat (items, file_items); + } - components = nautilus_mime_get_popup_components_for_files (unique_selection); - g_list_free (unique_selection); + nautilus_module_extension_list_free (providers); - for (l = components; l; l = l->next) { - Bonobo_ServerInfo *info; - GList *verb_names; + return items; +} - info = l->data; - verb_names = get_bonobo_menu_verb_names (info); - - add_bonobo_menu_ui_and_verbs (view, selection, info, - verb_names); - eel_g_list_free_deep (verb_names); - - } +static void +reset_extension_actions_menu (FMDirectoryView *view, GList *selection) +{ + GList *unique_selection; + GList *items; + GList *l; - if (components != NULL) { - gnome_vfs_mime_component_list_free (components); - } else { - sensitive = FALSE; + /* Clear any previous inserted items in the extension actions placeholder */ + nautilus_bonobo_remove_menu_items_and_commands + (view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_EXTENSION_ACTIONS); + nautilus_bonobo_remove_menu_items_and_commands + (view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER); + + /* only query for the unique files */ + unique_selection = get_unique_files (selection); + items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (view)), + selection); + + if (items) { + add_extension_menu_items (view, unique_selection, items); + + for (l = items; l != NULL; l = l->next) { + g_object_unref (l->data); + } + + g_list_free (items); } - nautilus_bonobo_set_sensitive (view->details->ui, - FM_DIRECTORY_VIEW_POPUP_PATH_MIME_ACTIONS, - sensitive); + g_list_free (unique_selection); } static char * @@ -5593,7 +5325,7 @@ real_update_menus (FMDirectoryView *view) /* Broken into its own function just for convenience */ reset_bonobo_open_with_menu (view, selection); - reset_bonobo_mime_actions_menu (view, selection); + reset_extension_actions_menu (view, selection); if (all_selected_items_in_trash (view)) { label = _("_Delete from Trash"); @@ -6459,7 +6191,8 @@ finish_loading (FMDirectoryView *view) attributes |= NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | NAUTILUS_FILE_ATTRIBUTE_METADATA | NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE | - NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME; + NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME | + NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO; nautilus_directory_file_monitor_add (view->details->model, &view->details->model, diff --git a/src/file-manager/fm-list-model.c b/src/file-manager/fm-list-model.c index 77d959c0f..89be75f06 100644 --- a/src/file-manager/fm-list-model.c +++ b/src/file-manager/fm-list-model.c @@ -4,6 +4,7 @@ Copyright (C) 2001, 2002 Anders Carlsson Copyright (C) 2003, Soeren Sandmann + 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 @@ -20,7 +21,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Authors: Anders Carlsson <andersca@gnu.org>, Soeren Sandmann (sandmann@daimi.au.dk) + Authors: Anders Carlsson <andersca@gnu.org>, Soeren Sandmann (sandmann@daimi.au.dk), Dave Camp <dave@ximian.com> */ #include <config.h> @@ -48,7 +49,7 @@ struct FMListModelDetails { int stamp; - int sort_column_id; + char *sort_attribute; GtkSortType order; gboolean sort_directories_first; @@ -56,6 +57,8 @@ struct FMListModelDetails { GtkTreeView *drag_view; int drag_begin_x; int drag_begin_y; + + GPtrArray *columns; }; typedef struct { @@ -64,11 +67,6 @@ typedef struct { GList *path_list; } DragDataGetInfo; -typedef struct { - const char *attribute_name; - int sort_column_id; -} AttributeEntry; - static GtkTargetEntry drag_types [] = { { NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST }, { NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST }, @@ -76,24 +74,6 @@ static GtkTargetEntry drag_types [] = { { NAUTILUS_ICON_DND_TEXT_TYPE, 0, NAUTILUS_ICON_DND_TEXT } }; -/* - * Do not change the order of the type and size attributes, they - * have to be in this order so that the column_id to attribute mapping - * works. This is needed to store the sorting preferences. This duplicate - * entry is here to allow the ordering by icon (i think...) - */ - -static const AttributeEntry attributes[] = { - { "name", FM_LIST_MODEL_NAME_COLUMN }, - { "type", FM_LIST_MODEL_TYPE_COLUMN }, -#ifdef GNOME2_CONVERSION_COMPLETE - { "emblems", FM_LIST_MODEL_EMBLEMS_COLUMN }, -#endif - { "size", FM_LIST_MODEL_SIZE_COLUMN }, - { "icon", FM_LIST_MODEL_TYPE_COLUMN }, - { "date_modified", FM_LIST_MODEL_DATE_MODIFIED_COLUMN }, -}; - static GtkTargetList *drag_target_list = NULL; static guint @@ -105,7 +85,7 @@ fm_list_model_get_flags (GtkTreeModel *tree_model) static int fm_list_model_get_n_columns (GtkTreeModel *tree_model) { - return FM_LIST_MODEL_NUM_COLUMNS; + return FM_LIST_MODEL_NUM_COLUMNS + FM_LIST_MODEL (tree_model)->details->columns->len; } static GType @@ -114,11 +94,6 @@ fm_list_model_get_column_type (GtkTreeModel *tree_model, int index) switch (index) { case FM_LIST_MODEL_FILE_COLUMN: return NAUTILUS_TYPE_FILE; - case FM_LIST_MODEL_NAME_COLUMN: - case FM_LIST_MODEL_SIZE_COLUMN: - case FM_LIST_MODEL_TYPE_COLUMN: - case FM_LIST_MODEL_DATE_MODIFIED_COLUMN: - return G_TYPE_STRING; case FM_LIST_MODEL_SMALLEST_ICON_COLUMN: case FM_LIST_MODEL_SMALLER_ICON_COLUMN: case FM_LIST_MODEL_SMALL_ICON_COLUMN: @@ -137,7 +112,11 @@ fm_list_model_get_column_type (GtkTreeModel *tree_model, int index) case FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN: return G_TYPE_BOOLEAN; default: - return G_TYPE_INVALID; + if (index < FM_LIST_MODEL_NUM_COLUMNS + FM_LIST_MODEL (tree_model)->details->columns->len) { + return G_TYPE_STRING; + } else { + return G_TYPE_INVALID; + } } } @@ -215,12 +194,6 @@ fm_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column g_value_set_object (value, file); break; - case FM_LIST_MODEL_NAME_COLUMN: - g_value_init (value, G_TYPE_STRING); - - str = nautilus_file_get_string_attribute_with_default (file, "name"); - g_value_set_string_take_ownership (value, str); - break; case FM_LIST_MODEL_SMALLEST_ICON_COLUMN: case FM_LIST_MODEL_SMALLER_ICON_COLUMN: case FM_LIST_MODEL_SMALL_ICON_COLUMN: @@ -308,31 +281,28 @@ fm_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column g_object_unref (icon); } break; - case FM_LIST_MODEL_SIZE_COLUMN: - g_value_init (value, G_TYPE_STRING); - - str = nautilus_file_get_string_attribute_with_default (file, "size"); - g_value_set_string_take_ownership (value, str); - break; - case FM_LIST_MODEL_TYPE_COLUMN: - g_value_init (value, G_TYPE_STRING); - - str = nautilus_file_get_string_attribute_with_default (file, "type"); - g_value_set_string_take_ownership (value, str); - break; - case FM_LIST_MODEL_DATE_MODIFIED_COLUMN: - g_value_init (value, G_TYPE_STRING); - - str = nautilus_file_get_string_attribute_with_default (file, "date_modified"); - g_value_set_string_take_ownership (value, str); - break; case FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN: g_value_init (value, G_TYPE_BOOLEAN); - - g_value_set_boolean (value, nautilus_file_can_rename (file)); - break; - default: - g_assert_not_reached (); + + g_value_set_boolean (value, nautilus_file_can_rename (file)); + break; + default: + if (column < FM_LIST_MODEL_NUM_COLUMNS + model->details->columns->len) { + NautilusColumn *nautilus_column; + char *attribute; + nautilus_column = model->details->columns->pdata[column - FM_LIST_MODEL_NUM_COLUMNS]; + + g_value_init (value, G_TYPE_STRING); + g_object_get (nautilus_column, + "attribute", &attribute, + NULL); + str = nautilus_file_get_string_attribute_with_default (file, + attribute); + g_value_set_string_take_ownership (value, str); + g_free (attribute); + } else { + g_assert_not_reached (); + } } } @@ -460,10 +430,10 @@ fm_list_model_compare_func (gconstpointer a, file1 = (NautilusFile *)a; file2 = (NautilusFile *)b; - result = nautilus_file_compare_for_sort (file1, file2, - fm_list_model_get_sort_type_from_sort_column_id (model->details->sort_column_id), - model->details->sort_directories_first, - (model->details->order == GTK_SORT_DESCENDING)); + result = nautilus_file_compare_for_sort_by_attribute (file1, file2, + model->details->sort_attribute, + model->details->sort_directories_first, + (model->details->order == GTK_SORT_DESCENDING)); return result; } @@ -514,21 +484,26 @@ fm_list_model_sort (FMListModel *model) g_free (new_order); } + static gboolean fm_list_model_get_sort_column_id (GtkTreeSortable *sortable, gint *sort_column_id, GtkSortType *order) { FMListModel *model; - + int id; + model = (FMListModel *)sortable; - - if (model->details->sort_column_id == -1) { + + id = fm_list_model_get_sort_column_id_from_attribute + (model, model->details->sort_attribute); + + if (id == -1) { return FALSE; } - + if (sort_column_id != NULL) { - *sort_column_id = model->details->sort_column_id; + *sort_column_id = id; } if (order != NULL) { @@ -545,19 +520,15 @@ fm_list_model_set_sort_column_id (GtkTreeSortable *sortable, gint sort_column_id model = (FMListModel *)sortable; - if ((model->details->sort_column_id == sort_column_id) && - (model->details->order == order)) { - return; - } + g_free (model->details->sort_attribute); + model->details->sort_attribute = fm_list_model_get_attribute_from_sort_column_id (model, sort_column_id); - model->details->sort_column_id = sort_column_id; model->details->order = order; fm_list_model_sort (model); gtk_tree_sortable_sort_column_changed (sortable); } - static gboolean fm_list_model_has_default_sort_func (GtkTreeSortable *sortable) { @@ -802,7 +773,8 @@ fm_list_model_set_should_sort_directories_first (FMListModel *model, gboolean so } int -fm_list_model_get_sort_column_id_from_attribute (const char *attribute) +fm_list_model_get_sort_column_id_from_attribute (FMListModel *model, + const char *attribute) { guint i; @@ -810,67 +782,51 @@ fm_list_model_get_sort_column_id_from_attribute (const char *attribute) return -1; } - for (i = 0; i < G_N_ELEMENTS (attributes); i++) { - if (strcmp (attributes[i].attribute_name, attribute) == 0) { - return attributes[i].sort_column_id; - } + /* Hack - the preferences dialog sets modification_date for some + * rather than date_modified for some reason. Make sure that + * works. */ + if (!strcmp (attribute, "modification_date")) { + attribute = "date_modified"; } + for (i = 0; i < model->details->columns->len; i++) { + NautilusColumn *column; + char *column_attribute; + + column = + NAUTILUS_COLUMN (model->details->columns->pdata[i]); + g_object_get (G_OBJECT (column), + "attribute", &column_attribute, + NULL); + if (!strcmp (column_attribute, attribute)) { + g_free (column_attribute); + return FM_LIST_MODEL_NUM_COLUMNS + i; + } + g_free (column_attribute); + } + return -1; } char * -fm_list_model_get_attribute_from_sort_column_id (int sort_column_id) +fm_list_model_get_attribute_from_sort_column_id (FMListModel *model, + int sort_column_id) { - guint i; - - for (i = 0; i < G_N_ELEMENTS (attributes); i++) { - if (attributes[i].sort_column_id == sort_column_id) { - return g_strdup (attributes[i].attribute_name); - } - } - - g_warning ("unknown sort column id: %d", sort_column_id); - return g_strdup ("name"); -} + NautilusColumn *column; + int index; + char *attribute; + + index = sort_column_id - FM_LIST_MODEL_NUM_COLUMNS; -int -fm_list_model_get_sort_column_id_from_sort_type (NautilusFileSortType sort_type) -{ - switch (sort_type) { - case NAUTILUS_FILE_SORT_NONE: - return -1; - case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME: - return FM_LIST_MODEL_NAME_COLUMN; - case NAUTILUS_FILE_SORT_BY_TYPE: - return FM_LIST_MODEL_TYPE_COLUMN; - case NAUTILUS_FILE_SORT_BY_SIZE: - return FM_LIST_MODEL_SIZE_COLUMN; - case NAUTILUS_FILE_SORT_BY_MTIME: - return FM_LIST_MODEL_DATE_MODIFIED_COLUMN; - case NAUTILUS_FILE_SORT_BY_EMBLEMS: - case NAUTILUS_FILE_SORT_BY_DIRECTORY: - break; + if (index < 0 || index >= model->details->columns->len) { + g_warning ("unknown sort column id: %d", sort_column_id); + return NULL; } - g_return_val_if_reached (-1); -} + column = NAUTILUS_COLUMN (model->details->columns->pdata[index]); + g_object_get (G_OBJECT (column), "attribute", &attribute, NULL); -NautilusFileSortType -fm_list_model_get_sort_type_from_sort_column_id (int sort_column_id) -{ - switch (sort_column_id) { - case FM_LIST_MODEL_NAME_COLUMN: - return NAUTILUS_FILE_SORT_BY_DISPLAY_NAME; - case FM_LIST_MODEL_TYPE_COLUMN: - return NAUTILUS_FILE_SORT_BY_TYPE; - case FM_LIST_MODEL_SIZE_COLUMN: - return NAUTILUS_FILE_SORT_BY_SIZE; - case FM_LIST_MODEL_DATE_MODIFIED_COLUMN: - return NAUTILUS_FILE_SORT_BY_MTIME; - } - - g_return_val_if_reached (NAUTILUS_FILE_SORT_NONE); + return attribute; } NautilusZoomLevel @@ -988,15 +944,56 @@ fm_list_model_get_drag_types (GtkTargetEntry **entries, *num_entries = G_N_ELEMENTS (drag_types); } +int +fm_list_model_add_column (FMListModel *model, + NautilusColumn *column) +{ + g_ptr_array_add (model->details->columns, column); + g_object_ref (column); + + return FM_LIST_MODEL_NUM_COLUMNS + (model->details->columns->len - 1); +} + +int +fm_list_model_get_column_number (FMListModel *model, + const char *column_name) +{ + int i; + + for (i = 0; i < model->details->columns->len; i++) { + NautilusColumn *column; + char *name; + + column = model->details->columns->pdata[i]; + + g_object_get (G_OBJECT (column), "name", &name, NULL); + + if (!strcmp (name, column_name)) { + g_free (name); + return FM_LIST_MODEL_NUM_COLUMNS + i; + } + g_free (name); + } + + return -1; +} + static void fm_list_model_finalize (GObject *object) { FMListModel *model; + int i; model = FM_LIST_MODEL (object); + for (i = 0; i < model->details->columns->len; i++) { + g_object_unref (model->details->columns->pdata[i]); + } + g_ptr_array_free (model->details->columns, TRUE); + g_sequence_free (model->details->files); g_hash_table_destroy (model->details->reverse_map); + g_free (model->details->sort_attribute); g_free (model->details); EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); @@ -1009,7 +1006,8 @@ fm_list_model_init (FMListModel *model) model->details->files = g_sequence_new ((GDestroyNotify)nautilus_file_unref); model->details->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal); model->details->stamp = g_random_int (); - model->details->sort_column_id = -1; + model->details->sort_attribute = NULL; + model->details->columns = g_ptr_array_new (); } static void diff --git a/src/file-manager/fm-list-model.h b/src/file-manager/fm-list-model.h index 033a568f5..d4a89a74e 100644 --- a/src/file-manager/fm-list-model.h +++ b/src/file-manager/fm-list-model.h @@ -27,6 +27,7 @@ #include <gdk/gdkdnd.h> #include <libnautilus-private/nautilus-file.h> #include <libnautilus-private/nautilus-icon-factory.h> +#include <libnautilus-extension/nautilus-column.h> #ifndef FM_LIST_MODEL_H #define FM_LIST_MODEL_H @@ -54,9 +55,6 @@ enum { FM_LIST_MODEL_LARGER_EMBLEM_COLUMN, FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN, FM_LIST_MODEL_NAME_COLUMN, - FM_LIST_MODEL_SIZE_COLUMN, - FM_LIST_MODEL_TYPE_COLUMN, - FM_LIST_MODEL_DATE_MODIFIED_COLUMN, FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN, FM_LIST_MODEL_NUM_COLUMNS }; @@ -88,11 +86,11 @@ gboolean fm_list_model_get_tree_iter_from_file (FMListModel * void fm_list_model_set_should_sort_directories_first (FMListModel *model, gboolean sort_directories_first); -int fm_list_model_get_sort_column_id_from_attribute (const char *attribute); -char *fm_list_model_get_attribute_from_sort_column_id (int sort_column_id); +int fm_list_model_get_sort_column_id_from_attribute (FMListModel *model, -int fm_list_model_get_sort_column_id_from_sort_type (NautilusFileSortType sort_type); -NautilusFileSortType fm_list_model_get_sort_type_from_sort_column_id (int sort_column_id); + const char *attribute); +char *fm_list_model_get_attribute_from_sort_column_id (FMListModel *model, + int sort_column_id); NautilusZoomLevel fm_list_model_get_zoom_level_from_column_id (int column); int fm_list_model_get_column_id_from_zoom_level (NautilusZoomLevel zoom_level); @@ -111,4 +109,9 @@ void fm_list_model_set_drag_view (FMListModel *model, void fm_list_model_get_drag_types (GtkTargetEntry **entries, int *num_entries); + +int fm_list_model_add_column (FMListModel *model, + NautilusColumn *column); +int fm_list_model_get_column_number (FMListModel *model, + const char *column_name); #endif /* FM_LIST_MODEL_H */ diff --git a/src/file-manager/fm-list-view.c b/src/file-manager/fm-list-view.c index 5f909aa8c..4d7b72a1c 100644 --- a/src/file-manager/fm-list-view.c +++ b/src/file-manager/fm-list-view.c @@ -31,19 +31,29 @@ #include <string.h> #include "fm-error-reporting.h" #include "fm-list-model.h" +#include <string.h> +#include <bonobo/bonobo-ui-util.h> #include <eel/eel-cell-renderer-pixbuf-list.h> #include <eel/eel-vfs-extensions.h> #include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-macros.h> #include <gdk/gdkkeysyms.h> +#include <gtk/gtkdialog.h> #include <gtk/gtkcellrendererpixbuf.h> #include <gtk/gtkcellrenderertext.h> #include <gtk/gtkentry.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkstock.h> #include <gtk/gtktreeselection.h> #include <gtk/gtktreeview.h> #include <libegg/eggtreemultidnd.h> #include <libgnome/gnome-i18n.h> #include <libgnome/gnome-macros.h> #include <libgnomevfs/gnome-vfs-utils.h> +#include <libnautilus-extension/nautilus-column-provider.h> +#include <libnautilus-private/nautilus-column-chooser.h> +#include <libnautilus-private/nautilus-column-utilities.h> #include <libnautilus-private/nautilus-directory-background.h> #include <libnautilus-private/nautilus-dnd.h> #include <libnautilus-private/nautilus-file-dnd.h> @@ -51,6 +61,7 @@ #include <libnautilus-private/nautilus-icon-dnd.h> #include <libnautilus-private/nautilus-icon-factory.h> #include <libnautilus-private/nautilus-metadata.h> +#include <libnautilus-private/nautilus-module.h> #include <libnautilus-private/nautilus-tree-view-drag-dest.h> #include <libnautilus/nautilus-scroll-positionable.h> #include <libnautilus-private/nautilus-cell-renderer-pixbuf-emblem.h> @@ -71,9 +82,7 @@ struct FMListViewDetails { GtkCellRendererPixbuf *pixbuf_cell; GtkCellRendererText *file_name_cell; - GtkCellRendererText *size_cell; - GtkCellRendererText *type_cell; - GtkCellRendererText *date_modified_cell; + GList *cells; NautilusZoomLevel zoom_level; @@ -90,10 +99,17 @@ struct FMListViewDetails { int drag_y; gboolean drag_started; + gboolean row_selected_on_button_down; /* typeahead selection state */ TypeSelectState *type_select_state; + + BonoboUIComponent *ui; + gboolean menus_ready; + + GHashTable *columns; + GtkWidget *column_editor; }; /* @@ -104,9 +120,11 @@ struct FMListViewDetails { #define LIST_VIEW_MINIMUM_ROW_HEIGHT 28 static int click_policy_auto_value; -static NautilusFileSortType default_sort_order_auto_value; +static char * default_sort_order_auto_value; static gboolean default_sort_reversed_auto_value; static NautilusZoomLevel default_zoom_level_auto_value; +static GList * default_visible_columns_auto_value; +static GList * default_column_order_auto_value; static GList * fm_list_view_get_selection (FMDirectoryView *view); static void fm_list_view_set_zoom_level (FMListView *view, @@ -765,9 +783,9 @@ sort_column_changed_callback (GtkTreeSortable *sortable, gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &reversed); - sort_attr = fm_list_model_get_attribute_from_sort_column_id (sort_column_id); - sort_column_id = fm_list_model_get_sort_column_id_from_sort_type (default_sort_order_auto_value); - default_sort_attr = fm_list_model_get_attribute_from_sort_column_id (sort_column_id); + sort_attr = fm_list_model_get_attribute_from_sort_column_id (view->details->model, sort_column_id); + sort_column_id = fm_list_model_get_sort_column_id_from_attribute (view->details->model, default_sort_order_auto_value); + default_sort_attr = fm_list_model_get_attribute_from_sort_column_id (view->details->model, sort_column_id); nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN, default_sort_attr, sort_attr); g_free (default_sort_attr); @@ -877,6 +895,60 @@ move_copy_items_callback (NautilusTreeViewDragDest *dest, } static void +apply_visible_columns_foreach (gpointer key, gpointer value, gpointer user_data) +{ + gboolean visible; + + visible = (eel_g_str_list_index (user_data, key) != -1); + + gtk_tree_view_column_set_visible (GTK_TREE_VIEW_COLUMN (value), + visible); +} + +static void +apply_visible_columns (FMListView *list_view, GList *visible_columns) +{ + g_hash_table_foreach (list_view->details->columns, + apply_visible_columns_foreach, + visible_columns); + +} + +static void +apply_column_order (FMListView *list_view, GList *column_order) +{ + GList *columns; + GtkTreeViewColumn *last_view_column; + GList *l; + + columns = nautilus_get_all_columns (); + columns = nautilus_sort_columns (columns, column_order); + + last_view_column = NULL; + for (l = columns; l != NULL; l = l->next) { + GtkTreeViewColumn *view_column; + char *name; + + g_object_get (G_OBJECT (l->data), "name", &name, NULL); + + view_column = g_hash_table_lookup (list_view->details->columns, + name); + + g_free (name); + + if (view_column) { + gtk_tree_view_move_column_after + (list_view->details->tree_view, + view_column, + last_view_column); + + last_view_column = view_column; + } + } + nautilus_column_list_free (columns); +} + +static void create_and_set_up_tree_view (FMListView *view) { GtkCellRenderer *cell; @@ -884,8 +956,14 @@ create_and_set_up_tree_view (FMListView *view) GtkTargetEntry *drag_types; AtkObject *atk_obj; int num_drag_types; - + GList *nautilus_columns; + GList *l; + view->details->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); + view->details->columns = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + NULL); fm_list_model_get_drag_types (&drag_types, &num_drag_types); @@ -938,70 +1016,91 @@ create_and_set_up_tree_view (FMListView *view) gtk_tree_selection_set_mode (gtk_tree_view_get_selection (view->details->tree_view), GTK_SELECTION_MULTIPLE); gtk_tree_view_set_rules_hint (view->details->tree_view, TRUE); - /* Create the file name column */ - cell = nautilus_cell_renderer_pixbuf_emblem_new (); - view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell; - - view->details->file_name_column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_sort_column_id (view->details->file_name_column, FM_LIST_MODEL_NAME_COLUMN); - gtk_tree_view_column_set_title (view->details->file_name_column, _("File name")); - gtk_tree_view_column_set_resizable (view->details->file_name_column, TRUE); + nautilus_columns = nautilus_get_all_columns (); - gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE); - gtk_tree_view_column_set_attributes (view->details->file_name_column, - cell, - "pixbuf", FM_LIST_MODEL_SMALLEST_ICON_COLUMN, - "pixbuf_emblem", FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN, - NULL); + for (l = nautilus_columns; l != NULL; l = l->next) { + NautilusColumn *nautilus_column; + int column_num; + char *name; + char *label; + float xalign; - cell = gtk_cell_renderer_text_new (); - view->details->file_name_cell = (GtkCellRendererText *)cell; - g_signal_connect (cell, "edited", G_CALLBACK (cell_renderer_edited), view); + nautilus_column = NAUTILUS_COLUMN (l->data); - gtk_tree_view_column_pack_start (view->details->file_name_column, cell, TRUE); - gtk_tree_view_column_set_attributes (view->details->file_name_column, cell, - "text", FM_LIST_MODEL_NAME_COLUMN, NULL); - gtk_tree_view_append_column (view->details->tree_view, view->details->file_name_column); + g_object_get (nautilus_column, + "name", &name, + "label", &label, + "xalign", &xalign, NULL); - /* Create the size column */ - cell = gtk_cell_renderer_text_new (); - view->details->size_cell = (GtkCellRendererText *)cell; - g_object_set (G_OBJECT (cell), - "xalign", 1.0, - NULL); - column = gtk_tree_view_column_new_with_attributes (_("Size"), - cell, - "text", FM_LIST_MODEL_SIZE_COLUMN, - NULL); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_sort_column_id (column, FM_LIST_MODEL_SIZE_COLUMN); - gtk_tree_view_append_column (view->details->tree_view, column); - - /* Create the type column */ - cell = gtk_cell_renderer_text_new (); - view->details->type_cell = (GtkCellRendererText *)cell; - column = gtk_tree_view_column_new_with_attributes (_("Type"), - cell, - "text", FM_LIST_MODEL_TYPE_COLUMN, - NULL); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_sort_column_id (column, FM_LIST_MODEL_TYPE_COLUMN); - gtk_tree_view_append_column (view->details->tree_view, column); - - /* Create the date modified column */ - cell = gtk_cell_renderer_text_new (); - view->details->date_modified_cell = (GtkCellRendererText *)cell; - column = gtk_tree_view_column_new_with_attributes (_("Date Modified"), - cell, - "text", FM_LIST_MODEL_DATE_MODIFIED_COLUMN, - NULL); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_sort_column_id (column, FM_LIST_MODEL_DATE_MODIFIED_COLUMN); - gtk_tree_view_append_column (view->details->tree_view, column); + column_num = fm_list_model_add_column (view->details->model, + nautilus_column); + + /* Created the name column specially, because it + * has the icon in it.*/ + if (!strcmp (name, "name")) { + /* Create the file name column */ + cell = nautilus_cell_renderer_pixbuf_emblem_new (); + view->details->pixbuf_cell = (GtkCellRendererPixbuf *)cell; + + view->details->file_name_column = gtk_tree_view_column_new (); + + g_hash_table_insert (view->details->columns, + g_strdup ("name"), + view->details->file_name_column); + + gtk_tree_view_column_set_sort_column_id (view->details->file_name_column, column_num); + gtk_tree_view_column_set_title (view->details->file_name_column, _("File name")); + gtk_tree_view_column_set_resizable (view->details->file_name_column, TRUE); + + gtk_tree_view_column_pack_start (view->details->file_name_column, cell, FALSE); + gtk_tree_view_column_set_attributes (view->details->file_name_column, + cell, + "pixbuf", FM_LIST_MODEL_SMALLEST_ICON_COLUMN, + "pixbuf_emblem", FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN, + NULL); + + cell = gtk_cell_renderer_text_new (); + view->details->file_name_cell = (GtkCellRendererText *)cell; + g_signal_connect (cell, "edited", G_CALLBACK (cell_renderer_edited), view); + + gtk_tree_view_column_pack_start (view->details->file_name_column, cell, TRUE); + gtk_tree_view_column_set_attributes (view->details->file_name_column, cell, + "text", + column_num, NULL); + gtk_tree_view_append_column (view->details->tree_view, view->details->file_name_column); + } else { + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, "xalign", xalign, NULL); + view->details->cells = g_list_append (view->details->cells, + cell); + column = gtk_tree_view_column_new_with_attributes (label, + cell, + "text", column_num, + NULL); + gtk_tree_view_column_set_sort_column_id (column, column_num); + g_hash_table_insert (view->details->columns, + g_strdup (name), + column); + + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_visible (column, TRUE); + gtk_tree_view_append_column (view->details->tree_view, column); + } + g_free (name); + g_free (label); + } + nautilus_column_list_free (nautilus_columns); + + /* Apply the default column order and visible columns, to get it + * right most of the time. The metadata will be checked when a + * folder is loaded */ + apply_visible_columns (view, default_visible_columns_auto_value); + apply_column_order (view, default_column_order_auto_value); gtk_widget_show (GTK_WIDGET (view->details->tree_view)); gtk_container_add (GTK_CONTAINER (view), GTK_WIDGET (view->details->tree_view)); + atk_obj = gtk_widget_get_accessible (GTK_WIDGET (view->details->tree_view)); atk_object_set_name (atk_obj, _("List View")); } @@ -1012,6 +1111,66 @@ fm_list_view_add_file (FMDirectoryView *view, NautilusFile *file) fm_list_model_add_file (FM_LIST_VIEW (view)->details->model, file); } +static GList * +get_visible_columns (FMListView *list_view) +{ + NautilusFile *file; + GList *visible_columns; + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (list_view)); + + visible_columns = nautilus_file_get_metadata_list + (file, + NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, + NAUTILUS_METADATA_SUBKEY_COLUMNS); + + if (!visible_columns) { + visible_columns = eel_g_str_list_copy (default_visible_columns_auto_value); + } + + return visible_columns; +} + +static void +set_visible_columns_from_metadata_and_preferences (FMListView *list_view) +{ + GList *visible_columns; + + visible_columns = get_visible_columns (list_view); + apply_visible_columns (list_view, visible_columns); + eel_g_list_free_deep (visible_columns); +} + +static GList * +get_column_order (FMListView *list_view) +{ + NautilusFile *file; + GList *column_order; + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (list_view)); + + column_order = nautilus_file_get_metadata_list + (file, + NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, + NAUTILUS_METADATA_SUBKEY_COLUMNS); + + if (!column_order) { + column_order = eel_g_str_list_copy (default_column_order_auto_value); + } + + return column_order; +} + +static void +set_column_order_from_metadata_and_preferences (FMListView *list_view) +{ + GList *column_order; + + column_order = get_column_order (list_view); + apply_column_order (list_view, column_order); + eel_g_list_free_deep (column_order); +} + static void set_sort_order_from_metadata_and_preferences (FMListView *list_view) { @@ -1024,11 +1183,10 @@ set_sort_order_from_metadata_and_preferences (FMListView *list_view) sort_attribute = nautilus_file_get_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN, NULL); - sort_column_id = fm_list_model_get_sort_column_id_from_attribute (sort_attribute); + sort_column_id = fm_list_model_get_sort_column_id_from_attribute (list_view->details->model, sort_attribute); g_free (sort_attribute); - if (sort_column_id == -1) { - sort_column_id = fm_list_model_get_sort_column_id_from_sort_type (default_sort_order_auto_value); + sort_column_id = fm_list_model_get_sort_column_id_from_attribute (list_view->details->model, default_sort_order_auto_value); } sort_reversed = nautilus_file_get_boolean_metadata (file, @@ -1098,6 +1256,8 @@ fm_list_view_begin_loading (FMDirectoryView *view) set_sort_order_from_metadata_and_preferences (list_view); set_zoom_level_from_metadata_and_preferences (list_view); + set_visible_columns_from_metadata_and_preferences (list_view); + set_column_order_from_metadata_and_preferences (list_view); } static void @@ -1263,6 +1423,195 @@ fm_list_view_reveal_selection (FMDirectoryView *view) nautilus_file_list_free (selection); } +static void +column_editor_response_callback (GtkWidget *dialog, + int response_id, + gpointer user_data) +{ + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +column_chooser_changed_callback (NautilusColumnChooser *chooser, + FMListView *view) +{ + NautilusFile *file; + GList *visible_columns; + GList *column_order; + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)); + + nautilus_column_chooser_get_settings (chooser, + &visible_columns, + &column_order); + + nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NAUTILUS_METADATA_SUBKEY_COLUMNS, visible_columns); + nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NAUTILUS_METADATA_SUBKEY_COLUMNS, column_order); + + eel_g_list_free_deep (visible_columns); + eel_g_list_free_deep (column_order); + + set_visible_columns_from_metadata_and_preferences (view); + set_column_order_from_metadata_and_preferences (view); +} + +static void +column_chooser_set_from_settings (NautilusColumnChooser *chooser, + FMListView *view) +{ + GList *visible_columns; + GList *column_order; + + g_signal_handlers_block_by_func + (chooser, G_CALLBACK (column_chooser_changed_callback), view); + + visible_columns = get_visible_columns (view); + column_order = get_column_order (view); + + nautilus_column_chooser_set_settings (chooser, + visible_columns, + column_order); + + eel_g_list_free_deep (visible_columns); + eel_g_list_free_deep (column_order); + + g_signal_handlers_unblock_by_func + (chooser, G_CALLBACK (column_chooser_changed_callback), view); +} + +static void +column_chooser_use_default_callback (NautilusColumnChooser *chooser, + FMListView *view) +{ + NautilusFile *file; + + file = fm_directory_view_get_directory_as_file + (FM_DIRECTORY_VIEW (view)); + + nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NAUTILUS_METADATA_SUBKEY_COLUMNS, NULL); + nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NAUTILUS_METADATA_SUBKEY_COLUMNS, NULL); + + set_visible_columns_from_metadata_and_preferences (FM_LIST_VIEW (view)); + set_column_order_from_metadata_and_preferences (FM_LIST_VIEW (view)); + column_chooser_set_from_settings (chooser, view); +} + +static GtkWidget * +create_column_editor (FMListView *view) +{ + GtkWidget *window; + GtkWidget *label; + GtkWidget *box; + GtkWidget *column_chooser; + NautilusFile *file; + char *title; + char *name; + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)); + name = nautilus_file_get_display_name (file); + title = g_strdup_printf (_("%s Visible Columns"), name); + g_free (name); + + window = gtk_dialog_new_with_buttons (title, + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, + NULL); + g_free (title); + g_signal_connect (window, "response", + G_CALLBACK (column_editor_response_callback), NULL); + + gtk_window_set_default_size (GTK_WINDOW (window), 300, 400); + + box = gtk_vbox_new (FALSE, 6); + gtk_container_set_border_width (GTK_CONTAINER (box), 12); + gtk_widget_show (box); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (window)->vbox), box); + + label = gtk_label_new (_("Choose the order of information to appear in this folder.")); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); + + column_chooser = nautilus_column_chooser_new (); + gtk_widget_show (column_chooser); + gtk_box_pack_start (GTK_BOX (box), column_chooser, TRUE, TRUE, 0); + + g_signal_connect (column_chooser, "changed", + G_CALLBACK (column_chooser_changed_callback), + view); + g_signal_connect (column_chooser, "use_default", + G_CALLBACK (column_chooser_use_default_callback), + view); + + column_chooser_set_from_settings + (NAUTILUS_COLUMN_CHOOSER (column_chooser), view); + + return window; +} + +static void +visible_columns_callback (BonoboUIComponent *component, + gpointer callback_data, + const char *verb) +{ + FMListView *list_view; + + list_view = FM_LIST_VIEW (callback_data); + + if (list_view->details->column_editor) { + gtk_window_present (GTK_WINDOW (list_view->details->column_editor)); + } else { + list_view->details->column_editor = create_column_editor (list_view); + eel_add_weak_pointer (&list_view->details->column_editor); + + gtk_widget_show (list_view->details->column_editor); + } +} + +static void +fm_list_view_merge_menus (FMDirectoryView *view) +{ + FMListView *list_view; + Bonobo_UIContainer ui_container; + BonoboUIVerb verbs [] = { + BONOBO_UI_VERB ("Visible Columns", visible_columns_callback), + BONOBO_UI_VERB_END + }; + + EEL_CALL_PARENT (FM_DIRECTORY_VIEW_CLASS, merge_menus, (view)); + + list_view = FM_LIST_VIEW (view); + + list_view->details->ui = bonobo_ui_component_new ("List View"); + ui_container = fm_directory_view_get_bonobo_ui_container (view); + bonobo_ui_component_set_container (list_view->details->ui, + ui_container, NULL); + bonobo_object_release_unref (ui_container, NULL); + bonobo_ui_util_set_ui (list_view->details->ui, + DATADIR, + "nautilus-list-view-ui.xml", + "nautilus", NULL); + + bonobo_ui_component_add_verb_list_with_data (list_view->details->ui, verbs, view); + + list_view->details->menus_ready = TRUE; +} + +static void +fm_list_view_update_menus (FMDirectoryView *view) +{ + FMListView *list_view; + + list_view = FM_LIST_VIEW (view); + + /* don't update if the menus aren't ready */ + if (!list_view->details->menus_ready) { + return; + } + + EEL_CALL_PARENT (FM_DIRECTORY_VIEW_CLASS, update_menus, (view)); +} /* Reset sort criteria and zoom level to match defaults */ static void @@ -1275,13 +1624,17 @@ fm_list_view_reset_to_defaults (FMDirectoryView *view) nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN, NULL, NULL); nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_REVERSED, NULL, NULL); nautilus_file_set_metadata (file, NAUTILUS_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL, NULL, NULL); + nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_COLUMN_ORDER, NAUTILUS_METADATA_SUBKEY_COLUMNS, NULL); + nautilus_file_set_metadata_list (file, NAUTILUS_METADATA_KEY_LIST_VIEW_VISIBLE_COLUMNS, NAUTILUS_METADATA_SUBKEY_COLUMNS, NULL); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (FM_LIST_VIEW (view)->details->model), - fm_list_model_get_sort_column_id_from_sort_type (default_sort_order_auto_value), + fm_list_model_get_sort_column_id_from_attribute (FM_LIST_VIEW (view)->details->model, default_sort_order_auto_value), default_sort_reversed_auto_value ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING); fm_list_view_set_zoom_level (FM_LIST_VIEW (view), get_default_zoom_level (), FALSE); + set_visible_columns_from_metadata_and_preferences (FM_LIST_VIEW (view)); + set_column_order_from_metadata_and_preferences (FM_LIST_VIEW (view)); } static void @@ -1289,6 +1642,7 @@ fm_list_view_scale_font_size (FMListView *view, NautilusZoomLevel new_level, gboolean update_size_table) { + GList *l; static gboolean first_time = TRUE; static double pango_scale[7]; int default_zoom_level, i; @@ -1313,15 +1667,11 @@ fm_list_view_scale_font_size (FMListView *view, g_object_set (G_OBJECT (view->details->file_name_cell), "scale", pango_scale[new_level], NULL); - g_object_set (G_OBJECT (view->details->size_cell), - "scale", pango_scale[new_level], - NULL); - g_object_set (G_OBJECT (view->details->type_cell), - "scale", pango_scale[new_level], - NULL); - g_object_set (G_OBJECT (view->details->date_modified_cell), - "scale", pango_scale[new_level], - NULL); + for (l = view->details->cells; l != NULL; l = l->next) { + g_object_set (G_OBJECT (l->data), + "scale", pango_scale[new_level], + NULL); + } } static void @@ -1526,6 +1876,26 @@ default_zoom_level_changed_callback (gpointer callback_data) } static void +default_visible_columns_changed_callback (gpointer callback_data) +{ + FMListView *list_view; + + list_view = FM_LIST_VIEW (callback_data); + + set_visible_columns_from_metadata_and_preferences (list_view); +} + +static void +default_column_order_changed_callback (gpointer callback_data) +{ + FMListView *list_view; + + list_view = FM_LIST_VIEW (callback_data); + + set_column_order_from_metadata_and_preferences (list_view); +} + +static void fm_list_view_sort_directories_first_changed (FMDirectoryView *view) { FMListView *list_view; @@ -1552,7 +1922,7 @@ fm_list_view_dispose (GObject *object) g_object_unref (list_view->details->drag_dest); list_view->details->drag_dest = NULL; } - + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -1570,10 +1940,18 @@ fm_list_view_finalize (GObject *object) gtk_tree_path_free (list_view->details->double_click_path[1]); } + if (list_view->details->ui != NULL) { + bonobo_ui_component_unset_container (list_view->details->ui, NULL); + bonobo_object_unref (list_view->details->ui); + } + gtk_target_list_unref (list_view->details->source_target_list); fm_list_view_flush_typeselect_state (list_view); + g_list_free (list_view->details->cells); + g_hash_table_destroy (list_view->details->columns); + g_free (list_view->details); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -1682,6 +2060,8 @@ fm_list_view_class_init (FMListViewClass *class) fm_directory_view_class->get_item_count = fm_list_view_get_item_count; fm_directory_view_class->is_empty = fm_list_view_is_empty; fm_directory_view_class->remove_file = fm_list_view_remove_file; + fm_directory_view_class->merge_menus = fm_list_view_merge_menus; + fm_directory_view_class->update_menus = fm_list_view_update_menus; fm_directory_view_class->reset_to_defaults = fm_list_view_reset_to_defaults; fm_directory_view_class->restore_default_zoom_level = fm_list_view_restore_default_zoom_level; fm_directory_view_class->reveal_selection = fm_list_view_reveal_selection; @@ -1694,12 +2074,16 @@ fm_list_view_class_init (FMListViewClass *class) eel_preferences_add_auto_enum (NAUTILUS_PREFERENCES_CLICK_POLICY, &click_policy_auto_value); - eel_preferences_add_auto_enum (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_ORDER, - (int *) &default_sort_order_auto_value); + eel_preferences_add_auto_string (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_ORDER, + (const char **) &default_sort_order_auto_value); eel_preferences_add_auto_boolean (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_SORT_IN_REVERSE_ORDER, &default_sort_reversed_auto_value); eel_preferences_add_auto_enum (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL, (int *) &default_zoom_level_auto_value); + eel_preferences_add_auto_string_glist (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS, + (const GList **) &default_visible_columns_auto_value); + eel_preferences_add_auto_string_glist (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER, + (const GList **) &default_column_order_auto_value); } static void @@ -1726,6 +2110,12 @@ fm_list_view_instance_init (FMListView *list_view) eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_ZOOM_LEVEL, default_zoom_level_changed_callback, list_view, G_OBJECT (list_view)); + eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS, + default_visible_columns_changed_callback, + list_view, G_OBJECT (list_view)); + eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER, + default_column_order_changed_callback, + list_view, G_OBJECT (list_view)); fm_list_view_click_policy_changed (FM_DIRECTORY_VIEW (list_view)); diff --git a/src/file-manager/fm-properties-window.c b/src/file-manager/fm-properties-window.c index c013319d5..bf2de856f 100644 --- a/src/file-manager/fm-properties-window.c +++ b/src/file-manager/fm-properties-window.c @@ -62,6 +62,7 @@ #include <libgnomeui/gnome-dialog.h> #include <libgnomeui/gnome-uidefs.h> #include <libgnomevfs/gnome-vfs.h> +#include <libnautilus-extension/nautilus-property-page-provider.h> #include <libnautilus-private/nautilus-customization-data.h> #include <libnautilus-private/nautilus-entry.h> #include <libnautilus-private/nautilus-file-attributes.h> @@ -71,6 +72,7 @@ #include <libnautilus-private/nautilus-emblem-utils.h> #include <libnautilus-private/nautilus-link.h> #include <libnautilus-private/nautilus-metadata.h> +#include <libnautilus-private/nautilus-module.h> #include <libnautilus-private/nautilus-undo-signal-handlers.h> #include <libnautilus-private/nautilus-mime-actions.h> #include <libnautilus-private/nautilus-view-identifier.h> @@ -156,13 +158,6 @@ typedef struct { GHashTable *pending_files; } StartupData; -typedef struct { - FMPropertiesWindow *window; - GtkWidget *vbox; - char *view_name; -} ActivationData; - - /* drag and drop definitions */ enum { @@ -204,7 +199,7 @@ static void remove_pending (StartupData *data gboolean cancel_call_when_ready, gboolean cancel_timed_wait, gboolean cancel_destroy_handler); -static void append_bonobo_pages (FMPropertiesWindow *window); +static void append_extension_pages (FMPropertiesWindow *window); GNOME_CLASS_BOILERPLATE (FMPropertiesWindow, fm_properties_window, GtkWindow, GTK_TYPE_WINDOW); @@ -929,7 +924,7 @@ update_properties_window_title (FMPropertiesWindow *window) } static void -clear_bonobo_pages (FMPropertiesWindow *window) +clear_extension_pages (FMPropertiesWindow *window) { int i; int num_pages; @@ -938,11 +933,11 @@ clear_bonobo_pages (FMPropertiesWindow *window) num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->details->notebook)); - for (i=0; i < num_pages; i++) { + for (i = 0; i < num_pages; i++) { page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->details->notebook), i); - if (g_object_get_data (G_OBJECT (page), "is-bonobo-page")) { + if (g_object_get_data (G_OBJECT (page), "is-extension-page")) { gtk_notebook_remove_page (GTK_NOTEBOOK (window->details->notebook), i); num_pages--; @@ -952,10 +947,10 @@ clear_bonobo_pages (FMPropertiesWindow *window) } static void -refresh_bonobo_pages (FMPropertiesWindow *window) +refresh_extension_pages (FMPropertiesWindow *window) { - clear_bonobo_pages (window); - append_bonobo_pages (window); + clear_extension_pages (window); + append_extension_pages (window); } static void @@ -1086,7 +1081,7 @@ properties_window_update (FMPropertiesWindow *window, window->details->mime_list = mime_list; } else { if (!mime_list_equal (window->details->mime_list, mime_list)) { - refresh_bonobo_pages (window); + refresh_extension_pages (window); } eel_g_list_free_deep (window->details->mime_list); @@ -3041,209 +3036,52 @@ create_permissions_page (FMPropertiesWindow *window) } } -static GtkWidget * -bonobo_page_error_message (const char *view_name, - const char *msg) -{ - GtkWidget *hbox; - GtkWidget *label; - GtkWidget *image; - - hbox = gtk_hbox_new (FALSE, GNOME_PAD); - image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, - GTK_ICON_SIZE_DIALOG); - - msg = g_strdup_printf ("There was an error while trying to create the view named `%s': %s", view_name, msg); - label = gtk_label_new (msg); - - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - - gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_widget_show_all (hbox); - - return hbox; -} - -static CORBA_sequence_CORBA_string * -get_uri_list (GList *file_list) -{ - CORBA_sequence_CORBA_string *uri_list; - GList *l; - int i; - - uri_list = CORBA_sequence_CORBA_string__alloc (); - uri_list->_maximum = g_list_length (file_list); - uri_list->_length = uri_list->_maximum; - uri_list->_buffer = CORBA_sequence_CORBA_string_allocbuf (uri_list->_length); - for (i = 0, l = file_list; l != NULL; i++, l = l->next) { - char *uri; - - uri = nautilus_file_get_uri (NAUTILUS_FILE (l->data)); - uri_list->_buffer[i] = CORBA_string_dup (uri); - g_free (uri); - } - - return uri_list; -} - -static void -bonobo_page_activate_callback (CORBA_Object obj, - const char *error_reason, - gpointer user_data) -{ - ActivationData *data; - FMPropertiesWindow *window; - GtkWidget *widget; - CORBA_Environment ev; - - data = (ActivationData *)user_data; - window = data->window; - - g_return_if_fail (FM_IS_PROPERTIES_WINDOW (window)); - - CORBA_exception_init (&ev); - widget = NULL; - - if (obj != CORBA_OBJECT_NIL) { - Bonobo_Control control; - Bonobo_PropertyBag pb; - GList *keys; - - control = Bonobo_Unknown_queryInterface - (obj, "IDL:Bonobo/Control:1.0", &ev); - - pb = Bonobo_Control_getProperties (control, &ev); - - if (!BONOBO_EX (&ev)) { - gboolean new_property; - - keys = bonobo_pbclient_get_keys (pb, NULL); - new_property = FALSE; - if (g_list_find_custom (keys, "uris", (GCompareFunc)strcmp)) { - new_property = TRUE; - } - bonobo_pbclient_free_keys (keys); - - if (new_property) { - /* Set the 'uris' property. */ - CORBA_sequence_CORBA_string *uri_list; - BonoboArg *arg; - - uri_list = get_uri_list (window->details->target_files); - arg = bonobo_arg_new (TC_CORBA_sequence_CORBA_string); - arg->_value = uri_list; - bonobo_pbclient_set_value_async (pb, "uris", arg, &ev); - bonobo_arg_release (arg); - } else { - /* Set the 'URI' property. */ - BonoboArg *arg; - char *uri; - - if (is_multi_file_window (window)) { - g_warning ("Multifile property page does not support the 'uris' property"); - bonobo_object_release_unref (pb, NULL); - bonobo_object_release_unref (control, NULL); - return; - } - - uri = nautilus_file_get_uri (get_target_file (window)); - - arg = bonobo_arg_new (BONOBO_ARG_STRING); - BONOBO_ARG_SET_STRING (arg, uri); - bonobo_pbclient_set_value_async (pb, "URI", arg, &ev); - bonobo_arg_release (arg); - g_free (uri); - } - - bonobo_object_release_unref (pb, NULL); - - if (!BONOBO_EX (&ev)) { - widget = bonobo_widget_new_control_from_objref - (control, CORBA_OBJECT_NIL); - bonobo_object_release_unref (control, &ev); - } - } - } - - if (widget == NULL) { - widget = bonobo_page_error_message (data->view_name, - error_reason); - } - - gtk_container_add (GTK_CONTAINER (data->vbox), widget); - gtk_widget_show (widget); - - g_free (data->view_name); - g_free (data); -} - -static gboolean -can_handle_multiple_files (Bonobo_ServerInfo *info) -{ - Bonobo_ActivationProperty *prop; - - prop = bonobo_server_info_prop_find (info, "nautilus:can_handle_multiple_files"); - - return prop && prop->v._u.value_boolean; -} - static void -append_bonobo_pages (FMPropertiesWindow *window) +append_extension_pages (FMPropertiesWindow *window) { - GList *all_components, *l; - GList *components; - CORBA_Environment ev; - - /* find all the property pages for this file */ - all_components = nautilus_mime_get_property_components_for_files - (window->details->target_files); + GList *providers; + GList *p; - /* filter out property pages that don't support multiple files */ - if (is_multi_file_window (window)) { - components = NULL; - for (l = all_components; l != NULL; l = l->next) { - if (can_handle_multiple_files (l->data)) { - components = g_list_prepend (components, - l->data); - } - } - components = g_list_reverse (components); - g_list_free (all_components); - } else { - components = all_components; - } - - CORBA_exception_init (&ev); + providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER); + + for (p = providers; p != NULL; p = p->next) { + NautilusPropertyPageProvider *provider; + GList *pages; + GList *l; - l = components; - while (l != NULL) { - NautilusViewIdentifier *view_id; - Bonobo_ServerInfo *server; - ActivationData *data; - GtkWidget *vbox; + provider = NAUTILUS_PROPERTY_PAGE_PROVIDER (p->data); + + pages = nautilus_property_page_provider_get_pages + (provider, window->details->target_files); + + for (l = pages; l != NULL; l = l->next) { + NautilusPropertyPage *page; + GtkWidget *page_widget; + GtkWidget *label; + + page = NAUTILUS_PROPERTY_PAGE (l->data); - server = l->data; - l = l->next; + g_object_get (G_OBJECT (page), + "page", &page_widget, "label", &label, + NULL); + + gtk_notebook_append_page (window->details->notebook, + page_widget, label); - view_id = nautilus_view_identifier_new_from_property_page (server); - vbox = create_page_with_vbox (window->details->notebook, - view_id->name); + g_object_set_data (G_OBJECT (page), + "is-extension-page", + page); - /* just a tag...the value doesn't matter */ - g_object_set_data (G_OBJECT (vbox), "is-bonobo-page", - vbox); + gtk_widget_unref (page_widget); + gtk_widget_unref (label); - data = g_new (ActivationData, 1); - data->window = window; - data->vbox = vbox; - data->view_name = g_strdup (view_id->name); + g_object_unref (page); + } - bonobo_activation_activate_from_id_async (view_id->iid, - 0, bonobo_page_activate_callback, - data, &ev); + g_list_free (pages); } + nautilus_module_extension_list_free (providers); } static gboolean @@ -3452,7 +3290,7 @@ create_properties_window (StartupData *startup_data) } /* append pages from available views */ - append_bonobo_pages (window); + append_extension_pages (window); /* Create box for help and close buttons. */ hbox = gtk_hbutton_box_new (); diff --git a/src/file-manager/nautilus-directory-view-ui.xml b/src/file-manager/nautilus-directory-view-ui.xml index 13065cb0e..dbceac809 100644 --- a/src/file-manager/nautilus-directory-view-ui.xml +++ b/src/file-manager/nautilus-directory-view-ui.xml @@ -203,6 +203,8 @@ accel="*Shift*Delete" verb="Delete"/> </placeholder> + + <placeholder name="Extension Actions"/> </submenu> <submenu name="View"> @@ -304,10 +306,11 @@ verb="Trash"/> <menuitem name="Delete" verb="Delete"/> </placeholder> + <placeholder name="Icon Appearance Items" delimit="top"> </placeholder> - <placeholder name="Mime Actions" delimit="none"/> + <placeholder name="Extension Actions" delimit="top"/> <separator/> <menuitem name="Properties" diff --git a/src/file-manager/nautilus-list-view-ui.xml b/src/file-manager/nautilus-list-view-ui.xml new file mode 100644 index 000000000..a42bc58f1 --- /dev/null +++ b/src/file-manager/nautilus-list-view-ui.xml @@ -0,0 +1,16 @@ +<Root> +<commands> + <cmd name="Visible Columns" + _label="Visible _Columns..." + _tip="Select the columns visible in this volder"/> +</commands> +<menu> + <submenu name="View"> + <placeholder name="View Items Placeholder"> + <menuitem name="Visible Columns" + verb="Visible Columns"/> + </placeholder> + + </submenu> +</menu> +</Root> diff --git a/src/nautilus-application.c b/src/nautilus-application.c index c303cf9ed..a5df8da7e 100644 --- a/src/nautilus-application.c +++ b/src/nautilus-application.c @@ -29,6 +29,7 @@ #include "nautilus-application.h" +#include "file-manager/fm-bonobo-provider.h" #include "file-manager/fm-desktop-icon-view.h" #include "file-manager/fm-icon-view.h" #include "file-manager/fm-list-view.h" @@ -71,6 +72,7 @@ #include <libnautilus-private/nautilus-global-preferences.h> #include <libnautilus-private/nautilus-icon-factory.h> #include <libnautilus-private/nautilus-metafile-factory.h> +#include <libnautilus-private/nautilus-module.h> #include <libnautilus-private/nautilus-sound.h> #include <libnautilus-private/nautilus-bonobo-extensions.h> #include <libnautilus-private/nautilus-undo-manager.h> @@ -395,6 +397,11 @@ create_starthere_link_callback (gpointer data) static void finish_startup (NautilusApplication *application) { + /* initialize nautilus modules */ + nautilus_module_init (); + + nautilus_module_add_type (FM_TYPE_BONOBO_PROVIDER); + /* initialize the sound machinery */ nautilus_sound_init (); diff --git a/src/nautilus-file-management-properties-main.c b/src/nautilus-file-management-properties-main.c index 1ec893f39..d0d51e801 100644 --- a/src/nautilus-file-management-properties-main.c +++ b/src/nautilus-file-management-properties-main.c @@ -29,6 +29,7 @@ #include <libgnome/gnome-program.h> #include <libgnomeui/gnome-ui-init.h> +#include <libnautilus-private/nautilus-module.h> #include <libintl.h> @@ -58,6 +59,8 @@ main (int argc, char *argv[]) eel_preferences_init ("/apps/nautilus"); + nautilus_module_init (); + nautilus_file_management_properties_dialog_show (G_CALLBACK (nautilus_file_management_properties_main_close_callback), NULL); gtk_main (); diff --git a/src/nautilus-file-management-properties.c b/src/nautilus-file-management-properties.c index 2ccba328a..f90400e76 100644 --- a/src/nautilus-file-management-properties.c +++ b/src/nautilus-file-management-properties.c @@ -26,10 +26,14 @@ #include "nautilus-file-management-properties.h" +#include <string.h> #include <gtk/gtkdialog.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> #include <gtk/gtkmessagedialog.h> -#include <gtk/gtksizegroup.h> #include <gtk/gtknotebook.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtksizegroup.h> #include <libgnome/gnome-help.h> #include <libgnome/gnome-i18n.h> @@ -37,9 +41,13 @@ #include <glade/glade.h> #include <eel/eel-gconf-extensions.h> +#include <eel/eel-glib-extensions.h> #include <eel/eel-preferences-glade.h> +#include <libnautilus-private/nautilus-column-chooser.h> +#include <libnautilus-private/nautilus-column-utilities.h> #include <libnautilus-private/nautilus-global-preferences.h> +#include <libnautilus-private/nautilus-module.h> /* string enum preferences */ #define NAUTILUS_FILE_MANAGEMENT_PROPERTIES_DEFAULT_VIEW_WIDGET "default_view_optionmenu" @@ -142,20 +150,6 @@ static const char *icon_captions_components[] = { NULL }; -static const char *icon_captions_values[] = { - "size", - "type", - "date_modified", - "date_accessed", - "owner", - "group", - "permissions", - "octal_permissions", - "mime_type", - "none", - NULL -}; - static GladeXML * nautilus_file_management_properties_dialog_create (void) { @@ -282,6 +276,239 @@ nautilus_file_management_properties_dialog_response_cb (GtkDialog *parent, } } +static void +columns_changed_callback (NautilusColumnChooser *chooser, + gpointer callback_data) +{ + GList *visible_columns; + GList *column_order; + + nautilus_column_chooser_get_settings (NAUTILUS_COLUMN_CHOOSER (chooser), + &visible_columns, + &column_order); + + eel_preferences_set_string_glist (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS, visible_columns); + eel_preferences_set_string_glist (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER, column_order); + + eel_g_list_free_deep (visible_columns); + eel_g_list_free_deep (column_order); +} + +static GtkWidget * +create_icon_caption_menu (GladeXML *xml_dialog, + GList *columns) +{ + GtkWidget *menu; + GList *l; + GtkWidget *menu_item; + + menu = gtk_menu_new (); + + menu_item = gtk_menu_item_new_with_label (_("None")); + gtk_widget_show (menu_item); + g_object_set_data (G_OBJECT (menu_item), "column_name", "none"); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + + for (l = columns; l != NULL; l = l->next) { + NautilusColumn *column; + char *name; + char *label; + + column = NAUTILUS_COLUMN (l->data); + + g_object_get (G_OBJECT (column), + "name", &name, "label", &label, + NULL); + + /* Don't show name here, it doesn't make sense */ + if (!strcmp (name, "name")) { + g_free (name); + g_free (label); + continue; + } + + menu_item = gtk_menu_item_new_with_label (label); + gtk_widget_show (menu_item); + g_object_set_data_full + (G_OBJECT (menu_item), "column_name", + g_strdup (name), + (GDestroyNotify)g_free); + g_free (name); + g_free (label); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } + + gtk_widget_show (menu); + + return menu; +} + +static void +icon_captions_changed_callback (GtkOptionMenu *option_menu, + gpointer user_data) +{ + GList *captions; + GladeXML *xml; + int i; + + xml = GLADE_XML (user_data); + + captions = NULL; + + for (i = 0; icon_captions_components[i] != NULL; i++) { + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *item; + char *name; + + option_menu = glade_xml_get_widget + (GLADE_XML (xml), icon_captions_components[i]); + menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (option_menu)); + item = gtk_menu_get_active (GTK_MENU (menu)); + + name = g_object_get_data (G_OBJECT (item), "column_name"); + captions = g_list_prepend (captions, g_strdup (name)); + } + captions = g_list_reverse (captions); + eel_preferences_set_string_glist (NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, captions); + eel_g_list_free_deep (captions); +} + +static void +update_caption_option_menu (GladeXML *xml, + const char *option_menu_name, + const char *name) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GList *l; + int i; + + option_menu = glade_xml_get_widget (xml, option_menu_name); + + g_signal_handlers_block_by_func + (option_menu, + G_CALLBACK (icon_captions_changed_callback), + xml); + menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (option_menu)); + for (l = GTK_MENU_SHELL (menu)->children, i = 0; + l != NULL; + l = l->next, i++) { + char *item_name; + item_name = g_object_get_data (G_OBJECT (l->data), + "column_name"); + if (!strcmp (name, item_name)) { + gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), i); + break; + } + } + + g_signal_handlers_unblock_by_func + (option_menu, + G_CALLBACK (icon_captions_changed_callback), + xml); +} + +static void +update_icon_captions_from_gconf (GladeXML *xml) +{ + GList *captions; + int i; + GList *l; + + + captions = eel_preferences_get_string_glist (NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS); + + for (l = captions, i = 0; + captions != NULL && icon_captions_components[i] != NULL; + l = l->next, i++) { + update_caption_option_menu (xml, + icon_captions_components[i], + (char *)l->data); + } + eel_g_list_free_deep (captions); +} + +static void +nautilus_file_management_properties_dialog_setup_icon_caption_page (GladeXML *xml_dialog) +{ + GList *columns; + int i; + gboolean writable; + + writable = eel_preferences_key_is_writable (NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS); + + columns = nautilus_get_all_columns (); + + for (i = 0; icon_captions_components[i] != NULL; i++) { + GtkWidget *menu; + GtkWidget *option_menu; + + option_menu = glade_xml_get_widget (xml_dialog, + icon_captions_components[i]); + + menu = create_icon_caption_menu (xml_dialog, columns); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + + gtk_widget_set_sensitive (GTK_WIDGET (option_menu), writable); + + g_signal_connect (option_menu, "changed", + G_CALLBACK (icon_captions_changed_callback), + xml_dialog); + } + + nautilus_column_list_free (columns); + + update_icon_captions_from_gconf (xml_dialog); +} + +static void +set_columns_from_gconf (NautilusColumnChooser *chooser) +{ + GList *visible_columns; + GList *column_order; + + visible_columns = eel_preferences_get_string_glist (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS); + column_order = eel_preferences_get_string_glist (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); + + nautilus_column_chooser_set_settings (NAUTILUS_COLUMN_CHOOSER (chooser), + visible_columns, + column_order); + + + eel_g_list_free_deep (visible_columns); + eel_g_list_free_deep (column_order); +} + +static void +use_default_callback (NautilusColumnChooser *chooser, + gpointer user_data) +{ + eel_preferences_unset (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_VISIBLE_COLUMNS); + eel_preferences_unset (NAUTILUS_PREFERENCES_LIST_VIEW_DEFAULT_COLUMN_ORDER); + set_columns_from_gconf (chooser); +} + +static void +nautilus_file_management_properties_dialog_setup_list_column_page (GladeXML *xml_dialog) +{ + GtkWidget *chooser; + GtkWidget *box; + + chooser = nautilus_column_chooser_new (); + g_signal_connect (chooser, "changed", + G_CALLBACK (columns_changed_callback), chooser); + g_signal_connect (chooser, "use_default", + G_CALLBACK (use_default_callback), chooser); + + set_columns_from_gconf (NAUTILUS_COLUMN_CHOOSER (chooser)); + + gtk_widget_show (chooser); + box = glade_xml_get_widget (xml_dialog, "list_columns_vbox"); + + gtk_box_pack_start (GTK_BOX (box), chooser, TRUE, TRUE, 0); +} + static void nautilus_file_management_properties_dialog_setup (GladeXML *xml_dialog, GtkWindow *window) { @@ -333,6 +560,7 @@ nautilus_file_management_properties_dialog_setup (GladeXML *xml_dialog, GtkWindo eel_preferences_glade_connect_bool (xml_dialog, NAUTILUS_FILE_MANAGEMENT_PROPERTIES_TREE_VIEW_FOLDERS_WIDGET, NAUTILUS_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES); + eel_preferences_glade_connect_string_enum_option_menu (xml_dialog, NAUTILUS_FILE_MANAGEMENT_PROPERTIES_DEFAULT_VIEW_WIDGET, NAUTILUS_PREFERENCES_DEFAULT_FOLDER_VIEWER, @@ -378,17 +606,15 @@ nautilus_file_management_properties_dialog_setup (GladeXML *xml_dialog, GtkWindo NAUTILUS_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION, executable_text_values); - eel_preferences_glade_connect_list_enum (xml_dialog, - icon_captions_components, - NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, - icon_captions_values); - - eel_preferences_glade_connect_int_enum (xml_dialog, NAUTILUS_FILE_MANAGEMENT_PROPERTIES_THUMBNAIL_LIMIT_WIDGET, NAUTILUS_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT, thumbnail_limit_values); + + nautilus_file_management_properties_dialog_setup_icon_caption_page (xml_dialog); + nautilus_file_management_properties_dialog_setup_list_column_page (xml_dialog); + /* UI callbacks */ dialog = glade_xml_get_widget (xml_dialog, "file_management_dialog"); g_signal_connect (G_OBJECT (dialog), "response", diff --git a/src/nautilus-file-management-properties.glade b/src/nautilus-file-management-properties.glade index 411834bad..f243f2260 100644 --- a/src/nautilus-file-management-properties.glade +++ b/src/nautilus-file-management-properties.glade @@ -1830,6 +1830,144 @@ </child> <child> + <widget class="GtkVBox" id="vbox29"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">18</property> + + <child> + <widget class="GtkVBox" id="vbox30"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label31"> + <property name="visible">True</property> + <property name="label" translatable="yes"><span weight="bold">List Columns</span></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox31"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label32"> + <property name="visible">True</property> + <property name="label" translatable="yes"> </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="list_columns_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkLabel" id="label33"> + <property name="visible">True</property> + <property name="label" translatable="yes">Choose the order of information to appear in the list view.</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label30"> + <property name="visible">True</property> + <property name="label" translatable="yes">List Columns</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> <widget class="GtkVBox" id="vbox9"> <property name="border_width">12</property> <property name="visible">True</property> diff --git a/src/nautilus-navigation-window-ui.xml b/src/nautilus-navigation-window-ui.xml index 71f5ecf01..2fba4df0c 100644 --- a/src/nautilus-navigation-window-ui.xml +++ b/src/nautilus-navigation-window-ui.xml @@ -167,14 +167,10 @@ type="toggle" pixtype="stock" pixname="Search" verb="Toggle Find Mode"/> - <toolitem name="Burn CD" - _label="Write to CD" - priority="1" - pixtype="stock" pixname="gtk-cdrom" - verb="Burn CD"/> - - <placeholder name="Extra Buttons Placeholder" delimit="top"/> + <placeholder name="Extra Buttons Placeholder" delimit="top"> + <placeholder name="Extension Actions"/> + </placeholder> <control name="ThrobberWrapper" behavior="pack-end"/> </dockitem> diff --git a/src/nautilus-navigation-window.c b/src/nautilus-navigation-window.c index c7c55a0f9..d89f1ca72 100644 --- a/src/nautilus-navigation-window.c +++ b/src/nautilus-navigation-window.c @@ -852,6 +852,19 @@ real_merge_menus (NautilusWindow *nautilus_window) } static void +real_merge_menus_2 (NautilusWindow *nautilus_window) +{ + NautilusNavigationWindow *window; + + EEL_CALL_PARENT (NAUTILUS_WINDOW_CLASS, + merge_menus_2, (nautilus_window)); + + window = NAUTILUS_NAVIGATION_WINDOW (nautilus_window); + + nautilus_navigation_window_initialize_menus_part_2 (window); +} + +static void zoom_level_changed_callback (NautilusViewFrame *view, NautilusNavigationWindow *window) { @@ -1480,6 +1493,7 @@ nautilus_navigation_window_class_init (NautilusNavigationWindowClass *class) GTK_WIDGET_CLASS (class)->show = nautilus_navigation_window_show; GTK_WIDGET_CLASS (class)->unrealize = nautilus_navigation_window_unrealize; NAUTILUS_WINDOW_CLASS (class)->merge_menus = real_merge_menus; + NAUTILUS_WINDOW_CLASS (class)->merge_menus_2 = real_merge_menus_2; NAUTILUS_WINDOW_CLASS (class)->load_view_as_menu = real_load_view_as_menu; NAUTILUS_WINDOW_CLASS (class)->set_content_view_widget = real_set_content_view_widget; NAUTILUS_WINDOW_CLASS (class)->set_throbber_active = real_set_throbber_active; diff --git a/src/nautilus-shell-ui.xml b/src/nautilus-shell-ui.xml index 68a28e95a..6b95539f2 100644 --- a/src/nautilus-shell-ui.xml +++ b/src/nautilus-shell-ui.xml @@ -25,9 +25,6 @@ <cmd name="Clear" sensitive="0"/> <cmd name="Reload" _tip="Display the latest contents of the current location"/> - <cmd name="Burn CD" - _label="_Write to CD" - _tip="Write contents to a CD"/> <cmd name="Go to Burn CD" _label="_CD Creator" _tip="Go to Empty CD folder"/> @@ -58,12 +55,8 @@ <placeholder name="General Status Placeholder" delimit="top"/> <placeholder name="File Items Placeholder" delimit="top"/> - - <placeholder name="Global File Items Placeholder" delimit="top"> - <menuitem name="Burn CD" - verb="Burn CD"/> - </placeholder> - + <placeholder name="Global File Items Placeholder" delimit="top"/> + <placeholder name="Extension Actions" delimit="top"/> <separator/> <placeholder name="Close Items Placeholder"/> @@ -124,6 +117,7 @@ <placeholder name="Edit Items Placeholder" delimit="top"/> <placeholder name="Global Edit Items Placeholder" delimit="none"/> + <placeholder name="Extension Actions" delimit="top"/> <separator/> <menuitem name="Backgrounds and Emblems" @@ -226,6 +220,7 @@ </placeholder> <placeholder name="New Object Items" delimit="none"> </placeholder> + <placeholder name="Extension Actions" delimit="top"/> </placeholder> <placeholder name="Zoom Items" delimit="top"> <menuitem name="Zoom In" diff --git a/src/nautilus-window-manage-views.c b/src/nautilus-window-manage-views.c index edc2e318f..ad285a50c 100644 --- a/src/nautilus-window-manage-views.c +++ b/src/nautilus-window-manage-views.c @@ -379,16 +379,6 @@ update_up_button (NautilusWindow *window) } static void -update_burn_cd_items (NautilusWindow *window) -{ - gboolean show_burn_cd; - - show_burn_cd = eel_istr_has_prefix (window->details->location, "burn:"); - - nautilus_window_allow_burn_cd (window, show_burn_cd); -} - -static void viewed_file_changed_callback (NautilusFile *file, NautilusWindow *window) { @@ -548,11 +538,11 @@ update_for_new_location (NautilusWindow *window) /* Check if we can go up. */ update_up_button (window); - /* Check if we can go up. */ - update_burn_cd_items (window); - /* Set up the content view menu for this new location. */ nautilus_window_load_view_as_menus (window); + + /* Load menus from nautilus extensions for this location */ + nautilus_window_load_extension_menus (window); #if !NEW_UI_COMPLETE if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) { @@ -563,6 +553,8 @@ update_for_new_location (NautilusWindow *window) /* Change the location bar to match the current location. */ nautilus_navigation_bar_set_location (NAUTILUS_NAVIGATION_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->navigation_bar), window->details->location); + + nautilus_navigation_window_load_extension_toolbar_items (NAUTILUS_NAVIGATION_WINDOW (window)); } /* Notify the information panel of the location change. */ diff --git a/src/nautilus-window-menus.c b/src/nautilus-window-menus.c index 577ae5059..56956690d 100644 --- a/src/nautilus-window-menus.c +++ b/src/nautilus-window-menus.c @@ -57,9 +57,11 @@ #include <libgnomevfs/gnome-vfs-file-info.h> #include <libgnomevfs/gnome-vfs-utils.h> #include <libgnomevfs/gnome-vfs-ops.h> +#include <libnautilus-extension/nautilus-menu-provider.h> #include <libnautilus-private/nautilus-bonobo-extensions.h> #include <libnautilus-private/nautilus-file-utilities.h> #include <libnautilus-private/nautilus-icon-factory.h> +#include <libnautilus-private/nautilus-module.h> #include <libnautilus-private/nautilus-undo-manager.h> #include <libnautilus/nautilus-bonobo-ui.h> @@ -78,6 +80,9 @@ #define MENU_PATH_SHOW_HIDE_LOCATION_BAR "/menu/View/Show Hide Placeholder/Show Hide Location Bar" #define MENU_PATH_SHOW_HIDE_STATUS_BAR "/menu/View/Show Hide Placeholder/Show Hide Statusbar" +#define MENU_PATH_EXTENSION_ACTIONS "/menu/File/Extension Actions" +#define POPUP_PATH_EXTENSION_ACTIONS "/popups/background/Before Zoom Items/Extension Actions" + #define COMMAND_PATH_CLOSE_WINDOW "/commands/Close" #define COMMAND_SHOW_HIDE_SIDEBAR "/commands/Show Hide Sidebar" #define COMMAND_SHOW_HIDE_TOOLBAR "/commands/Show Hide Toolbar" @@ -250,14 +255,6 @@ file_menu_close_window_callback (BonoboUIComponent *component, } static void -file_menu_burn_cd_callback (BonoboUIComponent *component, - gpointer user_data, - const char *verb) -{ - nautilus_window_launch_cd_burner (NAUTILUS_WINDOW (user_data)); -} - -static void connect_to_server_callback (BonoboUIComponent *component, gpointer user_data, const char *verb) @@ -664,7 +661,6 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window) BonoboUIVerb verbs [] = { BONOBO_UI_VERB ("New Window", file_menu_new_window_callback), BONOBO_UI_VERB ("Close", file_menu_close_window_callback), - BONOBO_UI_VERB ("Burn CD", file_menu_burn_cd_callback), BONOBO_UI_VERB ("Connect to Server", connect_to_server_callback), #ifdef HAVE_MEDUSA BONOBO_UI_VERB ("Find", file_menu_find_callback), @@ -734,3 +730,65 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window) nautilus_window_ui_thaw (window); } +static GList * +get_extension_menus (NautilusWindow *window) +{ + GList *providers; + GList *items; + GList *l; + + providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); + items = NULL; + + for (l = providers; l != NULL; l = l->next) { + NautilusMenuProvider *provider; + GList *file_items; + + provider = NAUTILUS_MENU_PROVIDER (l->data); + file_items = nautilus_menu_provider_get_background_items (provider, + GTK_WIDGET (window), + window->details->viewed_file); + items = g_list_concat (items, file_items); + } + + nautilus_module_extension_list_free (providers); + + return items; +} + +void +nautilus_window_load_extension_menus (NautilusWindow *window) +{ + GList *items; + GList *l; + + nautilus_bonobo_remove_menu_items_and_commands + (window->details->shell_ui, POPUP_PATH_EXTENSION_ACTIONS); + nautilus_bonobo_remove_menu_items_and_commands + (window->details->shell_ui, MENU_PATH_EXTENSION_ACTIONS); + + items = get_extension_menus (window); + + for (l = items; l != NULL; l = l->next) { + NautilusMenuItem *item; + + item = NAUTILUS_MENU_ITEM (l->data); + + nautilus_bonobo_add_extension_item_command + (window->details->shell_ui, item); + + nautilus_bonobo_add_extension_item + (window->details->shell_ui, + MENU_PATH_EXTENSION_ACTIONS, + item); + + nautilus_bonobo_add_extension_item + (window->details->shell_ui, + POPUP_PATH_EXTENSION_ACTIONS, + item); + + g_object_unref (item); + } + + g_list_free (items); +} diff --git a/src/nautilus-window-private.h b/src/nautilus-window-private.h index 5222da470..e451c7686 100644 --- a/src/nautilus-window-private.h +++ b/src/nautilus-window-private.h @@ -151,6 +151,7 @@ typedef void (*NautilusBookmarkFailedCallback) (NautilusWindow *window, void nautilus_window_set_status (NautilusWindow *window, const char *status); void nautilus_window_load_view_as_menus (NautilusWindow *window); +void nautilus_window_load_extension_menus (NautilusWindow *window); void nautilus_window_initialize_menus_part_1 (NautilusWindow *window); void nautilus_window_initialize_menus_part_2 (NautilusWindow *window); void nautilus_menus_append_bookmark_to_menu (NautilusWindow *window, @@ -203,6 +204,7 @@ void nautilus_navigation_window_update_show_hide_menu_items /* Navigation window toolbar */ void nautilus_navigation_window_activate_throbber (NautilusNavigationWindow *window); void nautilus_navigation_window_initialize_toolbars (NautilusNavigationWindow *window); +void nautilus_navigation_window_load_extension_toolbar_items (NautilusNavigationWindow *window); void nautilus_navigation_window_set_throbber_active (NautilusNavigationWindow *window, gboolean active); void nautilus_navigation_window_go_back (NautilusNavigationWindow *window); diff --git a/src/nautilus-window-toolbars.c b/src/nautilus-window-toolbars.c index dae2b77ac..edac4c6ad 100644 --- a/src/nautilus-window-toolbars.c +++ b/src/nautilus-window-toolbars.c @@ -47,10 +47,12 @@ #include <gdk/gdkkeysyms.h> #include <libgnome/gnome-i18n.h> #include <libgnomeui/gnome-popup-menu.h> +#include <libnautilus-extension/nautilus-menu-provider.h> #include <libnautilus-private/nautilus-bonobo-extensions.h> #include <libnautilus-private/nautilus-bookmark.h> #include <libnautilus-private/nautilus-file-utilities.h> #include <libnautilus-private/nautilus-global-preferences.h> +#include <libnautilus-private/nautilus-module.h> #include <libnautilus-private/nautilus-theme.h> /* FIXME bugzilla.gnome.org 41243: @@ -59,6 +61,8 @@ */ #include "nautilus-desktop-window.h" +#define TOOLBAR_PATH_EXTENSION_ACTIONS "/Toolbar/Extra Buttons Placeholder/Extension Actions" + enum { TOOLBAR_ITEM_STYLE_PROP, TOOLBAR_ITEM_ORIENTATION_PROP @@ -366,3 +370,61 @@ nautilus_navigation_window_initialize_toolbars (NautilusNavigationWindow *window nautilus_window_ui_thaw (NAUTILUS_WINDOW (window)); } + +static GList * +get_extension_toolbar_items (NautilusNavigationWindow *window) +{ + GList *items; + GList *providers; + GList *l; + + providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); + items = NULL; + + for (l = providers; l != NULL; l = l->next) { + NautilusMenuProvider *provider; + GList *file_items; + + provider = NAUTILUS_MENU_PROVIDER (l->data); + file_items = nautilus_menu_provider_get_toolbar_items + (provider, + GTK_WIDGET (window), + NAUTILUS_WINDOW (window)->details->viewed_file); + items = g_list_concat (items, file_items); + } + + nautilus_module_extension_list_free (providers); + + return items; +} + +void +nautilus_navigation_window_load_extension_toolbar_items (NautilusNavigationWindow *window) +{ + GList *items; + GList *l; + + nautilus_bonobo_remove_menu_items_and_commands + (NAUTILUS_WINDOW (window)->details->shell_ui, + TOOLBAR_PATH_EXTENSION_ACTIONS); + + items = get_extension_toolbar_items (window); + + for (l = items; l != NULL; l = l->next) { + NautilusMenuItem *item; + + item = NAUTILUS_MENU_ITEM (l->data); + + nautilus_bonobo_add_extension_item_command + (NAUTILUS_WINDOW (window)->details->shell_ui, item); + + nautilus_bonobo_add_extension_toolbar_item + (NAUTILUS_WINDOW (window)->details->shell_ui, + TOOLBAR_PATH_EXTENSION_ACTIONS, + item); + + g_object_unref (item); + } + + g_list_free (items); +} diff --git a/src/nautilus-window.c b/src/nautilus-window.c index 9f491465a..bdb44b00a 100644 --- a/src/nautilus-window.c +++ b/src/nautilus-window.c @@ -222,12 +222,8 @@ ui_idle_handler (gpointer data) old_updating_bonobo_state = window->details->updating_bonobo_state; if (window->details->ui_pending_initialize_menus_part_2) { -#if !NEW_UI_COMPLETE - if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) { - nautilus_navigation_window_initialize_menus_part_2 (NAUTILUS_NAVIGATION_WINDOW (window)); - } -#endif - window->details->ui_pending_initialize_menus_part_2 = FALSE; + EEL_CALL_METHOD (NAUTILUS_WINDOW_CLASS, window, + merge_menus_2, (window)); } if (window->details->ui_is_frozen) { @@ -433,19 +429,6 @@ nautilus_window_allow_reload (NautilusWindow *window, gboolean allow) } void -nautilus_window_allow_burn_cd (NautilusWindow *window, gboolean allow) -{ - g_return_if_fail (NAUTILUS_IS_WINDOW (window)); - - nautilus_window_ui_freeze (window); - - nautilus_bonobo_set_hidden (window->details->shell_ui, - NAUTILUS_COMMAND_BURN_CD, !allow); - - nautilus_window_ui_thaw (window); -} - -void nautilus_window_go_home (NautilusWindow *window) { char *home_uri; @@ -470,26 +453,6 @@ nautilus_window_go_home (NautilusWindow *window) } void -nautilus_window_launch_cd_burner (NautilusWindow *window) -{ - GError *error; - char *argv[] = { "nautilus-cd-burner", NULL}; - - error = NULL; - if (!g_spawn_async (NULL, - argv, NULL, - G_SPAWN_SEARCH_PATH, - NULL, NULL, - NULL, - &error)) { - eel_show_error_dialog (_("Unable to launch the cd burner application."), error->message, - _("Can't Launch CD Burner"), - GTK_WINDOW (window)); - g_error_free (error); - } -} - -void nautilus_window_prompt_for_location (NautilusWindow *window) { g_assert (NAUTILUS_IS_WINDOW (window)); @@ -622,6 +585,12 @@ real_merge_menus (NautilusWindow *window) } static void +real_merge_menus_2 (NautilusWindow *window) +{ + window->details->ui_pending_initialize_menus_part_2 = FALSE; +} + +static void nautilus_window_constructed (NautilusWindow *window) { nautilus_window_ui_freeze (window); @@ -632,7 +601,6 @@ nautilus_window_constructed (NautilusWindow *window) merge_menus, (window)); nautilus_window_allow_stop (window, FALSE); - nautilus_window_allow_burn_cd (window, FALSE); /* Set up undo manager */ nautilus_undo_manager_attach (window->application->undo_manager, G_OBJECT (window)); @@ -1629,6 +1597,7 @@ nautilus_window_class_init (NautilusWindowClass *class) class->get_title = real_get_title; class->set_title = real_set_title; class->merge_menus = real_merge_menus; + class->merge_menus_2 = real_merge_menus_2; class->set_content_view_widget = real_set_content_view_widget; class->load_view_as_menu = real_load_view_as_menu; diff --git a/src/nautilus-window.h b/src/nautilus-window.h index d7e92c1a7..cd4791600 100644 --- a/src/nautilus-window.h +++ b/src/nautilus-window.h @@ -69,6 +69,7 @@ typedef struct { void (* set_title) (NautilusWindow *window, const char *title); void (* merge_menus) (NautilusWindow *window); + void (* merge_menus_2) (NautilusWindow *window); void (* load_view_as_menu) (NautilusWindow *window); void (* set_content_view_widget) (NautilusWindow *window, NautilusViewFrame *frame); |