diff options
author | Ramiro Estrugo <ramiro@src.gnome.org> | 2001-04-18 16:12:01 +0000 |
---|---|---|
committer | Ramiro Estrugo <ramiro@src.gnome.org> | 2001-04-18 16:12:01 +0000 |
commit | 17054afdc73b07d297a5a531aec8b10ab9d83324 (patch) | |
tree | c030c1012faebb99e3759c27e9d8fea901373fec | |
parent | bd31494a9d5d8004258e17c830e92f043fb3bfc7 (diff) | |
download | nautilus-17054afdc73b07d297a5a531aec8b10ab9d83324.tar.gz |
Remove NAUTILUS_PREFERENCES_ICON_CAPTIONS, its not needed anymore.
* libnautilus-extensions/nautilus-global-preferences.h:
Remove NAUTILUS_PREFERENCES_ICON_CAPTIONS, its not needed anymore.
* libnautilus-extensions/nautilus-global-preferences.c:
(global_preferences_populate_pane): Add support for installing a
list if strings to ignore when enforcing the unique choice rule
for enumeration lists items.
(global_preferences_create_dialog),
(nautilus_global_preferences_initialize): Register the
enumerations at initialization time instead of dialog creation
time. This is needed so that sanity checking on enumeration
preferences can occur even if the user hasnt opened the dialog.
* libnautilus-extensions/nautilus-preferences-item.h:
* libnautilus-extensions/nautilus-preferences-item.c:
(nautilus_preferences_item_initialize_class),
(nautilus_preferences_item_initialize), (preferences_item_destroy),
(preferences_item_update_enumeration_list_uniqueness),
(preferences_item_update_enumeration_list),
(preferences_item_create_enumeration_list),
(enumeration_list_changed_callback),
(nautilus_preferences_item_enumeration_list_set_unique_exceptions):
Make sure the string pickers are wired such that duplicate choices cannot be
made by the user. We do this by making items that would result in duplicates
insensitive. Its possible to bypass this rule for some items. We use the
use the enumeration_list_unique_exceptions.
* libnautilus-extensions/nautilus-preferences.c:
(preferences_block_callbacks), (preferences_unblock_callbacks):
New private functions to block/unblock preferences callbacks.
(string_list_is_valid): New private function to sanity check the
values of a string list.
(nautilus_preferences_get_string_list): Sanity check the results
of this function for greater convenience of the callers - they no
longer need to do error checking on the result.
(preferences_entry_invoke_callbacks_if_needed): Invoke callbacks
only if they are not blocked.
* src/file-manager/Makefile.am:
* src/file-manager/fm-icon-text-window.c:
* src/file-manager/fm-icon-text-window.h:
Retire these 2 files. There no longer is a Icon Captions window.
* src/file-manager/fm-directory-view.c:
(fm_directory_view_initialize), (fm_directory_view_destroy):
Update for slight change in the Icon Captions preference name.
* src/file-manager/fm-icon-view.c:
(fm_icon_view_get_icon_text_attributes_from_preferences): New
function to fetch the icon caption attributes from preferences. A
similar function used to live in fm-icon-text-window.[ch]. That
is no longer the case now that the Icon Captions have moved into
the preferences dialog.
(fm_icon_view_get_icon_text_attribute_names): Simplify the munging
of icon captions by using a string list.
(fm_icon_view_merge_menus): Remove the Icon Captions menu. The
Icon Captions picker now lives in the preferences dialog.
* src/file-manager/nautilus-icon-view-ui.xml:
Remove Icon Captions menu item which no longer exists.
-rw-r--r-- | ChangeLog | 63 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-global-preferences.c | 40 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-global-preferences.h | 2 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-preferences-item.c | 126 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-preferences-item.h | 31 | ||||
-rw-r--r-- | libnautilus-extensions/nautilus-preferences.c | 88 | ||||
-rw-r--r-- | libnautilus-private/nautilus-global-preferences.c | 40 | ||||
-rw-r--r-- | libnautilus-private/nautilus-global-preferences.h | 2 | ||||
-rw-r--r-- | libnautilus-private/nautilus-preferences-item.c | 126 | ||||
-rw-r--r-- | libnautilus-private/nautilus-preferences-item.h | 31 | ||||
-rw-r--r-- | libnautilus-private/nautilus-preferences.c | 88 | ||||
-rw-r--r-- | src/file-manager/Makefile.am | 2 | ||||
-rw-r--r-- | src/file-manager/fm-directory-view.c | 4 | ||||
-rw-r--r-- | src/file-manager/fm-icon-text-window.c | 436 | ||||
-rw-r--r-- | src/file-manager/fm-icon-text-window.h | 40 | ||||
-rw-r--r-- | src/file-manager/fm-icon-view.c | 98 | ||||
-rw-r--r-- | src/file-manager/nautilus-icon-view-ui.xml | 9 |
17 files changed, 632 insertions, 594 deletions
@@ -1,3 +1,66 @@ +2001-04-18 Ramiro Estrugo <ramiro@eazel.com> + + * libnautilus-extensions/nautilus-global-preferences.h: + Remove NAUTILUS_PREFERENCES_ICON_CAPTIONS, its not needed anymore. + + * libnautilus-extensions/nautilus-global-preferences.c: + (global_preferences_populate_pane): Add support for installing a + list if strings to ignore when enforcing the unique choice rule + for enumeration lists items. + (global_preferences_create_dialog), + (nautilus_global_preferences_initialize): Register the + enumerations at initialization time instead of dialog creation + time. This is needed so that sanity checking on enumeration + preferences can occur even if the user hasnt opened the dialog. + + * libnautilus-extensions/nautilus-preferences-item.h: + * libnautilus-extensions/nautilus-preferences-item.c: + (nautilus_preferences_item_initialize_class), + (nautilus_preferences_item_initialize), (preferences_item_destroy), + (preferences_item_update_enumeration_list_uniqueness), + (preferences_item_update_enumeration_list), + (preferences_item_create_enumeration_list), + (enumeration_list_changed_callback), + (nautilus_preferences_item_enumeration_list_set_unique_exceptions): + Make sure the string pickers are wired such that duplicate choices cannot be + made by the user. We do this by making items that would result in duplicates + insensitive. Its possible to bypass this rule for some items. We use the + use the enumeration_list_unique_exceptions. + + * libnautilus-extensions/nautilus-preferences.c: + (preferences_block_callbacks), (preferences_unblock_callbacks): + New private functions to block/unblock preferences callbacks. + (string_list_is_valid): New private function to sanity check the + values of a string list. + (nautilus_preferences_get_string_list): Sanity check the results + of this function for greater convenience of the callers - they no + longer need to do error checking on the result. + (preferences_entry_invoke_callbacks_if_needed): Invoke callbacks + only if they are not blocked. + + * src/file-manager/Makefile.am: + * src/file-manager/fm-icon-text-window.c: + * src/file-manager/fm-icon-text-window.h: + Retire these 2 files. There no longer is a Icon Captions window. + + * src/file-manager/fm-directory-view.c: + (fm_directory_view_initialize), (fm_directory_view_destroy): + Update for slight change in the Icon Captions preference name. + + * src/file-manager/fm-icon-view.c: + (fm_icon_view_get_icon_text_attributes_from_preferences): New + function to fetch the icon caption attributes from preferences. A + similar function used to live in fm-icon-text-window.[ch]. That + is no longer the case now that the Icon Captions have moved into + the preferences dialog. + (fm_icon_view_get_icon_text_attribute_names): Simplify the munging + of icon captions by using a string list. + (fm_icon_view_merge_menus): Remove the Icon Captions menu. The + Icon Captions picker now lives in the preferences dialog. + + * src/file-manager/nautilus-icon-view-ui.xml: + Remove Icon Captions menu item which no longer exists. + 2001-04-17 Darin Adler <darin@eazel.com> * THANKS: Added a translator's name. diff --git a/libnautilus-extensions/nautilus-global-preferences.c b/libnautilus-extensions/nautilus-global-preferences.c index 4686e80f4..0e5925ffe 100644 --- a/libnautilus-extensions/nautilus-global-preferences.c +++ b/libnautilus-extensions/nautilus-global-preferences.c @@ -818,6 +818,7 @@ struct PreferenceDialogItem const char *control_preference_name; NautilusPreferencesItemControlAction control_action; int column; + const char *enumeration_list_unique_exceptions; }; /* The following tables define preference items for the preferences dialog. @@ -883,6 +884,21 @@ struct PreferenceDialogItem * a frame. Each of these groups can have 0 or 1 columns of preference * item widgets. This field controls which column the preference item * widgets appear in. + * + * 8. enumeration_list_unique_exceptions + * If the item type is one of: + * + * NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL + * NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + * + * The this field can be a string of exceptions to the rule that enumeration + * list items must always not allow duplicate choices. For example, if there + * are 3 string pickers in the item, then each one cannot select and item + * which is already selected in one of the other two. The preferences item + * widget enforces this rule by making such items insensitive. + * + * The enumeration_list_unique_exceptions allows a way to bypass this rule + * for certain choices. */ static PreferenceDialogItem appearance_items[] = { { N_("Smoother Graphics"), @@ -999,7 +1015,11 @@ static PreferenceDialogItem icon_captions_items[] = { NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, N_("Choose the order for information to appear beneath icon names.\n" "More information appears as you zoom in closer"), - NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL, + NULL, + 0, + 0, + "none" }, { NULL } }; @@ -1216,8 +1236,6 @@ global_preferences_create_dialog (void) preference_box = NAUTILUS_PREFERENCES_BOX (nautilus_preferences_dialog_get_prefs_box (NAUTILUS_PREFERENCES_DIALOG (prefs_dialog))); - global_preferences_register_enumerations (); - /* View Preferences */ global_preferences_populate_pane (preference_box, _("View Preferences"), @@ -1412,6 +1430,7 @@ global_preferences_populate_pane (NautilusPreferencesBox *preference_box, preference_dialog_item[i].item_type, preference_dialog_item[i].column); + /* Install a control preference if needed */ if (preference_dialog_item[i].control_preference_name != NULL) { nautilus_preferences_item_set_control_preference (NAUTILUS_PREFERENCES_ITEM (item), preference_dialog_item[i].control_preference_name); @@ -1420,6 +1439,19 @@ global_preferences_populate_pane (NautilusPreferencesBox *preference_box, nautilus_preferences_pane_add_control_preference (NAUTILUS_PREFERENCES_PANE (pane), preference_dialog_item[i].control_preference_name); + + } + + /* Install exceptions to enum lists uniqueness rule */ + if (preference_dialog_item[i].enumeration_list_unique_exceptions != NULL) { + g_assert (preference_dialog_item[i].item_type == + NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + || preference_dialog_item[i].item_type == + NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL); + nautilus_preferences_item_enumeration_list_set_unique_exceptions ( + NAUTILUS_PREFERENCES_ITEM (item), + preference_dialog_item[i].enumeration_list_unique_exceptions, + STRING_LIST_DEFAULT_TOKENS_DELIMETER); } } @@ -1598,6 +1630,8 @@ nautilus_global_preferences_initialize (void) /* Install defaults */ global_preferences_install_defaults (); + global_preferences_register_enumerations (); + /* Set up storage for values accessed in this file */ nautilus_preferences_add_auto_string (NAUTILUS_PREFERENCES_ICON_VIEW_SMOOTH_FONT, &icon_view_smooth_font_auto_value); diff --git a/libnautilus-extensions/nautilus-global-preferences.h b/libnautilus-extensions/nautilus-global-preferences.h index ffbb7d044..cf0d45773 100644 --- a/libnautilus-extensions/nautilus-global-preferences.h +++ b/libnautilus-extensions/nautilus-global-preferences.h @@ -31,8 +31,6 @@ BEGIN_GNOME_DECLS /* Which theme is active */ #define NAUTILUS_PREFERENCES_THEME "preferences/theme" -/* Which text attributes appear beneath icon names */ -#define NAUTILUS_PREFERENCES_ICON_CAPTIONS "icon_view/captions" /* How wide the sidebar is (or how wide it will be when expanded) */ #define NAUTILUS_PREFERENCES_SIDEBAR_WIDTH "preferences/sidebar_width" diff --git a/libnautilus-extensions/nautilus-preferences-item.c b/libnautilus-extensions/nautilus-preferences-item.c index d8f46a6f3..c3026ef96 100644 --- a/libnautilus-extensions/nautilus-preferences-item.c +++ b/libnautilus-extensions/nautilus-preferences-item.c @@ -62,6 +62,7 @@ struct NautilusPreferencesItemDetails GSList *change_signal_connections; char *control_preference_name; NautilusPreferencesItemControlAction control_action; + EelStringList *enumeration_list_unique_exceptions; }; /* GtkObjectClass methods */ @@ -76,9 +77,9 @@ static void preferences_item_create_editable_string (NautilusP static void preferences_item_create_enumeration_menu (NautilusPreferencesItem *item); static void preferences_item_create_enumeration_radio (NautilusPreferencesItem *item, gboolean horizontal); -static void preferences_item_create_enumeration_list (NautilusPreferencesItem *item, - gboolean horizontal); -static void preferences_item_create_font (NautilusPreferencesItem *item); +static void preferences_item_create_enumeration_list (NautilusPreferencesItem *item, + gboolean horizontal); +static void preferences_item_create_font (NautilusPreferencesItem *item); static void preferences_item_create_font (NautilusPreferencesItem *item); static void preferences_item_create_padding (NautilusPreferencesItem *item); static void preferences_item_create_smooth_font (NautilusPreferencesItem *item); @@ -100,8 +101,8 @@ static void enumeration_menu_changed_callback (EelString NautilusPreferencesItem *item); static void font_changed_callback (GtkWidget *caption, gpointer user_data); -static void enumeration_list_changed_callback (EelStringPicker *string_picker, - NautilusPreferencesItem *item); +static void enumeration_list_changed_callback (EelStringPicker *string_picker, + NautilusPreferencesItem *item); static void smooth_font_changed_callback (EelFontPicker *font_picker, gpointer callback_data); @@ -112,12 +113,8 @@ static void nautilus_preferences_item_initialize_class (NautilusPreferencesItemClass *preferences_item_class) { GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = GTK_OBJECT_CLASS (preferences_item_class); - widget_class = GTK_WIDGET_CLASS (preferences_item_class); - parent_class = gtk_type_class (gtk_vbox_get_type ()); + object_class = GTK_OBJECT_CLASS (preferences_item_class); /* GtkObjectClass */ object_class->destroy = preferences_item_destroy; @@ -128,6 +125,7 @@ nautilus_preferences_item_initialize (NautilusPreferencesItem *item) { item->details = g_new0 (NautilusPreferencesItemDetails, 1); item->details->item_type = PREFERENCES_ITEM_UNDEFINED_ITEM; + item->details->enumeration_list_unique_exceptions = eel_string_list_new (TRUE); } /* GtkObjectClass methods */ @@ -143,6 +141,7 @@ preferences_item_destroy (GtkObject *object) g_free (item->details->preference_name); g_free (item->details->control_preference_name); eel_g_slist_free_deep (item->details->change_signal_connections); + eel_string_list_free (item->details->enumeration_list_unique_exceptions); g_free (item->details); /* Chain destroy */ @@ -179,6 +178,74 @@ preferences_item_update_enumeration_radio (NautilusPreferencesItem *item) g_free (enumeration_id); } +/* Make sure the string pickers are wired such that duplicate choices cannot be + * made by the user. We do this by making items that would result in duplicates + * insensitive. Its possible to bypass this rule for some items. We use the + * use the enumeration_list_unique_exceptions for that. + */ +static void +preferences_item_update_enumeration_list_uniqueness (NautilusPreferencesItem *item) +{ + const GSList *node; + guint i; + guint j; + const PreferencesItemConnection *connection; + guint num_pickers; + EelStringList **insensitive_lists; + char *selected_string; + + g_return_if_fail (item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + || item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL); + + num_pickers = g_slist_length (item->details->change_signal_connections); + + g_return_if_fail (num_pickers > 0); + + /* Allocate as many insensitive lists as we have string pickers */ + insensitive_lists = g_new (EelStringList *, num_pickers); + for (j = 0; j < num_pickers; j++) { + insensitive_lists[j] = eel_string_list_new (TRUE); + } + + /* Populate the insensitive lists with the selected strings of all the + * other lists. + */ + for (node = item->details->change_signal_connections, i = 0; node != NULL; node = node->next, i++) { + g_assert (node->data != NULL); + + connection = node->data; + g_assert (EEL_IS_STRING_PICKER (connection->widget)); + + selected_string = eel_string_picker_get_selected_string (EEL_STRING_PICKER (connection->widget)); + + for (j = 0; j < num_pickers; j++) { + if (j != i && !eel_string_list_contains (item->details->enumeration_list_unique_exceptions, + selected_string)) { + eel_string_list_insert (insensitive_lists[j], + selected_string); + } + } + g_free (selected_string); + } + + /* Install the insensitive lists on the string pickers */ + for (node = item->details->change_signal_connections, i = 0; node != NULL; node = node->next, i++) { + g_assert (node->data != NULL); + + connection = node->data; + g_assert (EEL_IS_STRING_PICKER (connection->widget)); + + eel_string_picker_set_insensitive_list (EEL_STRING_PICKER (connection->widget), + insensitive_lists[i]); + } + + /* Free the insensitive lists */ + for (j = 0; j < num_pickers; j++) { + eel_string_list_free (insensitive_lists[j]); + } + g_free (insensitive_lists); +} + static void preferences_item_update_enumeration_list (NautilusPreferencesItem *item) { @@ -226,6 +293,8 @@ preferences_item_update_enumeration_list (NautilusPreferencesItem *item) eel_string_list_free (value); g_free (enumeration_id); + + preferences_item_update_enumeration_list_uniqueness (item); } /* This callback is called whenever the preference value changes, so that we can @@ -381,7 +450,7 @@ preferences_item_create_enumeration_list (NautilusPreferencesItem *item, gtk_widget_show (title); gtk_widget_show (picker_box); - /* Populate the radio group */ + /* Populate the string pickers */ for (j = 0; j < num_pickers; j++) { string_picker = eel_string_picker_new (); eel_caption_set_show_title (EEL_CAPTION (string_picker), FALSE); @@ -406,7 +475,6 @@ preferences_item_create_enumeration_list (NautilusPreferencesItem *item, string_picker, "changed", GTK_SIGNAL_FUNC (enumeration_list_changed_callback)); - } g_free (enumeration_id); @@ -1009,11 +1077,7 @@ enumeration_list_changed_callback (EelStringPicker *string_picker, g_free (enumeration_id); -// { -// EelStringList *foo; -// foo = nautilus_preferences_get_string_list (item->details->preference_name); -// g_print ("new_value = %s\n", eel_string_list_as_string (foo, ",", EEL_STRING_LIST_ALL_STRINGS)); -// } + preferences_item_update_enumeration_list_uniqueness (item); } char * @@ -1273,3 +1337,31 @@ nautilus_preferences_item_update_showing (NautilusPreferencesItem *item) eel_gtk_widget_set_shown (GTK_WIDGET (item), nautilus_preferences_item_is_showing (item)); } + +void +nautilus_preferences_item_enumeration_list_set_unique_exceptions (NautilusPreferencesItem *item, + const char *exceptions, + const char *exceptions_delimeter) +{ + EelStringList *new_exceptions; + + g_return_if_fail (NAUTILUS_IS_PREFERENCES_ITEM (item)); + g_return_if_fail (item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + || item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL); + g_return_if_fail (eel_strlen (exceptions_delimeter) > 0); + + new_exceptions = eel_string_list_new_from_tokens (exceptions, + exceptions_delimeter, + TRUE); + + if (eel_string_list_equals (new_exceptions, item->details->enumeration_list_unique_exceptions)) { + eel_string_list_free (new_exceptions); + return; + } + + eel_string_list_free (item->details->enumeration_list_unique_exceptions); + item->details->enumeration_list_unique_exceptions = new_exceptions; + + preferences_item_update_enumeration_list_uniqueness (item); +} + diff --git a/libnautilus-extensions/nautilus-preferences-item.h b/libnautilus-extensions/nautilus-preferences-item.h index 2361b75c1..497aaec0f 100644 --- a/libnautilus-extensions/nautilus-preferences-item.h +++ b/libnautilus-extensions/nautilus-preferences-item.h @@ -83,20 +83,23 @@ typedef enum NAUTILUS_PREFERENCE_ITEM_HIDE } NautilusPreferencesItemControlAction; -GtkType nautilus_preferences_item_get_type (void); -GtkWidget* nautilus_preferences_item_new (const char *preference_name, - NautilusPreferencesItemType item_type); -char * nautilus_preferences_item_get_name (const NautilusPreferencesItem *preferences_item); -void nautilus_preferences_item_set_control_preference (NautilusPreferencesItem *preferences_item, - const char *control_preference_name); -void nautilus_preferences_item_set_control_action (NautilusPreferencesItem *preferences_item, - NautilusPreferencesItemControlAction control_action); -gboolean nautilus_preferences_item_child_is_caption (const NautilusPreferencesItem *preferences_item); -int nautilus_preferences_item_get_child_width (const NautilusPreferencesItem *item); -void nautilus_preferences_item_set_caption_extra_spacing (NautilusPreferencesItem *item, - int extra_spacing); -void nautilus_preferences_item_update_showing (NautilusPreferencesItem *item); -gboolean nautilus_preferences_item_is_showing (const NautilusPreferencesItem *item); +GtkType nautilus_preferences_item_get_type (void); +GtkWidget* nautilus_preferences_item_new (const char *preference_name, + NautilusPreferencesItemType item_type); +char * nautilus_preferences_item_get_name (const NautilusPreferencesItem *preferences_item); +void nautilus_preferences_item_set_control_preference (NautilusPreferencesItem *preferences_item, + const char *control_preference_name); +void nautilus_preferences_item_set_control_action (NautilusPreferencesItem *preferences_item, + NautilusPreferencesItemControlAction control_action); +gboolean nautilus_preferences_item_child_is_caption (const NautilusPreferencesItem *preferences_item); +int nautilus_preferences_item_get_child_width (const NautilusPreferencesItem *item); +void nautilus_preferences_item_set_caption_extra_spacing (NautilusPreferencesItem *item, + int extra_spacing); +void nautilus_preferences_item_update_showing (NautilusPreferencesItem *item); +gboolean nautilus_preferences_item_is_showing (const NautilusPreferencesItem *item); +void nautilus_preferences_item_enumeration_list_set_unique_exceptions (NautilusPreferencesItem *item, + const char *exceptions, + const char *exceptions_delimeter); END_GNOME_DECLS diff --git a/libnautilus-extensions/nautilus-preferences.c b/libnautilus-extensions/nautilus-preferences.c index 8212e6fdc..9df5f6175 100644 --- a/libnautilus-extensions/nautilus-preferences.c +++ b/libnautilus-extensions/nautilus-preferences.c @@ -27,6 +27,7 @@ #include "nautilus-gconf-extensions.h" #include "nautilus-lib-self-check-functions.h" +#include <eel/eel-enumeration.h> #include <eel/eel-glib-extensions.h> #include <eel/eel-string-list.h> #include <eel/eel-string.h> @@ -65,6 +66,7 @@ typedef struct { char *description; PreferenceType type; GList *callback_list; + gboolean callbacks_blocked; GList *auto_storage_list; int gconf_connection_id; char *enumeration_id; @@ -126,6 +128,7 @@ static void preferences_callback_entry_free (Preferences static void preferences_entry_update_auto_storage (PreferencesEntry *entry); static void preferences_global_table_free (void); static const char * preferences_peek_user_level_name_for_storage (int user_level); +static PreferencesEntry * preferences_global_table_lookup_or_insert (const char *name); static guint user_level_changed_connection_id = NAUTILUS_GCONF_UNDEFINED_CONNECTION; static GHashTable *global_table = NULL; @@ -326,6 +329,34 @@ preferences_make_user_level_filtered_key (const char *name) return key; } +static void +preferences_block_callbacks (const char *name) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + entry->callbacks_blocked = TRUE; +} + +static void +preferences_unblock_callbacks (const char *name) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + entry->callbacks_blocked = FALSE; +} + /* Public preferences functions */ int nautilus_preferences_get_visible_user_level (const char *name) @@ -504,12 +535,35 @@ nautilus_preferences_set_string_list (const char *name, nautilus_gconf_suggest_sync (); } +static gboolean +string_list_is_valid (const EelStringList *string_list, + const char *enumeration_id) +{ + guint i; + char *nth; + gboolean bad; + + g_return_val_if_fail (string_list != NULL, FALSE); + g_return_val_if_fail (enumeration_id != NULL, FALSE); + + bad = FALSE; + for (i = 0; i < eel_string_list_get_length (string_list) && !bad; i++) { + nth = eel_string_list_nth (string_list, i); + bad = !eel_enumeration_id_contains_name (enumeration_id, nth); + g_free (nth); + } + + return !bad; +} + EelStringList * nautilus_preferences_get_string_list (const char *name) { EelStringList *result; char *key; GSList *slist; + PreferencesEntry *entry; + char *default_key; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (preferences_is_initialized (), NULL); @@ -520,6 +574,35 @@ nautilus_preferences_get_string_list (const char *name) result = eel_string_list_new_from_g_slist (slist, TRUE); eel_g_slist_free_deep (slist); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + /* No enumeration_id so we're done */ + if (entry->enumeration_id == NULL) { + return result; + } + + /* Do a sanity check on the validity of the values */ + if (string_list_is_valid (result, entry->enumeration_id)) { + return result; + } + + /* Forget the bad value and use the default instead */ + eel_string_list_free (result); + default_key = preferences_key_make_for_default_getter (name, + nautilus_preferences_get_user_level ()); + slist = nautilus_gconf_get_string_list (default_key); + g_free (default_key); + + result = eel_string_list_new_from_g_slist (slist, TRUE); + eel_g_slist_free_deep (slist); + + /* Go the extra mile and fix the problem for the user */ + preferences_block_callbacks (name); + nautilus_preferences_set_string_list (name, result); + preferences_unblock_callbacks (name); + return result; } @@ -759,6 +842,11 @@ preferences_entry_invoke_callbacks_if_needed (PreferencesEntry *entry) /* Store the new cached value */ nautilus_gconf_value_free (entry->cached_value); entry->cached_value = new_value; + + /* Dont invoke callbacks if the entry is blocked */ + if (entry->callbacks_blocked) { + return; + } /* Invoke callbacks for this entry if any */ if (entry->callback_list != NULL) { diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c index 4686e80f4..0e5925ffe 100644 --- a/libnautilus-private/nautilus-global-preferences.c +++ b/libnautilus-private/nautilus-global-preferences.c @@ -818,6 +818,7 @@ struct PreferenceDialogItem const char *control_preference_name; NautilusPreferencesItemControlAction control_action; int column; + const char *enumeration_list_unique_exceptions; }; /* The following tables define preference items for the preferences dialog. @@ -883,6 +884,21 @@ struct PreferenceDialogItem * a frame. Each of these groups can have 0 or 1 columns of preference * item widgets. This field controls which column the preference item * widgets appear in. + * + * 8. enumeration_list_unique_exceptions + * If the item type is one of: + * + * NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL + * NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + * + * The this field can be a string of exceptions to the rule that enumeration + * list items must always not allow duplicate choices. For example, if there + * are 3 string pickers in the item, then each one cannot select and item + * which is already selected in one of the other two. The preferences item + * widget enforces this rule by making such items insensitive. + * + * The enumeration_list_unique_exceptions allows a way to bypass this rule + * for certain choices. */ static PreferenceDialogItem appearance_items[] = { { N_("Smoother Graphics"), @@ -999,7 +1015,11 @@ static PreferenceDialogItem icon_captions_items[] = { NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, N_("Choose the order for information to appear beneath icon names.\n" "More information appears as you zoom in closer"), - NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL, + NULL, + 0, + 0, + "none" }, { NULL } }; @@ -1216,8 +1236,6 @@ global_preferences_create_dialog (void) preference_box = NAUTILUS_PREFERENCES_BOX (nautilus_preferences_dialog_get_prefs_box (NAUTILUS_PREFERENCES_DIALOG (prefs_dialog))); - global_preferences_register_enumerations (); - /* View Preferences */ global_preferences_populate_pane (preference_box, _("View Preferences"), @@ -1412,6 +1430,7 @@ global_preferences_populate_pane (NautilusPreferencesBox *preference_box, preference_dialog_item[i].item_type, preference_dialog_item[i].column); + /* Install a control preference if needed */ if (preference_dialog_item[i].control_preference_name != NULL) { nautilus_preferences_item_set_control_preference (NAUTILUS_PREFERENCES_ITEM (item), preference_dialog_item[i].control_preference_name); @@ -1420,6 +1439,19 @@ global_preferences_populate_pane (NautilusPreferencesBox *preference_box, nautilus_preferences_pane_add_control_preference (NAUTILUS_PREFERENCES_PANE (pane), preference_dialog_item[i].control_preference_name); + + } + + /* Install exceptions to enum lists uniqueness rule */ + if (preference_dialog_item[i].enumeration_list_unique_exceptions != NULL) { + g_assert (preference_dialog_item[i].item_type == + NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + || preference_dialog_item[i].item_type == + NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL); + nautilus_preferences_item_enumeration_list_set_unique_exceptions ( + NAUTILUS_PREFERENCES_ITEM (item), + preference_dialog_item[i].enumeration_list_unique_exceptions, + STRING_LIST_DEFAULT_TOKENS_DELIMETER); } } @@ -1598,6 +1630,8 @@ nautilus_global_preferences_initialize (void) /* Install defaults */ global_preferences_install_defaults (); + global_preferences_register_enumerations (); + /* Set up storage for values accessed in this file */ nautilus_preferences_add_auto_string (NAUTILUS_PREFERENCES_ICON_VIEW_SMOOTH_FONT, &icon_view_smooth_font_auto_value); diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h index ffbb7d044..cf0d45773 100644 --- a/libnautilus-private/nautilus-global-preferences.h +++ b/libnautilus-private/nautilus-global-preferences.h @@ -31,8 +31,6 @@ BEGIN_GNOME_DECLS /* Which theme is active */ #define NAUTILUS_PREFERENCES_THEME "preferences/theme" -/* Which text attributes appear beneath icon names */ -#define NAUTILUS_PREFERENCES_ICON_CAPTIONS "icon_view/captions" /* How wide the sidebar is (or how wide it will be when expanded) */ #define NAUTILUS_PREFERENCES_SIDEBAR_WIDTH "preferences/sidebar_width" diff --git a/libnautilus-private/nautilus-preferences-item.c b/libnautilus-private/nautilus-preferences-item.c index d8f46a6f3..c3026ef96 100644 --- a/libnautilus-private/nautilus-preferences-item.c +++ b/libnautilus-private/nautilus-preferences-item.c @@ -62,6 +62,7 @@ struct NautilusPreferencesItemDetails GSList *change_signal_connections; char *control_preference_name; NautilusPreferencesItemControlAction control_action; + EelStringList *enumeration_list_unique_exceptions; }; /* GtkObjectClass methods */ @@ -76,9 +77,9 @@ static void preferences_item_create_editable_string (NautilusP static void preferences_item_create_enumeration_menu (NautilusPreferencesItem *item); static void preferences_item_create_enumeration_radio (NautilusPreferencesItem *item, gboolean horizontal); -static void preferences_item_create_enumeration_list (NautilusPreferencesItem *item, - gboolean horizontal); -static void preferences_item_create_font (NautilusPreferencesItem *item); +static void preferences_item_create_enumeration_list (NautilusPreferencesItem *item, + gboolean horizontal); +static void preferences_item_create_font (NautilusPreferencesItem *item); static void preferences_item_create_font (NautilusPreferencesItem *item); static void preferences_item_create_padding (NautilusPreferencesItem *item); static void preferences_item_create_smooth_font (NautilusPreferencesItem *item); @@ -100,8 +101,8 @@ static void enumeration_menu_changed_callback (EelString NautilusPreferencesItem *item); static void font_changed_callback (GtkWidget *caption, gpointer user_data); -static void enumeration_list_changed_callback (EelStringPicker *string_picker, - NautilusPreferencesItem *item); +static void enumeration_list_changed_callback (EelStringPicker *string_picker, + NautilusPreferencesItem *item); static void smooth_font_changed_callback (EelFontPicker *font_picker, gpointer callback_data); @@ -112,12 +113,8 @@ static void nautilus_preferences_item_initialize_class (NautilusPreferencesItemClass *preferences_item_class) { GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = GTK_OBJECT_CLASS (preferences_item_class); - widget_class = GTK_WIDGET_CLASS (preferences_item_class); - parent_class = gtk_type_class (gtk_vbox_get_type ()); + object_class = GTK_OBJECT_CLASS (preferences_item_class); /* GtkObjectClass */ object_class->destroy = preferences_item_destroy; @@ -128,6 +125,7 @@ nautilus_preferences_item_initialize (NautilusPreferencesItem *item) { item->details = g_new0 (NautilusPreferencesItemDetails, 1); item->details->item_type = PREFERENCES_ITEM_UNDEFINED_ITEM; + item->details->enumeration_list_unique_exceptions = eel_string_list_new (TRUE); } /* GtkObjectClass methods */ @@ -143,6 +141,7 @@ preferences_item_destroy (GtkObject *object) g_free (item->details->preference_name); g_free (item->details->control_preference_name); eel_g_slist_free_deep (item->details->change_signal_connections); + eel_string_list_free (item->details->enumeration_list_unique_exceptions); g_free (item->details); /* Chain destroy */ @@ -179,6 +178,74 @@ preferences_item_update_enumeration_radio (NautilusPreferencesItem *item) g_free (enumeration_id); } +/* Make sure the string pickers are wired such that duplicate choices cannot be + * made by the user. We do this by making items that would result in duplicates + * insensitive. Its possible to bypass this rule for some items. We use the + * use the enumeration_list_unique_exceptions for that. + */ +static void +preferences_item_update_enumeration_list_uniqueness (NautilusPreferencesItem *item) +{ + const GSList *node; + guint i; + guint j; + const PreferencesItemConnection *connection; + guint num_pickers; + EelStringList **insensitive_lists; + char *selected_string; + + g_return_if_fail (item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + || item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL); + + num_pickers = g_slist_length (item->details->change_signal_connections); + + g_return_if_fail (num_pickers > 0); + + /* Allocate as many insensitive lists as we have string pickers */ + insensitive_lists = g_new (EelStringList *, num_pickers); + for (j = 0; j < num_pickers; j++) { + insensitive_lists[j] = eel_string_list_new (TRUE); + } + + /* Populate the insensitive lists with the selected strings of all the + * other lists. + */ + for (node = item->details->change_signal_connections, i = 0; node != NULL; node = node->next, i++) { + g_assert (node->data != NULL); + + connection = node->data; + g_assert (EEL_IS_STRING_PICKER (connection->widget)); + + selected_string = eel_string_picker_get_selected_string (EEL_STRING_PICKER (connection->widget)); + + for (j = 0; j < num_pickers; j++) { + if (j != i && !eel_string_list_contains (item->details->enumeration_list_unique_exceptions, + selected_string)) { + eel_string_list_insert (insensitive_lists[j], + selected_string); + } + } + g_free (selected_string); + } + + /* Install the insensitive lists on the string pickers */ + for (node = item->details->change_signal_connections, i = 0; node != NULL; node = node->next, i++) { + g_assert (node->data != NULL); + + connection = node->data; + g_assert (EEL_IS_STRING_PICKER (connection->widget)); + + eel_string_picker_set_insensitive_list (EEL_STRING_PICKER (connection->widget), + insensitive_lists[i]); + } + + /* Free the insensitive lists */ + for (j = 0; j < num_pickers; j++) { + eel_string_list_free (insensitive_lists[j]); + } + g_free (insensitive_lists); +} + static void preferences_item_update_enumeration_list (NautilusPreferencesItem *item) { @@ -226,6 +293,8 @@ preferences_item_update_enumeration_list (NautilusPreferencesItem *item) eel_string_list_free (value); g_free (enumeration_id); + + preferences_item_update_enumeration_list_uniqueness (item); } /* This callback is called whenever the preference value changes, so that we can @@ -381,7 +450,7 @@ preferences_item_create_enumeration_list (NautilusPreferencesItem *item, gtk_widget_show (title); gtk_widget_show (picker_box); - /* Populate the radio group */ + /* Populate the string pickers */ for (j = 0; j < num_pickers; j++) { string_picker = eel_string_picker_new (); eel_caption_set_show_title (EEL_CAPTION (string_picker), FALSE); @@ -406,7 +475,6 @@ preferences_item_create_enumeration_list (NautilusPreferencesItem *item, string_picker, "changed", GTK_SIGNAL_FUNC (enumeration_list_changed_callback)); - } g_free (enumeration_id); @@ -1009,11 +1077,7 @@ enumeration_list_changed_callback (EelStringPicker *string_picker, g_free (enumeration_id); -// { -// EelStringList *foo; -// foo = nautilus_preferences_get_string_list (item->details->preference_name); -// g_print ("new_value = %s\n", eel_string_list_as_string (foo, ",", EEL_STRING_LIST_ALL_STRINGS)); -// } + preferences_item_update_enumeration_list_uniqueness (item); } char * @@ -1273,3 +1337,31 @@ nautilus_preferences_item_update_showing (NautilusPreferencesItem *item) eel_gtk_widget_set_shown (GTK_WIDGET (item), nautilus_preferences_item_is_showing (item)); } + +void +nautilus_preferences_item_enumeration_list_set_unique_exceptions (NautilusPreferencesItem *item, + const char *exceptions, + const char *exceptions_delimeter) +{ + EelStringList *new_exceptions; + + g_return_if_fail (NAUTILUS_IS_PREFERENCES_ITEM (item)); + g_return_if_fail (item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_VERTICAL + || item->details->item_type == NAUTILUS_PREFERENCE_ITEM_ENUMERATION_LIST_HORIZONTAL); + g_return_if_fail (eel_strlen (exceptions_delimeter) > 0); + + new_exceptions = eel_string_list_new_from_tokens (exceptions, + exceptions_delimeter, + TRUE); + + if (eel_string_list_equals (new_exceptions, item->details->enumeration_list_unique_exceptions)) { + eel_string_list_free (new_exceptions); + return; + } + + eel_string_list_free (item->details->enumeration_list_unique_exceptions); + item->details->enumeration_list_unique_exceptions = new_exceptions; + + preferences_item_update_enumeration_list_uniqueness (item); +} + diff --git a/libnautilus-private/nautilus-preferences-item.h b/libnautilus-private/nautilus-preferences-item.h index 2361b75c1..497aaec0f 100644 --- a/libnautilus-private/nautilus-preferences-item.h +++ b/libnautilus-private/nautilus-preferences-item.h @@ -83,20 +83,23 @@ typedef enum NAUTILUS_PREFERENCE_ITEM_HIDE } NautilusPreferencesItemControlAction; -GtkType nautilus_preferences_item_get_type (void); -GtkWidget* nautilus_preferences_item_new (const char *preference_name, - NautilusPreferencesItemType item_type); -char * nautilus_preferences_item_get_name (const NautilusPreferencesItem *preferences_item); -void nautilus_preferences_item_set_control_preference (NautilusPreferencesItem *preferences_item, - const char *control_preference_name); -void nautilus_preferences_item_set_control_action (NautilusPreferencesItem *preferences_item, - NautilusPreferencesItemControlAction control_action); -gboolean nautilus_preferences_item_child_is_caption (const NautilusPreferencesItem *preferences_item); -int nautilus_preferences_item_get_child_width (const NautilusPreferencesItem *item); -void nautilus_preferences_item_set_caption_extra_spacing (NautilusPreferencesItem *item, - int extra_spacing); -void nautilus_preferences_item_update_showing (NautilusPreferencesItem *item); -gboolean nautilus_preferences_item_is_showing (const NautilusPreferencesItem *item); +GtkType nautilus_preferences_item_get_type (void); +GtkWidget* nautilus_preferences_item_new (const char *preference_name, + NautilusPreferencesItemType item_type); +char * nautilus_preferences_item_get_name (const NautilusPreferencesItem *preferences_item); +void nautilus_preferences_item_set_control_preference (NautilusPreferencesItem *preferences_item, + const char *control_preference_name); +void nautilus_preferences_item_set_control_action (NautilusPreferencesItem *preferences_item, + NautilusPreferencesItemControlAction control_action); +gboolean nautilus_preferences_item_child_is_caption (const NautilusPreferencesItem *preferences_item); +int nautilus_preferences_item_get_child_width (const NautilusPreferencesItem *item); +void nautilus_preferences_item_set_caption_extra_spacing (NautilusPreferencesItem *item, + int extra_spacing); +void nautilus_preferences_item_update_showing (NautilusPreferencesItem *item); +gboolean nautilus_preferences_item_is_showing (const NautilusPreferencesItem *item); +void nautilus_preferences_item_enumeration_list_set_unique_exceptions (NautilusPreferencesItem *item, + const char *exceptions, + const char *exceptions_delimeter); END_GNOME_DECLS diff --git a/libnautilus-private/nautilus-preferences.c b/libnautilus-private/nautilus-preferences.c index 8212e6fdc..9df5f6175 100644 --- a/libnautilus-private/nautilus-preferences.c +++ b/libnautilus-private/nautilus-preferences.c @@ -27,6 +27,7 @@ #include "nautilus-gconf-extensions.h" #include "nautilus-lib-self-check-functions.h" +#include <eel/eel-enumeration.h> #include <eel/eel-glib-extensions.h> #include <eel/eel-string-list.h> #include <eel/eel-string.h> @@ -65,6 +66,7 @@ typedef struct { char *description; PreferenceType type; GList *callback_list; + gboolean callbacks_blocked; GList *auto_storage_list; int gconf_connection_id; char *enumeration_id; @@ -126,6 +128,7 @@ static void preferences_callback_entry_free (Preferences static void preferences_entry_update_auto_storage (PreferencesEntry *entry); static void preferences_global_table_free (void); static const char * preferences_peek_user_level_name_for_storage (int user_level); +static PreferencesEntry * preferences_global_table_lookup_or_insert (const char *name); static guint user_level_changed_connection_id = NAUTILUS_GCONF_UNDEFINED_CONNECTION; static GHashTable *global_table = NULL; @@ -326,6 +329,34 @@ preferences_make_user_level_filtered_key (const char *name) return key; } +static void +preferences_block_callbacks (const char *name) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + entry->callbacks_blocked = TRUE; +} + +static void +preferences_unblock_callbacks (const char *name) +{ + PreferencesEntry *entry; + + g_return_if_fail (name != NULL); + g_return_if_fail (preferences_is_initialized ()); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + entry->callbacks_blocked = FALSE; +} + /* Public preferences functions */ int nautilus_preferences_get_visible_user_level (const char *name) @@ -504,12 +535,35 @@ nautilus_preferences_set_string_list (const char *name, nautilus_gconf_suggest_sync (); } +static gboolean +string_list_is_valid (const EelStringList *string_list, + const char *enumeration_id) +{ + guint i; + char *nth; + gboolean bad; + + g_return_val_if_fail (string_list != NULL, FALSE); + g_return_val_if_fail (enumeration_id != NULL, FALSE); + + bad = FALSE; + for (i = 0; i < eel_string_list_get_length (string_list) && !bad; i++) { + nth = eel_string_list_nth (string_list, i); + bad = !eel_enumeration_id_contains_name (enumeration_id, nth); + g_free (nth); + } + + return !bad; +} + EelStringList * nautilus_preferences_get_string_list (const char *name) { EelStringList *result; char *key; GSList *slist; + PreferencesEntry *entry; + char *default_key; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (preferences_is_initialized (), NULL); @@ -520,6 +574,35 @@ nautilus_preferences_get_string_list (const char *name) result = eel_string_list_new_from_g_slist (slist, TRUE); eel_g_slist_free_deep (slist); + + entry = preferences_global_table_lookup_or_insert (name); + g_assert (entry != NULL); + + /* No enumeration_id so we're done */ + if (entry->enumeration_id == NULL) { + return result; + } + + /* Do a sanity check on the validity of the values */ + if (string_list_is_valid (result, entry->enumeration_id)) { + return result; + } + + /* Forget the bad value and use the default instead */ + eel_string_list_free (result); + default_key = preferences_key_make_for_default_getter (name, + nautilus_preferences_get_user_level ()); + slist = nautilus_gconf_get_string_list (default_key); + g_free (default_key); + + result = eel_string_list_new_from_g_slist (slist, TRUE); + eel_g_slist_free_deep (slist); + + /* Go the extra mile and fix the problem for the user */ + preferences_block_callbacks (name); + nautilus_preferences_set_string_list (name, result); + preferences_unblock_callbacks (name); + return result; } @@ -759,6 +842,11 @@ preferences_entry_invoke_callbacks_if_needed (PreferencesEntry *entry) /* Store the new cached value */ nautilus_gconf_value_free (entry->cached_value); entry->cached_value = new_value; + + /* Dont invoke callbacks if the entry is blocked */ + if (entry->callbacks_blocked) { + return; + } /* Invoke callbacks for this entry if any */ if (entry->callback_list != NULL) { diff --git a/src/file-manager/Makefile.am b/src/file-manager/Makefile.am index a1c825f98..7c08cc4ed 100644 --- a/src/file-manager/Makefile.am +++ b/src/file-manager/Makefile.am @@ -22,7 +22,6 @@ libnautilus_file_manager_la_SOURCES= \ fm-desktop-icon-view.c \ fm-directory-view.c \ fm-error-reporting.c \ - fm-icon-text-window.c \ fm-icon-view.c \ fm-list-view.c \ fm-properties-window.c \ @@ -34,7 +33,6 @@ noinst_HEADERS = \ fm-desktop-icon-view.h \ fm-directory-view.h \ fm-error-reporting.h \ - fm-icon-text-window.h \ fm-icon-view.h \ fm-list-view-private.h \ fm-list-view.h \ diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index 60957c14c..ca2ddebeb 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -1186,7 +1186,7 @@ fm_directory_view_initialize (FMDirectoryView *view) nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ENABLE_DELETE, schedule_update_menus_callback, view); - nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ICON_CAPTIONS, + nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, text_attribute_names_changed_callback, view); nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, @@ -1256,7 +1256,7 @@ fm_directory_view_destroy (GtkObject *object) nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_ENABLE_DELETE, schedule_update_menus_callback, view); - nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_ICON_CAPTIONS, + nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, text_attribute_names_changed_callback, view); nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, diff --git a/src/file-manager/fm-icon-text-window.c b/src/file-manager/fm-icon-text-window.c deleted file mode 100644 index a9d3dd0f6..000000000 --- a/src/file-manager/fm-icon-text-window.c +++ /dev/null @@ -1,436 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* fm-icon-text-window.c - interface for window that lets user modify - displayed icon text. - - Copyright (C) 2000 Eazel, Inc. - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Authors: John Sullivan <sullivan@eazel.com> -*/ - -#include <config.h> -#include "fm-icon-text-window.h" - -#include <gtk/gtkaccellabel.h> -#include <gtk/gtkhbox.h> -#include <gtk/gtkhseparator.h> -#include <gtk/gtklabel.h> -#include <gtk/gtkmenu.h> -#include <gtk/gtkmenuitem.h> -#include <gtk/gtkoptionmenu.h> -#include <gtk/gtksignal.h> -#include <gtk/gtktext.h> -#include <gtk/gtkradiobutton.h> -#include <gtk/gtkvbox.h> -#include <libgnome/gnome-defs.h> -#include <libgnome/gnome-i18n.h> -#include <libgnomeui/gnome-uidefs.h> -#include <eel/eel-glib-extensions.h> -#include <libnautilus-extensions/nautilus-global-preferences.h> -#include <eel/eel-gtk-extensions.h> -#include <eel/eel-string.h> - -static void ensure_unique_attributes (int menu_index); -static gboolean fm_icon_text_window_delete_event_callback (GtkWidget *widget, - GdkEvent *event, - gpointer user_data); -static void fm_icon_text_window_destroy_callback (GtkObject *object, - gpointer user_data); - -#define DEFAULT_ATTRIBUTE_NAMES "size|date_modified|type" -#define PIECES_COUNT 3 -#define MENU_COUNT (PIECES_COUNT) - -static GtkOptionMenu *option_menus[MENU_COUNT]; - -static char * attribute_names[] = { - "size", - "type", - "date_modified", - "date_changed", - "date_accessed", - "owner", - "group", - "permissions", - "octal_permissions", - "mime_type", - "none", - NULL -}; - -static const char * attribute_labels[] = { - N_("size"), - N_("type"), - N_("date modified"), - N_("date changed"), - N_("date accessed"), - N_("owner"), - N_("group"), - N_("permissions"), - N_("octal permissions"), - N_("MIME type"), - N_("none"), - NULL -}; - -static int -get_attribute_index_from_option_menu (GtkOptionMenu *option_menu) -{ - g_assert (GTK_IS_OPTION_MENU (option_menu)); - return GPOINTER_TO_INT (gtk_object_get_user_data - (GTK_OBJECT (option_menu->menu_item))); -} - -static gboolean -attribute_names_string_is_good (const char *string) -{ - char **text_array; - int i, j, string_index; - int index_array[MENU_COUNT]; - - text_array = g_strsplit (string, "|", MENU_COUNT + 1); - - for (i = 0; i < MENU_COUNT; ++i) { - /* Check for too few attributes. */ - if (text_array[i] == NULL) { - break; - } - - /* Check for unknown attributes. */ - string_index = eel_g_strv_find (attribute_names, text_array[i]); - if (string_index < 0) { - break; - } - - /* Check for repeated attributes (except for none, which is allowed to repeat. */ - if (eel_strcmp (text_array[i], "none")) { - for (j = 0; j < i; j++) { - if (index_array[j] == string_index) { - goto bad; - } - } - } - - /* Remember this one for later. */ - index_array[i] = string_index; - } - bad: - - g_strfreev (text_array); - - /* It is good only if the entire for loop executed to completion. */ - return i == MENU_COUNT; -} - -static void -synch_menus_with_preference (gpointer user_data) -{ - char *preference; - char **text_array; - int i, string_index; - - preference = fm_get_text_attribute_names_preference (); - text_array = g_strsplit (preference, "|", 0); - g_free (preference); - - for (i = 0; i < MENU_COUNT; ++i) { - g_assert (text_array[i] != NULL); - string_index = eel_g_strv_find (attribute_names, text_array[i]); - g_assert (string_index >= 0); - gtk_option_menu_set_history (option_menus[i], string_index); - } - - g_strfreev (text_array); -} - -static char * -get_chosen_attribute_name (GtkOptionMenu *option_menu) -{ - int attribute_index; - - g_assert (GTK_IS_OPTION_MENU (option_menu)); - - attribute_index = get_attribute_index_from_option_menu (option_menu); - return g_strdup (attribute_names[attribute_index]); -} - -static void -changed_attributes_option_menu_callback (GtkMenuItem *menu_item, gpointer user_data) -{ - char ** attribute_names_array; - char * attribute_names_string; - int which_menu; - int index; - - which_menu = GPOINTER_TO_INT (user_data); - attribute_names_array = g_new0 (char *, PIECES_COUNT + 1); - - /* Check whether just-changed item matches any others. If so, - * change the other one to the first unused attribute. - */ - - ensure_unique_attributes (which_menu); - - for (index = 0; index < MENU_COUNT; ++index) { - attribute_names_array[index] = - get_chosen_attribute_name (option_menus[index]); - } - - attribute_names_string = g_strjoinv ("|", attribute_names_array); - - nautilus_preferences_set (NAUTILUS_PREFERENCES_ICON_CAPTIONS, - attribute_names_string); - - g_free (attribute_names_string); - g_strfreev (attribute_names_array); - - return; -} - -static GtkOptionMenu * -create_attributes_option_menu (int menu_number) -{ - GtkWidget *option_menu; - GtkWidget *menu; - int index; - - option_menu = gtk_option_menu_new (); - gtk_widget_show (option_menu); - menu = gtk_menu_new (); - - for (index = 0; attribute_names[index] != NULL; ++index) - { - GtkWidget *menu_item; - GtkWidget *accel_label; - - menu_item = gtk_menu_item_new (); - - /* Do some extra label-creating work so they're centered */ - accel_label = gtk_accel_label_new (_(attribute_labels[index])); - gtk_misc_set_alignment (GTK_MISC (accel_label), 0.5, 0.5); - gtk_container_add (GTK_CONTAINER (menu_item), accel_label); - gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item); - gtk_widget_show (accel_label); - - /* Store index in item as the way to get from item back to attribute name */ - gtk_object_set_user_data (GTK_OBJECT (menu_item), GINT_TO_POINTER (index)); - gtk_widget_show (menu_item); - gtk_menu_append (GTK_MENU (menu), menu_item); - - /* Wire all the menu items to the same callback. If any item is - * changed, the attribute text will be recomputed from scratch. - */ - gtk_signal_connect (GTK_OBJECT (menu_item), - "activate", - changed_attributes_option_menu_callback, - GINT_TO_POINTER (menu_number)); - } - - gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); - - return GTK_OPTION_MENU (option_menu); -} - -static GtkWidget * -create_icon_text_window (void) -{ - GtkWidget *window; - GtkWidget *contents_vbox; - GtkWidget *prompt; - GtkWidget *separator_line; - GtkWidget *hbox_to_center_menus; - GtkWidget *menus_vbox; - int index; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - eel_gtk_window_set_up_close_accelerator (GTK_WINDOW (window)); - gtk_container_set_border_width (GTK_CONTAINER (window), 8); - gtk_window_set_title (GTK_WINDOW (window), _("Icon Captions")); - gtk_window_set_wmclass (GTK_WINDOW (window), "icon_captions", "Nautilus"); - gtk_window_set_policy (GTK_WINDOW (window), FALSE, FALSE, FALSE); - - contents_vbox = gtk_vbox_new (FALSE, 0); - gtk_widget_show (contents_vbox); - gtk_container_add (GTK_CONTAINER (window), contents_vbox); - - prompt = gtk_label_new (_("Choose the order for information to appear beneath icon names. More information appears as you zoom in closer.")); - gtk_widget_show (prompt); - gtk_box_pack_start (GTK_BOX (contents_vbox), prompt, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (prompt), GTK_JUSTIFY_LEFT); - gtk_label_set_line_wrap (GTK_LABEL (prompt), TRUE); - - separator_line = gtk_hseparator_new (); - gtk_widget_show (separator_line); - gtk_box_pack_start (GTK_BOX (contents_vbox), separator_line, TRUE, TRUE, 8); - - hbox_to_center_menus = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox_to_center_menus); - gtk_box_pack_start (GTK_BOX (contents_vbox), hbox_to_center_menus, TRUE, TRUE, 0); - - menus_vbox = gtk_vbox_new (FALSE, 4); - gtk_widget_show (menus_vbox); - gtk_box_pack_start (GTK_BOX (hbox_to_center_menus), menus_vbox, TRUE, FALSE, 0); - - for (index = 0; index < MENU_COUNT; ++index) - { - option_menus[index] = create_attributes_option_menu (index); - gtk_box_pack_start (GTK_BOX (menus_vbox), GTK_WIDGET (option_menus[index]), FALSE, FALSE, 0); - } - - synch_menus_with_preference (NULL); - - nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ICON_CAPTIONS, - synch_menus_with_preference, - NULL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (fm_icon_text_window_delete_event_callback), - NULL); - - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (fm_icon_text_window_destroy_callback), - NULL); - - return window; -} - -static gboolean -is_in_chosen_values (int value) -{ - int i; - - for (i = 0; i < MENU_COUNT; ++i) { - if (value == get_attribute_index_from_option_menu (option_menus[i])) { - return TRUE; - } - } - - return FALSE; -} - -static void -ensure_unique_attributes (int chosen_menu) -{ - int i; - int chosen_value; - int new_value; - - chosen_value = get_attribute_index_from_option_menu (option_menus[chosen_menu]); - - /* allow the "none" value to be chosen multiple times */ - if (!eel_strcmp (attribute_names[chosen_value], "none")) { - return; - } - - for (i = 0; i < MENU_COUNT; ++i) { - if (i == chosen_menu) { - continue; - } - - if (chosen_value == get_attribute_index_from_option_menu (option_menus[i])) { - /* Another item already had this value; change that other item */ - for (new_value = 0; is_in_chosen_values (new_value); ++new_value) { - } - - gtk_option_menu_set_history (option_menus[i], new_value); - return; - } - } -} - -static gboolean -fm_icon_text_window_delete_event_callback (GtkWidget *widget, - GdkEvent *event, - gpointer user_data) -{ - /* Hide but don't destroy */ - gtk_widget_hide(widget); - return TRUE; -} - -static void -fm_icon_text_window_destroy_callback (GtkObject *object, - gpointer user_data) -{ - nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_ICON_CAPTIONS, - synch_menus_with_preference, - NULL); -} - -/** - * fm_icon_text_window_get_or_create: - * - * Get the icon text window. The first call will create the window; subsequent - * calls will return the same window. - * - * Return value: The GtkWindow with the UI for controlling which text appears - * beneath icons. - * - **/ -GtkWindow * -fm_icon_text_window_get_or_create (void) -{ - static GtkWidget *icon_text_window = NULL; - - if (icon_text_window == NULL) { - icon_text_window = create_icon_text_window (); - } - - return GTK_WINDOW (icon_text_window); -} - -/* fm_get_text_attribute_names_preference: - * - * Get the preference for which caption text should appear - * beneath icons. This function validates the raw preference - * and returns a default value if the raw preference is - * nonsensical. - */ -char * -fm_get_text_attribute_names_preference (void) -{ - static const char *auto_preferences_value; - static char *last_checked_value; - static gboolean auto_preferences_value_is_registered; - static char *captions_as_string; - - /* Register auto-storage value the first time it's asked for */ - if (!auto_preferences_value_is_registered) { - nautilus_preferences_add_auto_string (NAUTILUS_PREFERENCES_ICON_CAPTIONS, - &auto_preferences_value); - auto_preferences_value_is_registered = TRUE; - } - - /* Validate preferences value the first time we see it */ - if (last_checked_value == NULL || strcmp (last_checked_value, auto_preferences_value) != 0) { - if (attribute_names_string_is_good (auto_preferences_value)) { - g_free (captions_as_string); - captions_as_string = g_strdup (auto_preferences_value); - } - - g_free (last_checked_value); - last_checked_value = g_strdup (auto_preferences_value); - } - - /* If the preferences value was bad or nonexistent, use default value */ - if (captions_as_string == NULL) { - captions_as_string = g_strdup (DEFAULT_ATTRIBUTE_NAMES); - } - - return g_strdup (captions_as_string); -} diff --git a/src/file-manager/fm-icon-text-window.h b/src/file-manager/fm-icon-text-window.h deleted file mode 100644 index ad8acebcb..000000000 --- a/src/file-manager/fm-icon-text-window.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* fm-icon-text-window.h - interface for window that lets user modify - displayed icon text. - - Copyright (C) 2000 Eazel, Inc. - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Authors: John Sullivan <sullivan@eazel.com> -*/ - -#ifndef FM_ICON_TEXT_WINDOW_H -#define FM_ICON_TEXT_WINDOW_H - -#include <gtk/gtkwindow.h> - -/* Interface for creating the window. */ -GtkWindow *fm_icon_text_window_get_or_create (void); - -/* Cover for getting the attribute names preference. - * This is really not part of icon text window, but putting it here - * prevents us from having to abstract what attribute names are legal. - */ -char *fm_get_text_attribute_names_preference (void); - -#endif /* FM_ICON_TEXT_WINDOW_H */ diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c index 11132bb0a..8079a43c7 100644 --- a/src/file-manager/fm-icon-view.c +++ b/src/file-manager/fm-icon-view.c @@ -27,9 +27,13 @@ #include "fm-desktop-icon-view.h" #include "fm-error-reporting.h" -#include "fm-icon-text-window.h" #include <bonobo/bonobo-ui-util.h> #include <ctype.h> +#include <eel/eel-background.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-extensions.h> +#include <eel/eel-gtk-macros.h> +#include <eel/eel-string.h> #include <errno.h> #include <fcntl.h> #include <gtk/gtkmain.h> @@ -44,22 +48,17 @@ #include <libgnomevfs/gnome-vfs-utils.h> #include <libgnomevfs/gnome-vfs-xfer.h> #include <libnautilus-extensions/nautilus-audio-player.h> -#include <eel/eel-background.h> #include <libnautilus-extensions/nautilus-bonobo-extensions.h> #include <libnautilus-extensions/nautilus-directory-background.h> #include <libnautilus-extensions/nautilus-directory.h> #include <libnautilus-extensions/nautilus-file-utilities.h> #include <libnautilus-extensions/nautilus-font-factory.h> -#include <eel/eel-glib-extensions.h> #include <libnautilus-extensions/nautilus-global-preferences.h> -#include <eel/eel-gtk-extensions.h> -#include <eel/eel-gtk-macros.h> #include <libnautilus-extensions/nautilus-icon-container.h> #include <libnautilus-extensions/nautilus-icon-factory.h> #include <libnautilus-extensions/nautilus-link.h> #include <libnautilus-extensions/nautilus-metadata.h> #include <libnautilus-extensions/nautilus-sound.h> -#include <eel/eel-string.h> #include <libnautilus/nautilus-bonobo-ui.h> #include <libnautilus/nautilus-clipboard.h> #include <locale.h> @@ -73,7 +72,6 @@ /* Paths to use when creating & referring to Bonobo menu items */ #define MENU_PATH_RENAME "/menu/File/File Items Placeholder/Rename" -#define MENU_PATH_CUSTOMIZE_ICON_TEXT "/menu/Edit/Global Edit Items Placeholder/Icon Text" #define MENU_PATH_STRETCH_ICON "/menu/Edit/Edit Items Placeholder/Stretch" #define MENU_PATH_UNSTRETCH_ICONS "/menu/Edit/Edit Items Placeholder/Unstretch" #define MENU_PATH_LAY_OUT "/menu/View/View Items Placeholder/Lay Out" @@ -96,6 +94,8 @@ #define ID_TIGHTER_LAYOUT "Tighter Layout" #define ID_SORT_REVERSED "Reversed Order" +#define ICON_TEXT_ATTRIBUTES_NUM_ITEMS 3 +#define ICON_TEXT_ATTRIBUTES_DEFAULT_TOKENS "size,date_modified,type" typedef struct { NautilusFileSortType sort_type; @@ -459,12 +459,6 @@ handle_radio_item (FMIconView *view, } static void -customize_icon_text_callback (BonoboUIComponent *component, gpointer callback_data, const char *verb) -{ - eel_gtk_window_present (fm_icon_text_window_get_or_create ()); -} - -static void unref_cover (NautilusIconData *data, gpointer callback_data) { nautilus_file_unref (NAUTILUS_FILE (data)); @@ -1078,6 +1072,54 @@ fm_icon_view_get_background_widget (FMDirectoryView *view) return GTK_WIDGET (get_icon_container (FM_ICON_VIEW (view))); } +/* + * Get the preference for which caption text should appear + * beneath icons. + */ +static EelStringList * +fm_icon_view_get_icon_text_attributes_from_preferences (void) +{ + static const EelStringList *attributes; + + if (attributes == NULL) { + nautilus_preferences_add_auto_string_list (NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, + &attributes); + } + + /* A simple check that the attributes list matches the expected length */ + g_return_val_if_fail (eel_string_list_get_length (attributes) == ICON_TEXT_ATTRIBUTES_NUM_ITEMS, + eel_string_list_new_from_tokens (ICON_TEXT_ATTRIBUTES_DEFAULT_TOKENS, ",", TRUE)); + + + /* We don't need to sanity check the attributes list even though it came + * from preferences. + * + * There are 2 ways that the values in the list could be bad. + * + * 1) The user picks "bad" values. "bad" values are those that result in + * there being duplicate attributes in the list. + * + * 2) Value stored in GConf are tampered with. Its possible physically do + * this by pulling the rug underneath GConf and manually editing its + * config files. Its also possible to use a third party GConf key + * editor and store garbage for the keys in question. + * + * Thankfully, the Nautilus preferences machinery deals with both of + * these cases. + * + * In the first case, the preferences dialog widgetry prevents + * duplicate attributes by making "bad" choices insensitive. + * + * In the second case, the preferences getter (and also the auto storage) for + * string_list values are always valid members of the enumeration associated + * with the preference. + * + * So, no more error checking on attributes is needed here and we can return + * a copy of the auto stored value. + */ + return eel_string_list_copy (attributes); +} + /** * fm_icon_view_get_icon_text_attribute_names: * @@ -1092,8 +1134,10 @@ fm_icon_view_get_background_widget (FMDirectoryView *view) static char * fm_icon_view_get_icon_text_attribute_names (FMIconView *view) { - char *all_names, *result, *c; - int pieces_so_far, piece_count; + EelStringList *attributes; + char *result; + int piece_count; + const int pieces_by_level[] = { 0, /* NAUTILUS_ZOOM_LEVEL_SMALLEST */ 0, /* NAUTILUS_ZOOM_LEVEL_SMALLER */ @@ -1105,24 +1149,13 @@ fm_icon_view_get_icon_text_attribute_names (FMIconView *view) }; piece_count = pieces_by_level[fm_icon_view_get_zoom_level (view)]; - - all_names = fm_get_text_attribute_names_preference (); - pieces_so_far = 0; - - for (c = all_names; *c != '\0'; ++c) { - if (pieces_so_far == piece_count) { - break; - } - if (*c == '|') { - ++pieces_so_far; - } - } - - /* Return an initial substring of the full set */ - result = g_strndup (all_names, (c - all_names)); - - g_free (all_names); + attributes = fm_icon_view_get_icon_text_attributes_from_preferences (); + g_return_val_if_fail ((guint)piece_count <= eel_string_list_get_length (attributes), NULL); + + result = eel_string_list_as_string (attributes, "|", piece_count); + eel_string_list_free (attributes); + return result; } @@ -1258,7 +1291,6 @@ fm_icon_view_merge_menus (FMDirectoryView *view) FMIconView *icon_view; BonoboUIVerb verbs [] = { BONOBO_UI_VERB ("Rename", rename_icon_callback), - BONOBO_UI_VERB ("Icon Text", customize_icon_text_callback), BONOBO_UI_VERB ("Stretch", show_stretch_handles_callback), BONOBO_UI_VERB ("Unstretch", unstretch_icons_callback), BONOBO_UI_VERB ("Clean Up", clean_up_callback), diff --git a/src/file-manager/nautilus-icon-view-ui.xml b/src/file-manager/nautilus-icon-view-ui.xml index 4cbe8b0ba..f8fd03d46 100644 --- a/src/file-manager/nautilus-icon-view-ui.xml +++ b/src/file-manager/nautilus-icon-view-ui.xml @@ -3,9 +3,6 @@ <cmd name="Rename" _label="Rename" _tip="Rename selected icon"/> - <cmd name="Icon Text" - _label="Icon Captions..." - _tip="Choose which information appears beneath each icon's name"/> <cmd name="Stretch" _label="Stretch Icon" _tip="Make the selected icon stretchable"/> @@ -50,12 +47,6 @@ </submenu> <submenu name="Edit"> - <placeholder name="Global Edit Items Placeholder"> - <menuitem name="Icon Text" - _label="_Icon Captions..." - verb="Icon Text"/> - </placeholder> - <placeholder name="Edit Items Placeholder"> <menuitem name="Stretch" _label="_Stretch Icon" |