summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Sullivan <sullivan@src.gnome.org>2001-04-07 18:57:37 +0000
committerJohn Sullivan <sullivan@src.gnome.org>2001-04-07 18:57:37 +0000
commit3104ed53fdf00c56fb6efcf81187f088ba9a14fc (patch)
treeef1adbd22ea5b73d05149b4bd0f4e3e75d15c2f4
parent704295febe36ba8b21ffac12d106a29becdb102a (diff)
downloadnautilus-3104ed53fdf00c56fb6efcf81187f088ba9a14fc.tar.gz
Fixed bug 3787 (If location bar is turned off, user cannot
change viewer) Now the "View as" choices, including "View as...", appear at the bottom of the View menu as well as in the location bar. * libnautilus-extensions/nautilus-bonobo-extensions.h: * libnautilus-extensions/nautilus-bonobo-extensions.c: (add_numbered_menu_item_internal): Handle radio item case; change signature to support this. (nautilus_bonobo_add_numbered_menu_item), (nautilus_bonobo_add_numbered_toggle_menu_item): Updated for change to add_numbered_menu_item_internal. (nautilus_bonobo_add_numbered_radio_menu_item): New function, just like its fellows but creates a one-of-many menu item. (nautilus_bonobo_get_numbered_menu_item_index_from_command), (nautilus_bonobo_get_numbered_menu_item_container_path_from_command): New functions that return info given one of the numbered-menu-item generated commands. Useful for callbacks when all you have in hand is the command itself. * src/nautilus-shell-ui.xml: Add "View as" command; add placeholders and separators and "View as" menu item to View menu. Also removed pixmap from Close Window menu item because it was silly to have a pixmap on exactly one item in the File menu. * src/nautilus-window-manage-views.c: Took "static" off of nautilus_window_content_matches_iid so I could make it public and use it in nautilus-window.c. * src/nautilus-window-private.h: Added fields to Details struct and prototypes for functions needed by View As stuff. * src/nautilus-window-menus.c: (view_menu_view_as_callback): New callback function used by "View as" verb. (nautilus_window_initialize_menus_part_1): Wire up "View as" verb; register for Bonobo UI events to catch radio items being selected. * src/nautilus-window.c: (set_dummy_initial_view_as_menu): Changed "View as ..." to "View as...", which matches the new name of "View as Other..." (free_stored_viewers): New function, frees and nulls out the view identifiers stored in the Details struct for the "View as" menus. (nautilus_window_destroy): Call free_stored_viewers. (activate_nth_short_list_item): New function, switches viewers by viewer index. (activate_extra_viewer): New function, switches to sometimes- present extra viewer (used when current viewer isn't in short list). (handle_view_as_item_from_bonobo_menu): If item whose state has changed is a "View as" item, dispatch accordingly. (nautilus_window_handle_ui_event_callback): Call handle_view_as_item_from_bonobo_menu if UI event was state changing to TRUE. (view_as_menu_switch_views_callback), (create_view_as_menu_item): Changed to store viewer index and whether viewer is "extra viewer" rather than storing NautilusViewIdentifier. This is used for option menu in location bar and now closely matches the mechanism used for the View menu. (add_view_as_bonobo_menu_item): New function used by View menu View As items. (replace_extra_viewer_in_view_as_menus), (nautilus_window_synch_view_as_menus): (load_view_as_menus_callback): Renamed and cleaned up to separate information gathering from widget updating; now handle View As items in View menu also. (chose_component_callback): Added FIXME for pre-existing bug 8000. (nautilus_window_show_view_as_dialog): New function, extracted from view_as_menu_choose_view_callback. (view_as_menu_choose_view_callback): Now calls extracted function. (refresh_stored_viewers): New function, updates the list of viewers stored in the Details struct.
-rw-r--r--ChangeLog77
-rw-r--r--libnautilus-extensions/nautilus-bonobo-extensions.c118
-rw-r--r--libnautilus-extensions/nautilus-bonobo-extensions.h9
-rw-r--r--libnautilus-private/nautilus-bonobo-extensions.c118
-rw-r--r--libnautilus-private/nautilus-bonobo-extensions.h9
-rw-r--r--src/nautilus-navigation-window-menus.c15
-rw-r--r--src/nautilus-navigation-window.c352
-rw-r--r--src/nautilus-object-window.c352
-rw-r--r--src/nautilus-shell-ui.xml10
-rw-r--r--src/nautilus-spatial-window.c352
-rw-r--r--src/nautilus-window-manage-views.c6
-rw-r--r--src/nautilus-window-menus.c15
-rw-r--r--src/nautilus-window-private.h16
-rw-r--r--src/nautilus-window.c352
14 files changed, 1423 insertions, 378 deletions
diff --git a/ChangeLog b/ChangeLog
index 884063f64..f2e311130 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,80 @@
+2001-04-07 John Sullivan <sullivan@eazel.com>
+
+ Fixed bug 3787 (If location bar is turned off, user cannot
+ change viewer)
+
+ Now the "View as" choices, including "View as...", appear
+ at the bottom of the View menu as well as in the location bar.
+
+ * libnautilus-extensions/nautilus-bonobo-extensions.h:
+ * libnautilus-extensions/nautilus-bonobo-extensions.c:
+ (add_numbered_menu_item_internal): Handle radio item case; change
+ signature to support this.
+ (nautilus_bonobo_add_numbered_menu_item),
+ (nautilus_bonobo_add_numbered_toggle_menu_item):
+ Updated for change to add_numbered_menu_item_internal.
+ (nautilus_bonobo_add_numbered_radio_menu_item): New function,
+ just like its fellows but creates a one-of-many menu item.
+ (nautilus_bonobo_get_numbered_menu_item_index_from_command),
+ (nautilus_bonobo_get_numbered_menu_item_container_path_from_command):
+ New functions that return info given one of the numbered-menu-item
+ generated commands. Useful for callbacks when all you have in hand
+ is the command itself.
+
+ * src/nautilus-shell-ui.xml: Add "View as" command; add placeholders
+ and separators and "View as" menu item to View menu.
+ Also removed pixmap from Close Window menu item because it was
+ silly to have a pixmap on exactly one item in the File menu.
+
+ * src/nautilus-window-manage-views.c: Took "static" off of
+ nautilus_window_content_matches_iid so I could make it public
+ and use it in nautilus-window.c.
+
+ * src/nautilus-window-private.h: Added fields to Details struct
+ and prototypes for functions needed by View As stuff.
+
+ * src/nautilus-window-menus.c:
+ (view_menu_view_as_callback): New callback function used by
+ "View as" verb.
+ (nautilus_window_initialize_menus_part_1): Wire up "View as"
+ verb; register for Bonobo UI events to catch radio items being
+ selected.
+
+ * src/nautilus-window.c:
+ (set_dummy_initial_view_as_menu): Changed "View as ..." to
+ "View as...", which matches the new name of "View as Other..."
+ (free_stored_viewers): New function, frees and nulls out the
+ view identifiers stored in the Details struct for the "View as"
+ menus.
+ (nautilus_window_destroy): Call free_stored_viewers.
+ (activate_nth_short_list_item): New function, switches viewers
+ by viewer index.
+ (activate_extra_viewer): New function, switches to sometimes-
+ present extra viewer (used when current viewer isn't in short list).
+ (handle_view_as_item_from_bonobo_menu): If item whose state has
+ changed is a "View as" item, dispatch accordingly.
+ (nautilus_window_handle_ui_event_callback): Call
+ handle_view_as_item_from_bonobo_menu if UI event was state
+ changing to TRUE.
+ (view_as_menu_switch_views_callback),
+ (create_view_as_menu_item): Changed to store viewer index and
+ whether viewer is "extra viewer" rather than storing
+ NautilusViewIdentifier. This is used for option menu in location
+ bar and now closely matches the mechanism used for the View menu.
+ (add_view_as_bonobo_menu_item): New function used by View menu
+ View As items.
+ (replace_extra_viewer_in_view_as_menus),
+ (nautilus_window_synch_view_as_menus):
+ (load_view_as_menus_callback): Renamed and cleaned up to separate
+ information gathering from widget updating; now handle View As
+ items in View menu also.
+ (chose_component_callback): Added FIXME for pre-existing bug 8000.
+ (nautilus_window_show_view_as_dialog): New function, extracted
+ from view_as_menu_choose_view_callback.
+ (view_as_menu_choose_view_callback): Now calls extracted function.
+ (refresh_stored_viewers): New function, updates the list of viewers
+ stored in the Details struct.
+
2001-04-06 Rebecca Schulman <rebecka@eazel.com>
Fix bugzilla.eazel.com bug 7933, and the nautilus
half of bug 7934, by removing the search preferences
diff --git a/libnautilus-extensions/nautilus-bonobo-extensions.c b/libnautilus-extensions/nautilus-bonobo-extensions.c
index 84f5c4536..b7da068c8 100644
--- a/libnautilus-extensions/nautilus-bonobo-extensions.c
+++ b/libnautilus-extensions/nautilus-bonobo-extensions.c
@@ -43,6 +43,12 @@ struct NautilusBonoboActivationHandle {
guint idle_id;
};
+typedef enum {
+ NUMBERED_MENU_ITEM_PLAIN,
+ NUMBERED_MENU_ITEM_TOGGLE,
+ NUMBERED_MENU_ITEM_RADIO
+} NumberedMenuItemType;
+
void
nautilus_bonobo_set_accelerator (BonoboUIComponent *ui,
const char *path,
@@ -192,13 +198,55 @@ nautilus_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
return command_name;
}
+guint
+nautilus_bonobo_get_numbered_menu_item_index_from_command (const char *command)
+{
+ char *path;
+ char *index_string;
+ int index;
+ gboolean got_index;
+
+ path = gnome_vfs_unescape_string (command, NULL);
+ index_string = strrchr (path, '/');
+
+ if (index_string == NULL) {
+ got_index = FALSE;
+ } else {
+ got_index = eel_str_to_int (index_string + 1, &index);
+ }
+ g_free (path);
+
+ g_return_val_if_fail (got_index, 0);
+
+ return index;
+}
+
+char *
+nautilus_bonobo_get_numbered_menu_item_container_path_from_command (const char *command)
+{
+ char *path;
+ char *index_string;
+ char *container_path;
+
+ path = gnome_vfs_unescape_string (command, NULL);
+ index_string = strrchr (path, '/');
+
+ container_path = index_string == NULL
+ ? NULL
+ : g_strndup (path, index_string - path);
+ g_free (path);
+
+ return container_path;
+}
+
static void
add_numbered_menu_item_internal (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
- gboolean is_toggle,
- GdkPixbuf *pixbuf)
+ NumberedMenuItemType type,
+ GdkPixbuf *pixbuf,
+ const char *radio_group_name)
{
char *xml_item, *xml_command;
char *encoded_label, *command_name;
@@ -207,7 +255,9 @@ add_numbered_menu_item_internal (BonoboUIComponent *ui,
g_assert (BONOBO_IS_UI_COMPONENT (ui));
g_assert (container_path != NULL);
g_assert (label != NULL);
- g_assert (!is_toggle || pixbuf == NULL);
+ g_assert (type == NUMBERED_MENU_ITEM_PLAIN || pixbuf == NULL);
+ g_assert (type == NUMBERED_MENU_ITEM_RADIO || radio_group_name == NULL);
+ g_assert (type != NUMBERED_MENU_ITEM_RADIO || radio_group_name != NULL);
/* Because we are constructing the XML ourselves, we need to
* encode the label.
@@ -219,23 +269,32 @@ add_numbered_menu_item_internal (BonoboUIComponent *ui,
command_name = nautilus_bonobo_get_numbered_menu_item_command
(ui, container_path, index);
- /* Note: we ignore the pixbuf for toggle items. This could be changed
- * if we ever want a toggle item that also has a pixbuf.
- */
- if (is_toggle) {
+
+ switch (type) {
+ case NUMBERED_MENU_ITEM_TOGGLE:
xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" id=\"%s\" type=\"toggle\"/>\n",
item_name, encoded_label, command_name);
- } else if (pixbuf != NULL) {
- /* Encode pixbuf type and data into XML string */
- pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
-
- xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
- item_name, encoded_label, command_name, pixbuf_data);
- g_free (pixbuf_data);
- } else {
- xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\"/>\n",
- item_name, encoded_label, command_name);
+ break;
+ case NUMBERED_MENU_ITEM_RADIO:
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" id=\"%s\" type=\"radio\" group=\"%s\"/>\n",
+ item_name, encoded_label, command_name, radio_group_name);
+ break;
+ case NUMBERED_MENU_ITEM_PLAIN:
+ if (pixbuf != NULL) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
+ item_name, encoded_label, command_name, pixbuf_data);
+ g_free (pixbuf_data);
+ } else {
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\"/>\n",
+ item_name, encoded_label, command_name);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ xml_item = NULL; /* keep compiler happy */
}
+
g_free (encoded_label);
g_free (item_name);
@@ -269,11 +328,11 @@ nautilus_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
- add_numbered_menu_item_internal (ui, container_path, index, label, FALSE, pixbuf);
+ add_numbered_menu_item_internal (ui, container_path, index, label, NUMBERED_MENU_ITEM_PLAIN, pixbuf, NULL);
}
/* Add a menu item specified by number into a given path. Used for
- * dynamically creating a related series of menu items. Each index
+ * dynamically creating a related series of toggle menu items. Each index
* must be unique (normal use is to call this in a loop, and
* increment the index for each item).
*/
@@ -287,7 +346,26 @@ nautilus_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
- add_numbered_menu_item_internal (ui, container_path, index, label, TRUE, NULL);
+ add_numbered_menu_item_internal (ui, container_path, index, label, NUMBERED_MENU_ITEM_TOGGLE, NULL, NULL);
+}
+
+/* Add a menu item specified by number into a given path. Used for
+ * dynamically creating a related series of radio menu items. Each index
+ * must be unique (normal use is to call this in a loop, and
+ * increment the index for each item).
+ */
+void
+nautilus_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ const char *radio_group_name)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+
+ add_numbered_menu_item_internal (ui, container_path, index, label, NUMBERED_MENU_ITEM_RADIO, NULL, radio_group_name);
}
void
diff --git a/libnautilus-extensions/nautilus-bonobo-extensions.h b/libnautilus-extensions/nautilus-bonobo-extensions.h
index a39dc561d..052191f90 100644
--- a/libnautilus-extensions/nautilus-bonobo-extensions.h
+++ b/libnautilus-extensions/nautilus-bonobo-extensions.h
@@ -68,12 +68,21 @@ void nautilus_bonobo_add_numbered_toggle_menu_item
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);
+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);
diff --git a/libnautilus-private/nautilus-bonobo-extensions.c b/libnautilus-private/nautilus-bonobo-extensions.c
index 84f5c4536..b7da068c8 100644
--- a/libnautilus-private/nautilus-bonobo-extensions.c
+++ b/libnautilus-private/nautilus-bonobo-extensions.c
@@ -43,6 +43,12 @@ struct NautilusBonoboActivationHandle {
guint idle_id;
};
+typedef enum {
+ NUMBERED_MENU_ITEM_PLAIN,
+ NUMBERED_MENU_ITEM_TOGGLE,
+ NUMBERED_MENU_ITEM_RADIO
+} NumberedMenuItemType;
+
void
nautilus_bonobo_set_accelerator (BonoboUIComponent *ui,
const char *path,
@@ -192,13 +198,55 @@ nautilus_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
return command_name;
}
+guint
+nautilus_bonobo_get_numbered_menu_item_index_from_command (const char *command)
+{
+ char *path;
+ char *index_string;
+ int index;
+ gboolean got_index;
+
+ path = gnome_vfs_unescape_string (command, NULL);
+ index_string = strrchr (path, '/');
+
+ if (index_string == NULL) {
+ got_index = FALSE;
+ } else {
+ got_index = eel_str_to_int (index_string + 1, &index);
+ }
+ g_free (path);
+
+ g_return_val_if_fail (got_index, 0);
+
+ return index;
+}
+
+char *
+nautilus_bonobo_get_numbered_menu_item_container_path_from_command (const char *command)
+{
+ char *path;
+ char *index_string;
+ char *container_path;
+
+ path = gnome_vfs_unescape_string (command, NULL);
+ index_string = strrchr (path, '/');
+
+ container_path = index_string == NULL
+ ? NULL
+ : g_strndup (path, index_string - path);
+ g_free (path);
+
+ return container_path;
+}
+
static void
add_numbered_menu_item_internal (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
- gboolean is_toggle,
- GdkPixbuf *pixbuf)
+ NumberedMenuItemType type,
+ GdkPixbuf *pixbuf,
+ const char *radio_group_name)
{
char *xml_item, *xml_command;
char *encoded_label, *command_name;
@@ -207,7 +255,9 @@ add_numbered_menu_item_internal (BonoboUIComponent *ui,
g_assert (BONOBO_IS_UI_COMPONENT (ui));
g_assert (container_path != NULL);
g_assert (label != NULL);
- g_assert (!is_toggle || pixbuf == NULL);
+ g_assert (type == NUMBERED_MENU_ITEM_PLAIN || pixbuf == NULL);
+ g_assert (type == NUMBERED_MENU_ITEM_RADIO || radio_group_name == NULL);
+ g_assert (type != NUMBERED_MENU_ITEM_RADIO || radio_group_name != NULL);
/* Because we are constructing the XML ourselves, we need to
* encode the label.
@@ -219,23 +269,32 @@ add_numbered_menu_item_internal (BonoboUIComponent *ui,
command_name = nautilus_bonobo_get_numbered_menu_item_command
(ui, container_path, index);
- /* Note: we ignore the pixbuf for toggle items. This could be changed
- * if we ever want a toggle item that also has a pixbuf.
- */
- if (is_toggle) {
+
+ switch (type) {
+ case NUMBERED_MENU_ITEM_TOGGLE:
xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" id=\"%s\" type=\"toggle\"/>\n",
item_name, encoded_label, command_name);
- } else if (pixbuf != NULL) {
- /* Encode pixbuf type and data into XML string */
- pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
-
- xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
- item_name, encoded_label, command_name, pixbuf_data);
- g_free (pixbuf_data);
- } else {
- xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\"/>\n",
- item_name, encoded_label, command_name);
+ break;
+ case NUMBERED_MENU_ITEM_RADIO:
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" id=\"%s\" type=\"radio\" group=\"%s\"/>\n",
+ item_name, encoded_label, command_name, radio_group_name);
+ break;
+ case NUMBERED_MENU_ITEM_PLAIN:
+ if (pixbuf != NULL) {
+ pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
+ item_name, encoded_label, command_name, pixbuf_data);
+ g_free (pixbuf_data);
+ } else {
+ xml_item = g_strdup_printf ("<menuitem name=\"%s\" label=\"%s\" verb=\"%s\"/>\n",
+ item_name, encoded_label, command_name);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ xml_item = NULL; /* keep compiler happy */
}
+
g_free (encoded_label);
g_free (item_name);
@@ -269,11 +328,11 @@ nautilus_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
- add_numbered_menu_item_internal (ui, container_path, index, label, FALSE, pixbuf);
+ add_numbered_menu_item_internal (ui, container_path, index, label, NUMBERED_MENU_ITEM_PLAIN, pixbuf, NULL);
}
/* Add a menu item specified by number into a given path. Used for
- * dynamically creating a related series of menu items. Each index
+ * dynamically creating a related series of toggle menu items. Each index
* must be unique (normal use is to call this in a loop, and
* increment the index for each item).
*/
@@ -287,7 +346,26 @@ nautilus_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
- add_numbered_menu_item_internal (ui, container_path, index, label, TRUE, NULL);
+ add_numbered_menu_item_internal (ui, container_path, index, label, NUMBERED_MENU_ITEM_TOGGLE, NULL, NULL);
+}
+
+/* Add a menu item specified by number into a given path. Used for
+ * dynamically creating a related series of radio menu items. Each index
+ * must be unique (normal use is to call this in a loop, and
+ * increment the index for each item).
+ */
+void
+nautilus_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
+ const char *container_path,
+ guint index,
+ const char *label,
+ const char *radio_group_name)
+{
+ g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
+ g_return_if_fail (container_path != NULL);
+ g_return_if_fail (label != NULL);
+
+ add_numbered_menu_item_internal (ui, container_path, index, label, NUMBERED_MENU_ITEM_RADIO, NULL, radio_group_name);
}
void
diff --git a/libnautilus-private/nautilus-bonobo-extensions.h b/libnautilus-private/nautilus-bonobo-extensions.h
index a39dc561d..052191f90 100644
--- a/libnautilus-private/nautilus-bonobo-extensions.h
+++ b/libnautilus-private/nautilus-bonobo-extensions.h
@@ -68,12 +68,21 @@ void nautilus_bonobo_add_numbered_toggle_menu_item
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);
+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);
diff --git a/src/nautilus-navigation-window-menus.c b/src/nautilus-navigation-window-menus.c
index 3592a551f..cbc7c4c4f 100644
--- a/src/nautilus-navigation-window-menus.c
+++ b/src/nautilus-navigation-window-menus.c
@@ -513,6 +513,14 @@ view_menu_zoom_normal_callback (BonoboUIComponent *component,
}
static void
+view_menu_view_as_callback (BonoboUIComponent *component,
+ gpointer user_data,
+ const char *verb)
+{
+ nautilus_window_show_view_as_dialog (NAUTILUS_WINDOW (user_data));
+}
+
+static void
bookmarks_menu_add_bookmark_callback (BonoboUIComponent *component,
gpointer user_data,
const char *verb)
@@ -1261,6 +1269,7 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window)
BONOBO_UI_VERB ("Zoom In", view_menu_zoom_in_callback),
BONOBO_UI_VERB ("Zoom Out", view_menu_zoom_out_callback),
BONOBO_UI_VERB ("Zoom Normal", view_menu_zoom_normal_callback),
+ BONOBO_UI_VERB ("View as", view_menu_view_as_callback),
BONOBO_UI_VERB ("Add Bookmark", bookmarks_menu_add_bookmark_callback),
BONOBO_UI_VERB ("Edit Bookmarks", bookmarks_menu_edit_bookmarks_callback),
@@ -1308,6 +1317,12 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window)
/* Update the user level menu items for the first time */
user_level_changed_callback (window);
+ /* Register to catch Bonobo UI events so we can notice View As changes */
+ gtk_signal_connect (GTK_OBJECT (window->details->shell_ui),
+ "ui_event",
+ nautilus_window_handle_ui_event_callback,
+ window);
+
bonobo_ui_component_thaw (window->details->shell_ui, NULL);
#ifndef ENABLE_PROFILER
diff --git a/src/nautilus-navigation-window.c b/src/nautilus-navigation-window.c
index 9fceb61de..bb883d8b8 100644
--- a/src/nautilus-navigation-window.c
+++ b/src/nautilus-navigation-window.c
@@ -96,7 +96,14 @@
#define STATUS_BAR_PATH "/status"
#define MENU_BAR_PATH "/menu"
+#define COMMAND_PREFIX "/commands/"
#define NAUTILUS_COMMAND_TOGGLE_FIND_MODE "/commands/Toggle Find Mode"
+#define NAUTILUS_COMMAND_VIEW_AS "/commands/View as"
+
+#define NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER "/menu/View/View Choices/Extra Viewer"
+#define NAUTILUS_MENU_PATH_BEFORE_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
+#define NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER "/menu/View/View Choices/Short List"
+#define NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
enum {
ARG_0,
@@ -634,7 +641,7 @@ set_dummy_initial_view_as_menu (NautilusWindow *window)
GtkWidget *menu_item;
new_menu = gtk_menu_new ();
- menu_item = gtk_menu_item_new_with_label (_("View as ..."));
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -881,6 +888,17 @@ nautilus_window_get_arg (GtkObject *object,
}
}
+static void
+free_stored_viewers (NautilusWindow *window)
+{
+ eel_g_list_free_deep_custom (window->details->short_list_viewers,
+ (GFunc) nautilus_view_identifier_free,
+ NULL);
+ window->details->short_list_viewers = NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = NULL;
+}
+
static void
nautilus_window_destroy (GtkObject *object)
{
@@ -918,6 +936,8 @@ nautilus_window_destroy (GtkObject *object)
g_list_free (window->sidebar_panels);
nautilus_view_identifier_free (window->content_view_id);
+
+ free_stored_viewers (window);
g_free (window->details->location);
eel_g_list_free_deep (window->details->selection);
@@ -1083,23 +1103,80 @@ nautilus_window_size_request (GtkWidget *widget,
*/
static void
+activate_nth_short_list_item (NautilusWindow *window, guint index)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (index < g_list_length (window->details->short_list_viewers));
+
+ nautilus_window_set_content_view (window,
+ g_list_nth_data (window->details->short_list_viewers, index));
+}
+
+static void
+activate_extra_viewer (NautilusWindow *window)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (window->details->extra_viewer != NULL);
+
+ nautilus_window_set_content_view (window, window->details->extra_viewer);
+}
+
+static void
+handle_view_as_item_from_bonobo_menu (NautilusWindow *window, const char *id)
+{
+ char *container_path;
+
+ container_path = nautilus_bonobo_get_numbered_menu_item_container_path_from_command (id);
+
+ if (strcmp (container_path, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER) == 0) {
+ activate_nth_short_list_item
+ (window,
+ nautilus_bonobo_get_numbered_menu_item_index_from_command (id));
+ } else if (strcmp (container_path, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER) == 0) {
+ g_return_if_fail
+ (nautilus_bonobo_get_numbered_menu_item_index_from_command (id) == 0);
+ activate_extra_viewer (window);
+ }
+
+ g_free (container_path);
+}
+
+void
+nautilus_window_handle_ui_event_callback (BonoboUIComponent *ui,
+ const char *id,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ NautilusWindow *window)
+{
+ if (type == Bonobo_UIComponent_STATE_CHANGED
+ && strcmp (state, "1") == 0) {
+ handle_view_as_item_from_bonobo_menu (window, id);
+ }
+}
+
+static void
view_as_menu_switch_views_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
- NautilusViewIdentifier *identifier;
+ int viewer_index;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
-
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
- identifier = (NautilusViewIdentifier *) gtk_object_get_data (GTK_OBJECT (widget), "identifier");
-
- nautilus_window_set_content_view (window, identifier);
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
+
+ window = NAUTILUS_WINDOW (data);
+
+ if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "extra viewer")) == TRUE) {
+ activate_extra_viewer (window);
+ } else {
+ viewer_index = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "viewer index"));
+ activate_nth_short_list_item (window, viewer_index);
+ }
}
-/* Note: The identifier parameter ownership is handed off to the menu item. */
static GtkWidget *
-create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identifier)
+create_view_as_menu_item (NautilusWindow *window,
+ NautilusViewIdentifier *identifier,
+ guint index)
{
GtkWidget *menu_item;
char *menu_label;
@@ -1111,16 +1188,12 @@ create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identi
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_switch_views_callback,
- NULL);
+ window);
- /* Store copy of iid in item; free when item destroyed. */
- gtk_object_set_data_full (GTK_OBJECT (menu_item),
- "identifier",
- identifier,
- (GtkDestroyNotify) nautilus_view_identifier_free);
+ gtk_object_set_data (GTK_OBJECT (menu_item),
+ "viewer index",
+ GINT_TO_POINTER (index));
- /* Store reference to window in item; no need to free this. */
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
gtk_widget_show (menu_item);
return menu_item;
@@ -1138,17 +1211,50 @@ new_gtk_separator (void)
return result;
}
+static void
+add_view_as_bonobo_menu_item (NautilusWindow *window,
+ const char *placeholder_path,
+ NautilusViewIdentifier *identifier,
+ int index)
+{
+ char *tip;
+ char *item_path;
+
+ nautilus_bonobo_add_numbered_radio_menu_item
+ (window->details->shell_ui,
+ placeholder_path,
+ index,
+ identifier->view_as_label,
+ "viewers group");
+
+ tip = g_strdup_printf (_("Display this location with the %s"), identifier->viewer_label);
+ item_path = nautilus_bonobo_get_numbered_menu_item_path
+ (window->details->shell_ui,
+ placeholder_path,
+ index);
+ nautilus_bonobo_set_tip (window->details->shell_ui, item_path, tip);
+ g_free (item_path);
+ g_free (tip);
+}
+
/* Make a special first item in the "View as" option menu that represents
* the current content view. This should only be called if the current
* content view isn't already in the "View as" option menu.
*/
static void
-replace_special_current_view_in_view_as_menu (NautilusWindow *window)
+replace_extra_viewer_in_view_as_menus (NautilusWindow *window)
{
GtkWidget *menu;
GtkWidget *first_menu_item;
GtkWidget *new_menu_item;
-
+ gboolean had_extra_viewer;
+
+ had_extra_viewer = window->details->extra_viewer != NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = nautilus_view_identifier_copy (window->content_view_id);
+ g_assert (window->details->extra_viewer != NULL);
+
+ /* Update the View As option menu */
menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
/* Remove menu before changing contents so it is resized properly
@@ -1157,73 +1263,103 @@ replace_special_current_view_in_view_as_menu (NautilusWindow *window)
gtk_widget_ref (menu);
gtk_option_menu_remove_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
- g_assert (first_menu_item != NULL);
-
- if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "current content view"))) {
+ if (had_extra_viewer) {
+ first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
+ g_assert (first_menu_item != NULL);
+ g_assert (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "extra viewer")) == TRUE);
gtk_container_remove (GTK_CONTAINER (menu), first_menu_item);
} else {
/* Prepend separator. */
gtk_menu_prepend (GTK_MENU (menu), new_gtk_separator ());
}
- new_menu_item = create_view_as_menu_item (window, nautilus_view_identifier_copy (window->content_view_id));
- gtk_object_set_data (GTK_OBJECT (new_menu_item), "current content view", GINT_TO_POINTER (TRUE));
+ new_menu_item = create_view_as_menu_item (window, window->details->extra_viewer, 0);
+ gtk_object_set_data (GTK_OBJECT (new_menu_item), "extra viewer", GINT_TO_POINTER (TRUE));
gtk_menu_prepend (GTK_MENU (menu), new_menu_item);
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu), menu);
gtk_widget_unref (menu);
+
+ /* Also update the Bonobo View menu item */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER,
+ window->details->extra_viewer,
+ 0);
}
/**
- * nautilus_window_synch_view_as_menu:
+ * nautilus_window_synch_view_as_menus:
*
- * Set the visible item of the "View as" option menu to
+ * Set the visible item of the "View as" option menu and
+ * the marked "View as" item in the View menu to
* match the current content view.
*
* @window: The NautilusWindow whose "View as" option menu should be synched.
*/
void
-nautilus_window_synch_view_as_menu (NautilusWindow *window)
+nautilus_window_synch_view_as_menus (NautilusWindow *window)
{
- GList *children, *child;
- GtkWidget *menu;
- const char *content_view_iid;
- NautilusViewIdentifier *item_id;
- int index, matching_index;
+ int index;
+ char *verb_name, *command_path;
+ GList *node;
+ int option_menu_index;
+ int numbered_menu_item_index;
+ const char *numbered_menu_item_container_path;
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
- menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- if (menu == NULL) {
+ if (window->content_view == NULL) {
return;
}
-
- children = gtk_container_children (GTK_CONTAINER (menu));
- matching_index = -1;
-
- if (window->content_view != NULL) {
- content_view_iid = nautilus_view_frame_get_view_iid (window->content_view);
- for (child = children, index = 0; child != NULL; child = child->next, ++index) {
- item_id = (NautilusViewIdentifier *) gtk_object_get_data
- (GTK_OBJECT (child->data), "identifier");
- if (item_id != NULL && strcmp (content_view_iid, item_id->iid) == 0) {
- matching_index = index;
+ option_menu_index = -1;
+ numbered_menu_item_index = -1;
+ numbered_menu_item_container_path = 0;
+
+ if (window->details->extra_viewer != NULL &&
+ nautilus_window_content_view_matches_iid (window, window->details->extra_viewer->iid)) {
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
+ } else {
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ if (nautilus_window_content_view_matches_iid (window, ((NautilusViewIdentifier *)node->data)->iid)) {
+ option_menu_index = window->details->extra_viewer == NULL
+ ? index
+ : index + 2;
+ numbered_menu_item_index = index;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER;
break;
}
}
}
- if (matching_index == -1) {
- replace_special_current_view_in_view_as_menu (window);
- matching_index = 0;
+ if (option_menu_index == -1) {
+ replace_extra_viewer_in_view_as_menus (window);
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
}
+ g_assert (option_menu_index >= 0);
+ g_assert (numbered_menu_item_index >= 0);
+ g_assert (numbered_menu_item_container_path != NULL);
+
+ /* Make option menu show the right item */
gtk_option_menu_set_history (GTK_OPTION_MENU (window->view_as_option_menu),
- matching_index);
+ option_menu_index);
- g_list_free (children);
+ /* Make View menu in menu bar mark the right item */
+ verb_name = nautilus_bonobo_get_numbered_menu_item_command
+ (window->details->shell_ui,
+ numbered_menu_item_container_path,
+ numbered_menu_item_index);
+ command_path = g_strconcat (COMMAND_PREFIX, verb_name, NULL);
+ nautilus_bonobo_set_toggle_state (window->details->shell_ui, command_path, TRUE);
+ g_free (command_path);
+ g_free (verb_name);
}
static void
@@ -1242,7 +1378,10 @@ chose_component_callback (NautilusViewIdentifier *identifier, gpointer callback_
* now, hardwire this case, which is the most obvious one by
* far.
*/
- nautilus_window_load_view_as_menu (window);
+ /* FIXME bugzilla.eazel.com 8000: It's possible to get the
+ * same view listed twice in the menu due to this call.
+ */
+ nautilus_window_load_view_as_menus (window);
}
static void
@@ -1255,71 +1394,118 @@ cancel_chose_component_callback (NautilusWindow *window)
}
}
+void
+nautilus_window_show_view_as_dialog (NautilusWindow *window)
+{
+ g_return_if_fail (NAUTILUS_IS_WINDOW (window));
+
+ /* Call back when the user chose the component. */
+ cancel_chose_component_callback (window);
+ nautilus_choose_component_for_file (window->details->viewed_file,
+ GTK_WINDOW (window),
+ chose_component_callback,
+ window);
+}
+
static void
view_as_menu_choose_view_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
+ window = NAUTILUS_WINDOW (data);
/* Set the option menu back to its previous setting (Don't
- * leave it on this dialog-producing "View as Other..."
+ * leave it on this dialog-producing "View as..."
* setting). If the menu choice causes a content view change,
* this will be updated again later, in
- * nautilus_window_load_view_as_menu. Do this right away so
+ * nautilus_window_load_view_as_menus. Do this right away so
* the user never sees the option menu set to "View as
* Other...".
*/
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
- /* Call back when the user chose the component. */
- cancel_chose_component_callback (window);
- nautilus_choose_component_for_file (window->details->viewed_file,
- GTK_WINDOW (window),
- chose_component_callback,
- window);
+ nautilus_window_show_view_as_dialog (window);
}
static void
-load_view_as_menu_callback (NautilusFile *file,
+refresh_stored_viewers (NautilusWindow *window)
+{
+ GList *components;
+ GList *node;
+ NautilusViewIdentifier *identifier;
+
+ free_stored_viewers (window);
+
+ components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
+ for (node = components; node != NULL; node = node->next) {
+ identifier = nautilus_view_identifier_new_from_content_view (node->data);
+ window->details->short_list_viewers =
+ g_list_append (window->details->short_list_viewers, identifier);
+ }
+ gnome_vfs_mime_component_list_free (components);
+}
+
+static void
+load_view_as_menus_callback (NautilusFile *file,
gpointer callback_data)
{
- GList *components;
- GList *p;
GtkWidget *new_menu;
GtkWidget *menu_item;
+ GList *node;
NautilusWindow *window;
+ int index;
window = NAUTILUS_WINDOW (callback_data);
g_return_if_fail (GTK_IS_OPTION_MENU (window->view_as_option_menu));
-
+
+ /* Clear out the menu items created last time. For the option menu, we need do
+ * nothing since we replace the entire menu. For the View menu, we have
+ * to do this explicitly.
+ */
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER);
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER);
+
+ refresh_stored_viewers (window);
+
new_menu = gtk_menu_new ();
/* Add a menu item for each view in the preferred list for this location. */
- components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
- for (p = components; p != NULL; p = p->next) {
- menu_item = create_view_as_menu_item
- (window, nautilus_view_identifier_new_from_content_view (p->data));
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ /* Menu item in option menu. This doesn't use Bonobo, for various
+ * historical and technical reasons.
+ */
+ menu_item = create_view_as_menu_item (window, node->data, index);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
+
+ /* Menu item in View menu. */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER,
+ node->data,
+ index);
}
- gnome_vfs_mime_component_list_free (components);
- /* Add separator before "Other" if there are any other viewers in menu. */
- if (components != NULL) {
+ /* Add/Show separator before "View as..." if there are any other viewers in menu. */
+ if (window->details->short_list_viewers != NULL) {
gtk_menu_append (GTK_MENU (new_menu), new_gtk_separator ());
}
+ nautilus_bonobo_set_hidden (window->details->shell_ui,
+ NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR,
+ window->details->short_list_viewers == NULL);
- /* Add "View as Other..." extra bonus choice. */
- menu_item = gtk_menu_item_new_with_label (_("View as Other..."));
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
+ /* Add "View as..." extra bonus choice. */
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_choose_view_callback,
- NULL);
+ window);
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -1329,19 +1515,19 @@ load_view_as_menu_callback (NautilusFile *file,
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu),
new_menu);
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
}
static void
cancel_view_as_callback (NautilusWindow *window)
{
nautilus_file_cancel_call_when_ready (window->details->viewed_file,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
}
void
-nautilus_window_load_view_as_menu (NautilusWindow *window)
+nautilus_window_load_view_as_menus (NautilusWindow *window)
{
GList *attributes;
@@ -1352,7 +1538,7 @@ nautilus_window_load_view_as_menu (NautilusWindow *window)
cancel_view_as_callback (window);
nautilus_file_call_when_ready (window->details->viewed_file,
attributes,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
g_list_free (attributes);
diff --git a/src/nautilus-object-window.c b/src/nautilus-object-window.c
index 9fceb61de..bb883d8b8 100644
--- a/src/nautilus-object-window.c
+++ b/src/nautilus-object-window.c
@@ -96,7 +96,14 @@
#define STATUS_BAR_PATH "/status"
#define MENU_BAR_PATH "/menu"
+#define COMMAND_PREFIX "/commands/"
#define NAUTILUS_COMMAND_TOGGLE_FIND_MODE "/commands/Toggle Find Mode"
+#define NAUTILUS_COMMAND_VIEW_AS "/commands/View as"
+
+#define NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER "/menu/View/View Choices/Extra Viewer"
+#define NAUTILUS_MENU_PATH_BEFORE_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
+#define NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER "/menu/View/View Choices/Short List"
+#define NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
enum {
ARG_0,
@@ -634,7 +641,7 @@ set_dummy_initial_view_as_menu (NautilusWindow *window)
GtkWidget *menu_item;
new_menu = gtk_menu_new ();
- menu_item = gtk_menu_item_new_with_label (_("View as ..."));
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -881,6 +888,17 @@ nautilus_window_get_arg (GtkObject *object,
}
}
+static void
+free_stored_viewers (NautilusWindow *window)
+{
+ eel_g_list_free_deep_custom (window->details->short_list_viewers,
+ (GFunc) nautilus_view_identifier_free,
+ NULL);
+ window->details->short_list_viewers = NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = NULL;
+}
+
static void
nautilus_window_destroy (GtkObject *object)
{
@@ -918,6 +936,8 @@ nautilus_window_destroy (GtkObject *object)
g_list_free (window->sidebar_panels);
nautilus_view_identifier_free (window->content_view_id);
+
+ free_stored_viewers (window);
g_free (window->details->location);
eel_g_list_free_deep (window->details->selection);
@@ -1083,23 +1103,80 @@ nautilus_window_size_request (GtkWidget *widget,
*/
static void
+activate_nth_short_list_item (NautilusWindow *window, guint index)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (index < g_list_length (window->details->short_list_viewers));
+
+ nautilus_window_set_content_view (window,
+ g_list_nth_data (window->details->short_list_viewers, index));
+}
+
+static void
+activate_extra_viewer (NautilusWindow *window)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (window->details->extra_viewer != NULL);
+
+ nautilus_window_set_content_view (window, window->details->extra_viewer);
+}
+
+static void
+handle_view_as_item_from_bonobo_menu (NautilusWindow *window, const char *id)
+{
+ char *container_path;
+
+ container_path = nautilus_bonobo_get_numbered_menu_item_container_path_from_command (id);
+
+ if (strcmp (container_path, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER) == 0) {
+ activate_nth_short_list_item
+ (window,
+ nautilus_bonobo_get_numbered_menu_item_index_from_command (id));
+ } else if (strcmp (container_path, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER) == 0) {
+ g_return_if_fail
+ (nautilus_bonobo_get_numbered_menu_item_index_from_command (id) == 0);
+ activate_extra_viewer (window);
+ }
+
+ g_free (container_path);
+}
+
+void
+nautilus_window_handle_ui_event_callback (BonoboUIComponent *ui,
+ const char *id,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ NautilusWindow *window)
+{
+ if (type == Bonobo_UIComponent_STATE_CHANGED
+ && strcmp (state, "1") == 0) {
+ handle_view_as_item_from_bonobo_menu (window, id);
+ }
+}
+
+static void
view_as_menu_switch_views_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
- NautilusViewIdentifier *identifier;
+ int viewer_index;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
-
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
- identifier = (NautilusViewIdentifier *) gtk_object_get_data (GTK_OBJECT (widget), "identifier");
-
- nautilus_window_set_content_view (window, identifier);
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
+
+ window = NAUTILUS_WINDOW (data);
+
+ if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "extra viewer")) == TRUE) {
+ activate_extra_viewer (window);
+ } else {
+ viewer_index = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "viewer index"));
+ activate_nth_short_list_item (window, viewer_index);
+ }
}
-/* Note: The identifier parameter ownership is handed off to the menu item. */
static GtkWidget *
-create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identifier)
+create_view_as_menu_item (NautilusWindow *window,
+ NautilusViewIdentifier *identifier,
+ guint index)
{
GtkWidget *menu_item;
char *menu_label;
@@ -1111,16 +1188,12 @@ create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identi
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_switch_views_callback,
- NULL);
+ window);
- /* Store copy of iid in item; free when item destroyed. */
- gtk_object_set_data_full (GTK_OBJECT (menu_item),
- "identifier",
- identifier,
- (GtkDestroyNotify) nautilus_view_identifier_free);
+ gtk_object_set_data (GTK_OBJECT (menu_item),
+ "viewer index",
+ GINT_TO_POINTER (index));
- /* Store reference to window in item; no need to free this. */
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
gtk_widget_show (menu_item);
return menu_item;
@@ -1138,17 +1211,50 @@ new_gtk_separator (void)
return result;
}
+static void
+add_view_as_bonobo_menu_item (NautilusWindow *window,
+ const char *placeholder_path,
+ NautilusViewIdentifier *identifier,
+ int index)
+{
+ char *tip;
+ char *item_path;
+
+ nautilus_bonobo_add_numbered_radio_menu_item
+ (window->details->shell_ui,
+ placeholder_path,
+ index,
+ identifier->view_as_label,
+ "viewers group");
+
+ tip = g_strdup_printf (_("Display this location with the %s"), identifier->viewer_label);
+ item_path = nautilus_bonobo_get_numbered_menu_item_path
+ (window->details->shell_ui,
+ placeholder_path,
+ index);
+ nautilus_bonobo_set_tip (window->details->shell_ui, item_path, tip);
+ g_free (item_path);
+ g_free (tip);
+}
+
/* Make a special first item in the "View as" option menu that represents
* the current content view. This should only be called if the current
* content view isn't already in the "View as" option menu.
*/
static void
-replace_special_current_view_in_view_as_menu (NautilusWindow *window)
+replace_extra_viewer_in_view_as_menus (NautilusWindow *window)
{
GtkWidget *menu;
GtkWidget *first_menu_item;
GtkWidget *new_menu_item;
-
+ gboolean had_extra_viewer;
+
+ had_extra_viewer = window->details->extra_viewer != NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = nautilus_view_identifier_copy (window->content_view_id);
+ g_assert (window->details->extra_viewer != NULL);
+
+ /* Update the View As option menu */
menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
/* Remove menu before changing contents so it is resized properly
@@ -1157,73 +1263,103 @@ replace_special_current_view_in_view_as_menu (NautilusWindow *window)
gtk_widget_ref (menu);
gtk_option_menu_remove_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
- g_assert (first_menu_item != NULL);
-
- if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "current content view"))) {
+ if (had_extra_viewer) {
+ first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
+ g_assert (first_menu_item != NULL);
+ g_assert (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "extra viewer")) == TRUE);
gtk_container_remove (GTK_CONTAINER (menu), first_menu_item);
} else {
/* Prepend separator. */
gtk_menu_prepend (GTK_MENU (menu), new_gtk_separator ());
}
- new_menu_item = create_view_as_menu_item (window, nautilus_view_identifier_copy (window->content_view_id));
- gtk_object_set_data (GTK_OBJECT (new_menu_item), "current content view", GINT_TO_POINTER (TRUE));
+ new_menu_item = create_view_as_menu_item (window, window->details->extra_viewer, 0);
+ gtk_object_set_data (GTK_OBJECT (new_menu_item), "extra viewer", GINT_TO_POINTER (TRUE));
gtk_menu_prepend (GTK_MENU (menu), new_menu_item);
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu), menu);
gtk_widget_unref (menu);
+
+ /* Also update the Bonobo View menu item */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER,
+ window->details->extra_viewer,
+ 0);
}
/**
- * nautilus_window_synch_view_as_menu:
+ * nautilus_window_synch_view_as_menus:
*
- * Set the visible item of the "View as" option menu to
+ * Set the visible item of the "View as" option menu and
+ * the marked "View as" item in the View menu to
* match the current content view.
*
* @window: The NautilusWindow whose "View as" option menu should be synched.
*/
void
-nautilus_window_synch_view_as_menu (NautilusWindow *window)
+nautilus_window_synch_view_as_menus (NautilusWindow *window)
{
- GList *children, *child;
- GtkWidget *menu;
- const char *content_view_iid;
- NautilusViewIdentifier *item_id;
- int index, matching_index;
+ int index;
+ char *verb_name, *command_path;
+ GList *node;
+ int option_menu_index;
+ int numbered_menu_item_index;
+ const char *numbered_menu_item_container_path;
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
- menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- if (menu == NULL) {
+ if (window->content_view == NULL) {
return;
}
-
- children = gtk_container_children (GTK_CONTAINER (menu));
- matching_index = -1;
-
- if (window->content_view != NULL) {
- content_view_iid = nautilus_view_frame_get_view_iid (window->content_view);
- for (child = children, index = 0; child != NULL; child = child->next, ++index) {
- item_id = (NautilusViewIdentifier *) gtk_object_get_data
- (GTK_OBJECT (child->data), "identifier");
- if (item_id != NULL && strcmp (content_view_iid, item_id->iid) == 0) {
- matching_index = index;
+ option_menu_index = -1;
+ numbered_menu_item_index = -1;
+ numbered_menu_item_container_path = 0;
+
+ if (window->details->extra_viewer != NULL &&
+ nautilus_window_content_view_matches_iid (window, window->details->extra_viewer->iid)) {
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
+ } else {
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ if (nautilus_window_content_view_matches_iid (window, ((NautilusViewIdentifier *)node->data)->iid)) {
+ option_menu_index = window->details->extra_viewer == NULL
+ ? index
+ : index + 2;
+ numbered_menu_item_index = index;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER;
break;
}
}
}
- if (matching_index == -1) {
- replace_special_current_view_in_view_as_menu (window);
- matching_index = 0;
+ if (option_menu_index == -1) {
+ replace_extra_viewer_in_view_as_menus (window);
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
}
+ g_assert (option_menu_index >= 0);
+ g_assert (numbered_menu_item_index >= 0);
+ g_assert (numbered_menu_item_container_path != NULL);
+
+ /* Make option menu show the right item */
gtk_option_menu_set_history (GTK_OPTION_MENU (window->view_as_option_menu),
- matching_index);
+ option_menu_index);
- g_list_free (children);
+ /* Make View menu in menu bar mark the right item */
+ verb_name = nautilus_bonobo_get_numbered_menu_item_command
+ (window->details->shell_ui,
+ numbered_menu_item_container_path,
+ numbered_menu_item_index);
+ command_path = g_strconcat (COMMAND_PREFIX, verb_name, NULL);
+ nautilus_bonobo_set_toggle_state (window->details->shell_ui, command_path, TRUE);
+ g_free (command_path);
+ g_free (verb_name);
}
static void
@@ -1242,7 +1378,10 @@ chose_component_callback (NautilusViewIdentifier *identifier, gpointer callback_
* now, hardwire this case, which is the most obvious one by
* far.
*/
- nautilus_window_load_view_as_menu (window);
+ /* FIXME bugzilla.eazel.com 8000: It's possible to get the
+ * same view listed twice in the menu due to this call.
+ */
+ nautilus_window_load_view_as_menus (window);
}
static void
@@ -1255,71 +1394,118 @@ cancel_chose_component_callback (NautilusWindow *window)
}
}
+void
+nautilus_window_show_view_as_dialog (NautilusWindow *window)
+{
+ g_return_if_fail (NAUTILUS_IS_WINDOW (window));
+
+ /* Call back when the user chose the component. */
+ cancel_chose_component_callback (window);
+ nautilus_choose_component_for_file (window->details->viewed_file,
+ GTK_WINDOW (window),
+ chose_component_callback,
+ window);
+}
+
static void
view_as_menu_choose_view_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
+ window = NAUTILUS_WINDOW (data);
/* Set the option menu back to its previous setting (Don't
- * leave it on this dialog-producing "View as Other..."
+ * leave it on this dialog-producing "View as..."
* setting). If the menu choice causes a content view change,
* this will be updated again later, in
- * nautilus_window_load_view_as_menu. Do this right away so
+ * nautilus_window_load_view_as_menus. Do this right away so
* the user never sees the option menu set to "View as
* Other...".
*/
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
- /* Call back when the user chose the component. */
- cancel_chose_component_callback (window);
- nautilus_choose_component_for_file (window->details->viewed_file,
- GTK_WINDOW (window),
- chose_component_callback,
- window);
+ nautilus_window_show_view_as_dialog (window);
}
static void
-load_view_as_menu_callback (NautilusFile *file,
+refresh_stored_viewers (NautilusWindow *window)
+{
+ GList *components;
+ GList *node;
+ NautilusViewIdentifier *identifier;
+
+ free_stored_viewers (window);
+
+ components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
+ for (node = components; node != NULL; node = node->next) {
+ identifier = nautilus_view_identifier_new_from_content_view (node->data);
+ window->details->short_list_viewers =
+ g_list_append (window->details->short_list_viewers, identifier);
+ }
+ gnome_vfs_mime_component_list_free (components);
+}
+
+static void
+load_view_as_menus_callback (NautilusFile *file,
gpointer callback_data)
{
- GList *components;
- GList *p;
GtkWidget *new_menu;
GtkWidget *menu_item;
+ GList *node;
NautilusWindow *window;
+ int index;
window = NAUTILUS_WINDOW (callback_data);
g_return_if_fail (GTK_IS_OPTION_MENU (window->view_as_option_menu));
-
+
+ /* Clear out the menu items created last time. For the option menu, we need do
+ * nothing since we replace the entire menu. For the View menu, we have
+ * to do this explicitly.
+ */
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER);
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER);
+
+ refresh_stored_viewers (window);
+
new_menu = gtk_menu_new ();
/* Add a menu item for each view in the preferred list for this location. */
- components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
- for (p = components; p != NULL; p = p->next) {
- menu_item = create_view_as_menu_item
- (window, nautilus_view_identifier_new_from_content_view (p->data));
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ /* Menu item in option menu. This doesn't use Bonobo, for various
+ * historical and technical reasons.
+ */
+ menu_item = create_view_as_menu_item (window, node->data, index);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
+
+ /* Menu item in View menu. */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER,
+ node->data,
+ index);
}
- gnome_vfs_mime_component_list_free (components);
- /* Add separator before "Other" if there are any other viewers in menu. */
- if (components != NULL) {
+ /* Add/Show separator before "View as..." if there are any other viewers in menu. */
+ if (window->details->short_list_viewers != NULL) {
gtk_menu_append (GTK_MENU (new_menu), new_gtk_separator ());
}
+ nautilus_bonobo_set_hidden (window->details->shell_ui,
+ NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR,
+ window->details->short_list_viewers == NULL);
- /* Add "View as Other..." extra bonus choice. */
- menu_item = gtk_menu_item_new_with_label (_("View as Other..."));
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
+ /* Add "View as..." extra bonus choice. */
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_choose_view_callback,
- NULL);
+ window);
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -1329,19 +1515,19 @@ load_view_as_menu_callback (NautilusFile *file,
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu),
new_menu);
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
}
static void
cancel_view_as_callback (NautilusWindow *window)
{
nautilus_file_cancel_call_when_ready (window->details->viewed_file,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
}
void
-nautilus_window_load_view_as_menu (NautilusWindow *window)
+nautilus_window_load_view_as_menus (NautilusWindow *window)
{
GList *attributes;
@@ -1352,7 +1538,7 @@ nautilus_window_load_view_as_menu (NautilusWindow *window)
cancel_view_as_callback (window);
nautilus_file_call_when_ready (window->details->viewed_file,
attributes,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
g_list_free (attributes);
diff --git a/src/nautilus-shell-ui.xml b/src/nautilus-shell-ui.xml
index 978d3ce5a..fa3be15c0 100644
--- a/src/nautilus-shell-ui.xml
+++ b/src/nautilus-shell-ui.xml
@@ -34,6 +34,8 @@
_tip="Show the contents in less detail"/>
<cmd name="Zoom Normal" _label="Normal Size"
_tip="Show the contents at the normal size"/>
+ <cmd name="View as" _label="View as..."
+ _tip="Choose a view for the current location, or modify the set of views"/>
</commands>
<menu>
@@ -49,7 +51,6 @@
<menuitem name="Close"
_label="_Close Window"
_tip="Close this window"
- pixtype="stock" pixname="Close"
accel="*Control*w"
verb="Close"/>
<menuitem name="Close All Windows"
@@ -169,6 +170,13 @@
_label="_Normal Size"
verb="Zoom Normal"/>
</placeholder>
+ <placeholder name="View Choices">
+ <placeholder name="Extra Viewer" delimit="top"/>
+ <separator name="Before Short List"/>
+ <placeholder name="Short List"/>
+ <separator name="After Short List"/>
+ <menuitem name="View as" _label="_View as..." verb="View as"/>
+ </placeholder>
</submenu>
<submenu name="Go" _label="_Go">
diff --git a/src/nautilus-spatial-window.c b/src/nautilus-spatial-window.c
index 9fceb61de..bb883d8b8 100644
--- a/src/nautilus-spatial-window.c
+++ b/src/nautilus-spatial-window.c
@@ -96,7 +96,14 @@
#define STATUS_BAR_PATH "/status"
#define MENU_BAR_PATH "/menu"
+#define COMMAND_PREFIX "/commands/"
#define NAUTILUS_COMMAND_TOGGLE_FIND_MODE "/commands/Toggle Find Mode"
+#define NAUTILUS_COMMAND_VIEW_AS "/commands/View as"
+
+#define NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER "/menu/View/View Choices/Extra Viewer"
+#define NAUTILUS_MENU_PATH_BEFORE_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
+#define NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER "/menu/View/View Choices/Short List"
+#define NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
enum {
ARG_0,
@@ -634,7 +641,7 @@ set_dummy_initial_view_as_menu (NautilusWindow *window)
GtkWidget *menu_item;
new_menu = gtk_menu_new ();
- menu_item = gtk_menu_item_new_with_label (_("View as ..."));
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -881,6 +888,17 @@ nautilus_window_get_arg (GtkObject *object,
}
}
+static void
+free_stored_viewers (NautilusWindow *window)
+{
+ eel_g_list_free_deep_custom (window->details->short_list_viewers,
+ (GFunc) nautilus_view_identifier_free,
+ NULL);
+ window->details->short_list_viewers = NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = NULL;
+}
+
static void
nautilus_window_destroy (GtkObject *object)
{
@@ -918,6 +936,8 @@ nautilus_window_destroy (GtkObject *object)
g_list_free (window->sidebar_panels);
nautilus_view_identifier_free (window->content_view_id);
+
+ free_stored_viewers (window);
g_free (window->details->location);
eel_g_list_free_deep (window->details->selection);
@@ -1083,23 +1103,80 @@ nautilus_window_size_request (GtkWidget *widget,
*/
static void
+activate_nth_short_list_item (NautilusWindow *window, guint index)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (index < g_list_length (window->details->short_list_viewers));
+
+ nautilus_window_set_content_view (window,
+ g_list_nth_data (window->details->short_list_viewers, index));
+}
+
+static void
+activate_extra_viewer (NautilusWindow *window)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (window->details->extra_viewer != NULL);
+
+ nautilus_window_set_content_view (window, window->details->extra_viewer);
+}
+
+static void
+handle_view_as_item_from_bonobo_menu (NautilusWindow *window, const char *id)
+{
+ char *container_path;
+
+ container_path = nautilus_bonobo_get_numbered_menu_item_container_path_from_command (id);
+
+ if (strcmp (container_path, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER) == 0) {
+ activate_nth_short_list_item
+ (window,
+ nautilus_bonobo_get_numbered_menu_item_index_from_command (id));
+ } else if (strcmp (container_path, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER) == 0) {
+ g_return_if_fail
+ (nautilus_bonobo_get_numbered_menu_item_index_from_command (id) == 0);
+ activate_extra_viewer (window);
+ }
+
+ g_free (container_path);
+}
+
+void
+nautilus_window_handle_ui_event_callback (BonoboUIComponent *ui,
+ const char *id,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ NautilusWindow *window)
+{
+ if (type == Bonobo_UIComponent_STATE_CHANGED
+ && strcmp (state, "1") == 0) {
+ handle_view_as_item_from_bonobo_menu (window, id);
+ }
+}
+
+static void
view_as_menu_switch_views_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
- NautilusViewIdentifier *identifier;
+ int viewer_index;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
-
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
- identifier = (NautilusViewIdentifier *) gtk_object_get_data (GTK_OBJECT (widget), "identifier");
-
- nautilus_window_set_content_view (window, identifier);
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
+
+ window = NAUTILUS_WINDOW (data);
+
+ if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "extra viewer")) == TRUE) {
+ activate_extra_viewer (window);
+ } else {
+ viewer_index = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "viewer index"));
+ activate_nth_short_list_item (window, viewer_index);
+ }
}
-/* Note: The identifier parameter ownership is handed off to the menu item. */
static GtkWidget *
-create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identifier)
+create_view_as_menu_item (NautilusWindow *window,
+ NautilusViewIdentifier *identifier,
+ guint index)
{
GtkWidget *menu_item;
char *menu_label;
@@ -1111,16 +1188,12 @@ create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identi
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_switch_views_callback,
- NULL);
+ window);
- /* Store copy of iid in item; free when item destroyed. */
- gtk_object_set_data_full (GTK_OBJECT (menu_item),
- "identifier",
- identifier,
- (GtkDestroyNotify) nautilus_view_identifier_free);
+ gtk_object_set_data (GTK_OBJECT (menu_item),
+ "viewer index",
+ GINT_TO_POINTER (index));
- /* Store reference to window in item; no need to free this. */
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
gtk_widget_show (menu_item);
return menu_item;
@@ -1138,17 +1211,50 @@ new_gtk_separator (void)
return result;
}
+static void
+add_view_as_bonobo_menu_item (NautilusWindow *window,
+ const char *placeholder_path,
+ NautilusViewIdentifier *identifier,
+ int index)
+{
+ char *tip;
+ char *item_path;
+
+ nautilus_bonobo_add_numbered_radio_menu_item
+ (window->details->shell_ui,
+ placeholder_path,
+ index,
+ identifier->view_as_label,
+ "viewers group");
+
+ tip = g_strdup_printf (_("Display this location with the %s"), identifier->viewer_label);
+ item_path = nautilus_bonobo_get_numbered_menu_item_path
+ (window->details->shell_ui,
+ placeholder_path,
+ index);
+ nautilus_bonobo_set_tip (window->details->shell_ui, item_path, tip);
+ g_free (item_path);
+ g_free (tip);
+}
+
/* Make a special first item in the "View as" option menu that represents
* the current content view. This should only be called if the current
* content view isn't already in the "View as" option menu.
*/
static void
-replace_special_current_view_in_view_as_menu (NautilusWindow *window)
+replace_extra_viewer_in_view_as_menus (NautilusWindow *window)
{
GtkWidget *menu;
GtkWidget *first_menu_item;
GtkWidget *new_menu_item;
-
+ gboolean had_extra_viewer;
+
+ had_extra_viewer = window->details->extra_viewer != NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = nautilus_view_identifier_copy (window->content_view_id);
+ g_assert (window->details->extra_viewer != NULL);
+
+ /* Update the View As option menu */
menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
/* Remove menu before changing contents so it is resized properly
@@ -1157,73 +1263,103 @@ replace_special_current_view_in_view_as_menu (NautilusWindow *window)
gtk_widget_ref (menu);
gtk_option_menu_remove_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
- g_assert (first_menu_item != NULL);
-
- if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "current content view"))) {
+ if (had_extra_viewer) {
+ first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
+ g_assert (first_menu_item != NULL);
+ g_assert (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "extra viewer")) == TRUE);
gtk_container_remove (GTK_CONTAINER (menu), first_menu_item);
} else {
/* Prepend separator. */
gtk_menu_prepend (GTK_MENU (menu), new_gtk_separator ());
}
- new_menu_item = create_view_as_menu_item (window, nautilus_view_identifier_copy (window->content_view_id));
- gtk_object_set_data (GTK_OBJECT (new_menu_item), "current content view", GINT_TO_POINTER (TRUE));
+ new_menu_item = create_view_as_menu_item (window, window->details->extra_viewer, 0);
+ gtk_object_set_data (GTK_OBJECT (new_menu_item), "extra viewer", GINT_TO_POINTER (TRUE));
gtk_menu_prepend (GTK_MENU (menu), new_menu_item);
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu), menu);
gtk_widget_unref (menu);
+
+ /* Also update the Bonobo View menu item */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER,
+ window->details->extra_viewer,
+ 0);
}
/**
- * nautilus_window_synch_view_as_menu:
+ * nautilus_window_synch_view_as_menus:
*
- * Set the visible item of the "View as" option menu to
+ * Set the visible item of the "View as" option menu and
+ * the marked "View as" item in the View menu to
* match the current content view.
*
* @window: The NautilusWindow whose "View as" option menu should be synched.
*/
void
-nautilus_window_synch_view_as_menu (NautilusWindow *window)
+nautilus_window_synch_view_as_menus (NautilusWindow *window)
{
- GList *children, *child;
- GtkWidget *menu;
- const char *content_view_iid;
- NautilusViewIdentifier *item_id;
- int index, matching_index;
+ int index;
+ char *verb_name, *command_path;
+ GList *node;
+ int option_menu_index;
+ int numbered_menu_item_index;
+ const char *numbered_menu_item_container_path;
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
- menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- if (menu == NULL) {
+ if (window->content_view == NULL) {
return;
}
-
- children = gtk_container_children (GTK_CONTAINER (menu));
- matching_index = -1;
-
- if (window->content_view != NULL) {
- content_view_iid = nautilus_view_frame_get_view_iid (window->content_view);
- for (child = children, index = 0; child != NULL; child = child->next, ++index) {
- item_id = (NautilusViewIdentifier *) gtk_object_get_data
- (GTK_OBJECT (child->data), "identifier");
- if (item_id != NULL && strcmp (content_view_iid, item_id->iid) == 0) {
- matching_index = index;
+ option_menu_index = -1;
+ numbered_menu_item_index = -1;
+ numbered_menu_item_container_path = 0;
+
+ if (window->details->extra_viewer != NULL &&
+ nautilus_window_content_view_matches_iid (window, window->details->extra_viewer->iid)) {
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
+ } else {
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ if (nautilus_window_content_view_matches_iid (window, ((NautilusViewIdentifier *)node->data)->iid)) {
+ option_menu_index = window->details->extra_viewer == NULL
+ ? index
+ : index + 2;
+ numbered_menu_item_index = index;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER;
break;
}
}
}
- if (matching_index == -1) {
- replace_special_current_view_in_view_as_menu (window);
- matching_index = 0;
+ if (option_menu_index == -1) {
+ replace_extra_viewer_in_view_as_menus (window);
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
}
+ g_assert (option_menu_index >= 0);
+ g_assert (numbered_menu_item_index >= 0);
+ g_assert (numbered_menu_item_container_path != NULL);
+
+ /* Make option menu show the right item */
gtk_option_menu_set_history (GTK_OPTION_MENU (window->view_as_option_menu),
- matching_index);
+ option_menu_index);
- g_list_free (children);
+ /* Make View menu in menu bar mark the right item */
+ verb_name = nautilus_bonobo_get_numbered_menu_item_command
+ (window->details->shell_ui,
+ numbered_menu_item_container_path,
+ numbered_menu_item_index);
+ command_path = g_strconcat (COMMAND_PREFIX, verb_name, NULL);
+ nautilus_bonobo_set_toggle_state (window->details->shell_ui, command_path, TRUE);
+ g_free (command_path);
+ g_free (verb_name);
}
static void
@@ -1242,7 +1378,10 @@ chose_component_callback (NautilusViewIdentifier *identifier, gpointer callback_
* now, hardwire this case, which is the most obvious one by
* far.
*/
- nautilus_window_load_view_as_menu (window);
+ /* FIXME bugzilla.eazel.com 8000: It's possible to get the
+ * same view listed twice in the menu due to this call.
+ */
+ nautilus_window_load_view_as_menus (window);
}
static void
@@ -1255,71 +1394,118 @@ cancel_chose_component_callback (NautilusWindow *window)
}
}
+void
+nautilus_window_show_view_as_dialog (NautilusWindow *window)
+{
+ g_return_if_fail (NAUTILUS_IS_WINDOW (window));
+
+ /* Call back when the user chose the component. */
+ cancel_chose_component_callback (window);
+ nautilus_choose_component_for_file (window->details->viewed_file,
+ GTK_WINDOW (window),
+ chose_component_callback,
+ window);
+}
+
static void
view_as_menu_choose_view_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
+ window = NAUTILUS_WINDOW (data);
/* Set the option menu back to its previous setting (Don't
- * leave it on this dialog-producing "View as Other..."
+ * leave it on this dialog-producing "View as..."
* setting). If the menu choice causes a content view change,
* this will be updated again later, in
- * nautilus_window_load_view_as_menu. Do this right away so
+ * nautilus_window_load_view_as_menus. Do this right away so
* the user never sees the option menu set to "View as
* Other...".
*/
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
- /* Call back when the user chose the component. */
- cancel_chose_component_callback (window);
- nautilus_choose_component_for_file (window->details->viewed_file,
- GTK_WINDOW (window),
- chose_component_callback,
- window);
+ nautilus_window_show_view_as_dialog (window);
}
static void
-load_view_as_menu_callback (NautilusFile *file,
+refresh_stored_viewers (NautilusWindow *window)
+{
+ GList *components;
+ GList *node;
+ NautilusViewIdentifier *identifier;
+
+ free_stored_viewers (window);
+
+ components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
+ for (node = components; node != NULL; node = node->next) {
+ identifier = nautilus_view_identifier_new_from_content_view (node->data);
+ window->details->short_list_viewers =
+ g_list_append (window->details->short_list_viewers, identifier);
+ }
+ gnome_vfs_mime_component_list_free (components);
+}
+
+static void
+load_view_as_menus_callback (NautilusFile *file,
gpointer callback_data)
{
- GList *components;
- GList *p;
GtkWidget *new_menu;
GtkWidget *menu_item;
+ GList *node;
NautilusWindow *window;
+ int index;
window = NAUTILUS_WINDOW (callback_data);
g_return_if_fail (GTK_IS_OPTION_MENU (window->view_as_option_menu));
-
+
+ /* Clear out the menu items created last time. For the option menu, we need do
+ * nothing since we replace the entire menu. For the View menu, we have
+ * to do this explicitly.
+ */
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER);
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER);
+
+ refresh_stored_viewers (window);
+
new_menu = gtk_menu_new ();
/* Add a menu item for each view in the preferred list for this location. */
- components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
- for (p = components; p != NULL; p = p->next) {
- menu_item = create_view_as_menu_item
- (window, nautilus_view_identifier_new_from_content_view (p->data));
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ /* Menu item in option menu. This doesn't use Bonobo, for various
+ * historical and technical reasons.
+ */
+ menu_item = create_view_as_menu_item (window, node->data, index);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
+
+ /* Menu item in View menu. */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER,
+ node->data,
+ index);
}
- gnome_vfs_mime_component_list_free (components);
- /* Add separator before "Other" if there are any other viewers in menu. */
- if (components != NULL) {
+ /* Add/Show separator before "View as..." if there are any other viewers in menu. */
+ if (window->details->short_list_viewers != NULL) {
gtk_menu_append (GTK_MENU (new_menu), new_gtk_separator ());
}
+ nautilus_bonobo_set_hidden (window->details->shell_ui,
+ NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR,
+ window->details->short_list_viewers == NULL);
- /* Add "View as Other..." extra bonus choice. */
- menu_item = gtk_menu_item_new_with_label (_("View as Other..."));
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
+ /* Add "View as..." extra bonus choice. */
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_choose_view_callback,
- NULL);
+ window);
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -1329,19 +1515,19 @@ load_view_as_menu_callback (NautilusFile *file,
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu),
new_menu);
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
}
static void
cancel_view_as_callback (NautilusWindow *window)
{
nautilus_file_cancel_call_when_ready (window->details->viewed_file,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
}
void
-nautilus_window_load_view_as_menu (NautilusWindow *window)
+nautilus_window_load_view_as_menus (NautilusWindow *window)
{
GList *attributes;
@@ -1352,7 +1538,7 @@ nautilus_window_load_view_as_menu (NautilusWindow *window)
cancel_view_as_callback (window);
nautilus_file_call_when_ready (window->details->viewed_file,
attributes,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
g_list_free (attributes);
diff --git a/src/nautilus-window-manage-views.c b/src/nautilus-window-manage-views.c
index f4c9a07f4..6b5874553 100644
--- a/src/nautilus-window-manage-views.c
+++ b/src/nautilus-window-manage-views.c
@@ -598,7 +598,7 @@ update_for_new_location (NautilusWindow *window)
update_up_button (window);
/* Set up the content view menu for this new location. */
- nautilus_window_load_view_as_menu (window);
+ nautilus_window_load_view_as_menus (window);
/* Check if the back and forward buttons need enabling or disabling. */
nautilus_window_allow_back (window, window->back_list != NULL);
@@ -661,7 +661,7 @@ location_has_really_changed (NautilusWindow *window)
* views in the menu are for the old location).
*/
if (window->details->pending_location == NULL) {
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
}
/* Tell the window we are finished. */
@@ -913,7 +913,7 @@ set_to_pending_location_and_selection (NautilusWindow *window)
window->details->pending_selection = NULL;
}
-static gboolean
+gboolean
nautilus_window_content_view_matches_iid (NautilusWindow *window,
const char *iid)
{
diff --git a/src/nautilus-window-menus.c b/src/nautilus-window-menus.c
index 3592a551f..cbc7c4c4f 100644
--- a/src/nautilus-window-menus.c
+++ b/src/nautilus-window-menus.c
@@ -513,6 +513,14 @@ view_menu_zoom_normal_callback (BonoboUIComponent *component,
}
static void
+view_menu_view_as_callback (BonoboUIComponent *component,
+ gpointer user_data,
+ const char *verb)
+{
+ nautilus_window_show_view_as_dialog (NAUTILUS_WINDOW (user_data));
+}
+
+static void
bookmarks_menu_add_bookmark_callback (BonoboUIComponent *component,
gpointer user_data,
const char *verb)
@@ -1261,6 +1269,7 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window)
BONOBO_UI_VERB ("Zoom In", view_menu_zoom_in_callback),
BONOBO_UI_VERB ("Zoom Out", view_menu_zoom_out_callback),
BONOBO_UI_VERB ("Zoom Normal", view_menu_zoom_normal_callback),
+ BONOBO_UI_VERB ("View as", view_menu_view_as_callback),
BONOBO_UI_VERB ("Add Bookmark", bookmarks_menu_add_bookmark_callback),
BONOBO_UI_VERB ("Edit Bookmarks", bookmarks_menu_edit_bookmarks_callback),
@@ -1308,6 +1317,12 @@ nautilus_window_initialize_menus_part_1 (NautilusWindow *window)
/* Update the user level menu items for the first time */
user_level_changed_callback (window);
+ /* Register to catch Bonobo UI events so we can notice View As changes */
+ gtk_signal_connect (GTK_OBJECT (window->details->shell_ui),
+ "ui_event",
+ nautilus_window_handle_ui_event_callback,
+ window);
+
bonobo_ui_component_thaw (window->details->shell_ui, NULL);
#ifndef ENABLE_PROFILER
diff --git a/src/nautilus-window-private.h b/src/nautilus-window-private.h
index 5433d22aa..a485d8713 100644
--- a/src/nautilus-window-private.h
+++ b/src/nautilus-window-private.h
@@ -78,6 +78,10 @@ struct NautilusWindowDetails
GList *pending_selection;
NautilusDetermineViewHandle *determine_view_handle;
+ /* View As choices */
+ GList *short_list_viewers;
+ NautilusViewIdentifier *extra_viewer;
+
/* Throbber. */
Bonobo_EventSource_ListenerId throbber_location_change_request_listener_id;
@@ -119,13 +123,20 @@ struct NautilusWindowDetails
#define NAUTILUS_WINDOW_DEFAULT_WIDTH 800
#define NAUTILUS_WINDOW_DEFAULT_HEIGHT 550
+gboolean nautilus_window_content_view_matches_iid (NautilusWindow *window,
+ const char *iid);
void nautilus_window_set_status (NautilusWindow *window,
const char *status);
-void nautilus_window_load_view_as_menu (NautilusWindow *window);
-void nautilus_window_synch_view_as_menu (NautilusWindow *window);
+void nautilus_window_load_view_as_menus (NautilusWindow *window);
+void nautilus_window_synch_view_as_menus (NautilusWindow *window);
void nautilus_window_initialize_menus_part_1 (NautilusWindow *window);
void nautilus_window_initialize_menus_part_2 (NautilusWindow *window);
void nautilus_window_initialize_toolbars (NautilusWindow *window);
+void nautilus_window_handle_ui_event_callback (BonoboUIComponent *ui,
+ const char *id,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ NautilusWindow *window);
void nautilus_window_go_back (NautilusWindow *window);
void nautilus_window_go_forward (NautilusWindow *window);
void nautilus_window_go_up (NautilusWindow *window);
@@ -141,6 +152,7 @@ void nautilus_window_zoom_out (Nautil
void nautilus_window_zoom_to_level (NautilusWindow *window,
double level);
void nautilus_window_zoom_to_fit (NautilusWindow *window);
+void nautilus_window_show_view_as_dialog (NautilusWindow *window);
void nautilus_window_set_content_view_widget (NautilusWindow *window,
NautilusViewFrame *content_view);
void nautilus_window_add_sidebar_panel (NautilusWindow *window,
diff --git a/src/nautilus-window.c b/src/nautilus-window.c
index 9fceb61de..bb883d8b8 100644
--- a/src/nautilus-window.c
+++ b/src/nautilus-window.c
@@ -96,7 +96,14 @@
#define STATUS_BAR_PATH "/status"
#define MENU_BAR_PATH "/menu"
+#define COMMAND_PREFIX "/commands/"
#define NAUTILUS_COMMAND_TOGGLE_FIND_MODE "/commands/Toggle Find Mode"
+#define NAUTILUS_COMMAND_VIEW_AS "/commands/View as"
+
+#define NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER "/menu/View/View Choices/Extra Viewer"
+#define NAUTILUS_MENU_PATH_BEFORE_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
+#define NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER "/menu/View/View Choices/Short List"
+#define NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR "/menu/View/View Choices/Before Short List"
enum {
ARG_0,
@@ -634,7 +641,7 @@ set_dummy_initial_view_as_menu (NautilusWindow *window)
GtkWidget *menu_item;
new_menu = gtk_menu_new ();
- menu_item = gtk_menu_item_new_with_label (_("View as ..."));
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -881,6 +888,17 @@ nautilus_window_get_arg (GtkObject *object,
}
}
+static void
+free_stored_viewers (NautilusWindow *window)
+{
+ eel_g_list_free_deep_custom (window->details->short_list_viewers,
+ (GFunc) nautilus_view_identifier_free,
+ NULL);
+ window->details->short_list_viewers = NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = NULL;
+}
+
static void
nautilus_window_destroy (GtkObject *object)
{
@@ -918,6 +936,8 @@ nautilus_window_destroy (GtkObject *object)
g_list_free (window->sidebar_panels);
nautilus_view_identifier_free (window->content_view_id);
+
+ free_stored_viewers (window);
g_free (window->details->location);
eel_g_list_free_deep (window->details->selection);
@@ -1083,23 +1103,80 @@ nautilus_window_size_request (GtkWidget *widget,
*/
static void
+activate_nth_short_list_item (NautilusWindow *window, guint index)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (index < g_list_length (window->details->short_list_viewers));
+
+ nautilus_window_set_content_view (window,
+ g_list_nth_data (window->details->short_list_viewers, index));
+}
+
+static void
+activate_extra_viewer (NautilusWindow *window)
+{
+ g_assert (NAUTILUS_IS_WINDOW (window));
+ g_assert (window->details->extra_viewer != NULL);
+
+ nautilus_window_set_content_view (window, window->details->extra_viewer);
+}
+
+static void
+handle_view_as_item_from_bonobo_menu (NautilusWindow *window, const char *id)
+{
+ char *container_path;
+
+ container_path = nautilus_bonobo_get_numbered_menu_item_container_path_from_command (id);
+
+ if (strcmp (container_path, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER) == 0) {
+ activate_nth_short_list_item
+ (window,
+ nautilus_bonobo_get_numbered_menu_item_index_from_command (id));
+ } else if (strcmp (container_path, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER) == 0) {
+ g_return_if_fail
+ (nautilus_bonobo_get_numbered_menu_item_index_from_command (id) == 0);
+ activate_extra_viewer (window);
+ }
+
+ g_free (container_path);
+}
+
+void
+nautilus_window_handle_ui_event_callback (BonoboUIComponent *ui,
+ const char *id,
+ Bonobo_UIComponent_EventType type,
+ const char *state,
+ NautilusWindow *window)
+{
+ if (type == Bonobo_UIComponent_STATE_CHANGED
+ && strcmp (state, "1") == 0) {
+ handle_view_as_item_from_bonobo_menu (window, id);
+ }
+}
+
+static void
view_as_menu_switch_views_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
- NautilusViewIdentifier *identifier;
+ int viewer_index;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
-
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
- identifier = (NautilusViewIdentifier *) gtk_object_get_data (GTK_OBJECT (widget), "identifier");
-
- nautilus_window_set_content_view (window, identifier);
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
+
+ window = NAUTILUS_WINDOW (data);
+
+ if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "extra viewer")) == TRUE) {
+ activate_extra_viewer (window);
+ } else {
+ viewer_index = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "viewer index"));
+ activate_nth_short_list_item (window, viewer_index);
+ }
}
-/* Note: The identifier parameter ownership is handed off to the menu item. */
static GtkWidget *
-create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identifier)
+create_view_as_menu_item (NautilusWindow *window,
+ NautilusViewIdentifier *identifier,
+ guint index)
{
GtkWidget *menu_item;
char *menu_label;
@@ -1111,16 +1188,12 @@ create_view_as_menu_item (NautilusWindow *window, NautilusViewIdentifier *identi
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_switch_views_callback,
- NULL);
+ window);
- /* Store copy of iid in item; free when item destroyed. */
- gtk_object_set_data_full (GTK_OBJECT (menu_item),
- "identifier",
- identifier,
- (GtkDestroyNotify) nautilus_view_identifier_free);
+ gtk_object_set_data (GTK_OBJECT (menu_item),
+ "viewer index",
+ GINT_TO_POINTER (index));
- /* Store reference to window in item; no need to free this. */
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
gtk_widget_show (menu_item);
return menu_item;
@@ -1138,17 +1211,50 @@ new_gtk_separator (void)
return result;
}
+static void
+add_view_as_bonobo_menu_item (NautilusWindow *window,
+ const char *placeholder_path,
+ NautilusViewIdentifier *identifier,
+ int index)
+{
+ char *tip;
+ char *item_path;
+
+ nautilus_bonobo_add_numbered_radio_menu_item
+ (window->details->shell_ui,
+ placeholder_path,
+ index,
+ identifier->view_as_label,
+ "viewers group");
+
+ tip = g_strdup_printf (_("Display this location with the %s"), identifier->viewer_label);
+ item_path = nautilus_bonobo_get_numbered_menu_item_path
+ (window->details->shell_ui,
+ placeholder_path,
+ index);
+ nautilus_bonobo_set_tip (window->details->shell_ui, item_path, tip);
+ g_free (item_path);
+ g_free (tip);
+}
+
/* Make a special first item in the "View as" option menu that represents
* the current content view. This should only be called if the current
* content view isn't already in the "View as" option menu.
*/
static void
-replace_special_current_view_in_view_as_menu (NautilusWindow *window)
+replace_extra_viewer_in_view_as_menus (NautilusWindow *window)
{
GtkWidget *menu;
GtkWidget *first_menu_item;
GtkWidget *new_menu_item;
-
+ gboolean had_extra_viewer;
+
+ had_extra_viewer = window->details->extra_viewer != NULL;
+ nautilus_view_identifier_free (window->details->extra_viewer);
+ window->details->extra_viewer = nautilus_view_identifier_copy (window->content_view_id);
+ g_assert (window->details->extra_viewer != NULL);
+
+ /* Update the View As option menu */
menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
/* Remove menu before changing contents so it is resized properly
@@ -1157,73 +1263,103 @@ replace_special_current_view_in_view_as_menu (NautilusWindow *window)
gtk_widget_ref (menu);
gtk_option_menu_remove_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
- g_assert (first_menu_item != NULL);
-
- if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "current content view"))) {
+ if (had_extra_viewer) {
+ first_menu_item = eel_gtk_container_get_first_child (GTK_CONTAINER (menu));
+ g_assert (first_menu_item != NULL);
+ g_assert (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (first_menu_item), "extra viewer")) == TRUE);
gtk_container_remove (GTK_CONTAINER (menu), first_menu_item);
} else {
/* Prepend separator. */
gtk_menu_prepend (GTK_MENU (menu), new_gtk_separator ());
}
- new_menu_item = create_view_as_menu_item (window, nautilus_view_identifier_copy (window->content_view_id));
- gtk_object_set_data (GTK_OBJECT (new_menu_item), "current content view", GINT_TO_POINTER (TRUE));
+ new_menu_item = create_view_as_menu_item (window, window->details->extra_viewer, 0);
+ gtk_object_set_data (GTK_OBJECT (new_menu_item), "extra viewer", GINT_TO_POINTER (TRUE));
gtk_menu_prepend (GTK_MENU (menu), new_menu_item);
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu), menu);
gtk_widget_unref (menu);
+
+ /* Also update the Bonobo View menu item */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER,
+ window->details->extra_viewer,
+ 0);
}
/**
- * nautilus_window_synch_view_as_menu:
+ * nautilus_window_synch_view_as_menus:
*
- * Set the visible item of the "View as" option menu to
+ * Set the visible item of the "View as" option menu and
+ * the marked "View as" item in the View menu to
* match the current content view.
*
* @window: The NautilusWindow whose "View as" option menu should be synched.
*/
void
-nautilus_window_synch_view_as_menu (NautilusWindow *window)
+nautilus_window_synch_view_as_menus (NautilusWindow *window)
{
- GList *children, *child;
- GtkWidget *menu;
- const char *content_view_iid;
- NautilusViewIdentifier *item_id;
- int index, matching_index;
+ int index;
+ char *verb_name, *command_path;
+ GList *node;
+ int option_menu_index;
+ int numbered_menu_item_index;
+ const char *numbered_menu_item_container_path;
g_return_if_fail (NAUTILUS_IS_WINDOW (window));
- menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (window->view_as_option_menu));
- if (menu == NULL) {
+ if (window->content_view == NULL) {
return;
}
-
- children = gtk_container_children (GTK_CONTAINER (menu));
- matching_index = -1;
-
- if (window->content_view != NULL) {
- content_view_iid = nautilus_view_frame_get_view_iid (window->content_view);
- for (child = children, index = 0; child != NULL; child = child->next, ++index) {
- item_id = (NautilusViewIdentifier *) gtk_object_get_data
- (GTK_OBJECT (child->data), "identifier");
- if (item_id != NULL && strcmp (content_view_iid, item_id->iid) == 0) {
- matching_index = index;
+ option_menu_index = -1;
+ numbered_menu_item_index = -1;
+ numbered_menu_item_container_path = 0;
+
+ if (window->details->extra_viewer != NULL &&
+ nautilus_window_content_view_matches_iid (window, window->details->extra_viewer->iid)) {
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
+ } else {
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ if (nautilus_window_content_view_matches_iid (window, ((NautilusViewIdentifier *)node->data)->iid)) {
+ option_menu_index = window->details->extra_viewer == NULL
+ ? index
+ : index + 2;
+ numbered_menu_item_index = index;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER;
break;
}
}
}
- if (matching_index == -1) {
- replace_special_current_view_in_view_as_menu (window);
- matching_index = 0;
+ if (option_menu_index == -1) {
+ replace_extra_viewer_in_view_as_menus (window);
+ option_menu_index = 0;
+ numbered_menu_item_index = 0;
+ numbered_menu_item_container_path = NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER;
}
+ g_assert (option_menu_index >= 0);
+ g_assert (numbered_menu_item_index >= 0);
+ g_assert (numbered_menu_item_container_path != NULL);
+
+ /* Make option menu show the right item */
gtk_option_menu_set_history (GTK_OPTION_MENU (window->view_as_option_menu),
- matching_index);
+ option_menu_index);
- g_list_free (children);
+ /* Make View menu in menu bar mark the right item */
+ verb_name = nautilus_bonobo_get_numbered_menu_item_command
+ (window->details->shell_ui,
+ numbered_menu_item_container_path,
+ numbered_menu_item_index);
+ command_path = g_strconcat (COMMAND_PREFIX, verb_name, NULL);
+ nautilus_bonobo_set_toggle_state (window->details->shell_ui, command_path, TRUE);
+ g_free (command_path);
+ g_free (verb_name);
}
static void
@@ -1242,7 +1378,10 @@ chose_component_callback (NautilusViewIdentifier *identifier, gpointer callback_
* now, hardwire this case, which is the most obvious one by
* far.
*/
- nautilus_window_load_view_as_menu (window);
+ /* FIXME bugzilla.eazel.com 8000: It's possible to get the
+ * same view listed twice in the menu due to this call.
+ */
+ nautilus_window_load_view_as_menus (window);
}
static void
@@ -1255,71 +1394,118 @@ cancel_chose_component_callback (NautilusWindow *window)
}
}
+void
+nautilus_window_show_view_as_dialog (NautilusWindow *window)
+{
+ g_return_if_fail (NAUTILUS_IS_WINDOW (window));
+
+ /* Call back when the user chose the component. */
+ cancel_chose_component_callback (window);
+ nautilus_choose_component_for_file (window->details->viewed_file,
+ GTK_WINDOW (window),
+ chose_component_callback,
+ window);
+}
+
static void
view_as_menu_choose_view_callback (GtkWidget *widget, gpointer data)
{
NautilusWindow *window;
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- g_return_if_fail (NAUTILUS_IS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window")));
+ g_return_if_fail (NAUTILUS_IS_WINDOW (data));
- window = NAUTILUS_WINDOW (gtk_object_get_data (GTK_OBJECT (widget), "window"));
+ window = NAUTILUS_WINDOW (data);
/* Set the option menu back to its previous setting (Don't
- * leave it on this dialog-producing "View as Other..."
+ * leave it on this dialog-producing "View as..."
* setting). If the menu choice causes a content view change,
* this will be updated again later, in
- * nautilus_window_load_view_as_menu. Do this right away so
+ * nautilus_window_load_view_as_menus. Do this right away so
* the user never sees the option menu set to "View as
* Other...".
*/
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
- /* Call back when the user chose the component. */
- cancel_chose_component_callback (window);
- nautilus_choose_component_for_file (window->details->viewed_file,
- GTK_WINDOW (window),
- chose_component_callback,
- window);
+ nautilus_window_show_view_as_dialog (window);
}
static void
-load_view_as_menu_callback (NautilusFile *file,
+refresh_stored_viewers (NautilusWindow *window)
+{
+ GList *components;
+ GList *node;
+ NautilusViewIdentifier *identifier;
+
+ free_stored_viewers (window);
+
+ components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
+ for (node = components; node != NULL; node = node->next) {
+ identifier = nautilus_view_identifier_new_from_content_view (node->data);
+ window->details->short_list_viewers =
+ g_list_append (window->details->short_list_viewers, identifier);
+ }
+ gnome_vfs_mime_component_list_free (components);
+}
+
+static void
+load_view_as_menus_callback (NautilusFile *file,
gpointer callback_data)
{
- GList *components;
- GList *p;
GtkWidget *new_menu;
GtkWidget *menu_item;
+ GList *node;
NautilusWindow *window;
+ int index;
window = NAUTILUS_WINDOW (callback_data);
g_return_if_fail (GTK_IS_OPTION_MENU (window->view_as_option_menu));
-
+
+ /* Clear out the menu items created last time. For the option menu, we need do
+ * nothing since we replace the entire menu. For the View menu, we have
+ * to do this explicitly.
+ */
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER);
+ nautilus_bonobo_remove_menu_items_and_commands
+ (window->details->shell_ui, NAUTILUS_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER);
+
+ refresh_stored_viewers (window);
+
new_menu = gtk_menu_new ();
/* Add a menu item for each view in the preferred list for this location. */
- components = nautilus_mime_get_short_list_components_for_file (window->details->viewed_file);
- for (p = components; p != NULL; p = p->next) {
- menu_item = create_view_as_menu_item
- (window, nautilus_view_identifier_new_from_content_view (p->data));
+ for (node = window->details->short_list_viewers, index = 0;
+ node != NULL;
+ node = node->next, ++index) {
+ /* Menu item in option menu. This doesn't use Bonobo, for various
+ * historical and technical reasons.
+ */
+ menu_item = create_view_as_menu_item (window, node->data, index);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
+
+ /* Menu item in View menu. */
+ add_view_as_bonobo_menu_item (window,
+ NAUTILUS_MENU_PATH_SHORT_LIST_PLACEHOLDER,
+ node->data,
+ index);
}
- gnome_vfs_mime_component_list_free (components);
- /* Add separator before "Other" if there are any other viewers in menu. */
- if (components != NULL) {
+ /* Add/Show separator before "View as..." if there are any other viewers in menu. */
+ if (window->details->short_list_viewers != NULL) {
gtk_menu_append (GTK_MENU (new_menu), new_gtk_separator ());
}
+ nautilus_bonobo_set_hidden (window->details->shell_ui,
+ NAUTILUS_MENU_PATH_AFTER_SHORT_LIST_SEPARATOR,
+ window->details->short_list_viewers == NULL);
- /* Add "View as Other..." extra bonus choice. */
- menu_item = gtk_menu_item_new_with_label (_("View as Other..."));
- gtk_object_set_data (GTK_OBJECT (menu_item), "window", window);
+ /* Add "View as..." extra bonus choice. */
+ menu_item = gtk_menu_item_new_with_label (_("View as..."));
gtk_signal_connect (GTK_OBJECT (menu_item),
"activate",
view_as_menu_choose_view_callback,
- NULL);
+ window);
gtk_widget_show (menu_item);
gtk_menu_append (GTK_MENU (new_menu), menu_item);
@@ -1329,19 +1515,19 @@ load_view_as_menu_callback (NautilusFile *file,
gtk_option_menu_set_menu (GTK_OPTION_MENU (window->view_as_option_menu),
new_menu);
- nautilus_window_synch_view_as_menu (window);
+ nautilus_window_synch_view_as_menus (window);
}
static void
cancel_view_as_callback (NautilusWindow *window)
{
nautilus_file_cancel_call_when_ready (window->details->viewed_file,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
}
void
-nautilus_window_load_view_as_menu (NautilusWindow *window)
+nautilus_window_load_view_as_menus (NautilusWindow *window)
{
GList *attributes;
@@ -1352,7 +1538,7 @@ nautilus_window_load_view_as_menu (NautilusWindow *window)
cancel_view_as_callback (window);
nautilus_file_call_when_ready (window->details->viewed_file,
attributes,
- load_view_as_menu_callback,
+ load_view_as_menus_callback,
window);
g_list_free (attributes);