add menu_sort_entries() which sorts all entries in an ObMenu

this function sorts each group of entries that appear together between two
consecutive separators (or ends of the list)
This commit is contained in:
Dana Jansens 2011-01-27 17:30:45 -05:00
parent 7d32190a4c
commit 9f31f80ce8
2 changed files with 79 additions and 1 deletions

View file

@ -385,6 +385,7 @@ ObMenu* menu_new(const gchar *name, const gchar *title,
self->shortcut = parse_shortcut(title, allow_shortcut_selection,
&self->title, &self->shortcut_position,
&self->shortcut_always_show);
self->collate_key = g_utf8_collate_key(self->title, -1);
g_hash_table_replace(menu_hash, self->name, self);
@ -400,6 +401,7 @@ ObMenu* menu_new(const gchar *name, const gchar *title,
self->more_menu = g_slice_new0(ObMenu);
self->more_menu->name = _("More...");
self->more_menu->title = _("More...");
self->more_menu->collate_key = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
self->more_menu->data = data;
self->more_menu->shortcut = g_unichar_tolower(g_utf8_get_char("M"));
@ -426,6 +428,7 @@ static void menu_destroy_hash_value(ObMenu *self)
menu_clear_entries(self);
g_free(self->name);
g_free(self->title);
g_free(self->collate_key);
g_free(self->execute);
g_slice_free(ObMenu, self->more_menu);
@ -541,6 +544,7 @@ void menu_entry_unref(ObMenuEntry *self)
case OB_MENU_ENTRY_TYPE_NORMAL:
RrImageUnref(self->data.normal.icon);
g_free(self->data.normal.label);
g_free(self->data.normal.collate_key);
while (self->data.normal.actions) {
actions_act_unref(self->data.normal.actions->data);
self->data.normal.actions =
@ -714,10 +718,13 @@ void menu_entry_set_label(ObMenuEntry *self, const gchar *label,
break;
case OB_MENU_ENTRY_TYPE_NORMAL:
g_free(self->data.normal.label);
g_free(self->data.normal.collate_key);
self->data.normal.shortcut =
parse_shortcut(label, allow_shortcut, &self->data.normal.label,
&self->data.normal.shortcut_position,
&self->data.normal.shortcut_always_show);
self->data.normal.collate_key =
g_utf8_collate_key(self->data.normal.label, -1);
break;
default:
g_assert_not_reached();
@ -728,3 +735,69 @@ void menu_show_all_shortcuts(ObMenu *self, gboolean show)
{
self->show_all_shortcuts = show;
}
static int sort_func(const void *a, const void *b) {
const ObMenuEntry *e[2] = {*(ObMenuEntry**)a, *(ObMenuEntry**)b};
const gchar *k[2];
gint i;
for (i = 0; i < 2; ++i) {
if (e[i]->type == OB_MENU_ENTRY_TYPE_NORMAL)
k[i] = e[i]->data.normal.collate_key;
else {
g_assert(e[i]->type == OB_MENU_ENTRY_TYPE_SUBMENU);
if (e[i]->data.submenu.submenu)
k[i] = e[i]->data.submenu.submenu->collate_key;
else
return -1; /* arbitrary really.. the submenu doesn't exist. */
}
}
return strcmp(k[0], k[1]);
}
/*!
@param start The first entry in the range to sort.
@param end The last entry in the range to sort.
*/
static void sort_range(ObMenu *self, GList *start, GList *end, guint len)
{
ObMenuEntry **ar;
GList *it;
guint i;
if (!len) return;
ar = g_slice_alloc(sizeof(ObMenuEntry*) * len);
for (i = 0, it = start; it != g_list_next(end); ++i, it = g_list_next(it))
ar[i] = it->data;
qsort(ar, len, sizeof(ObMenuEntry*), sort_func);
for (i = 0, it = start; it != g_list_next(end); ++i, it = g_list_next(it))
it->data = ar[i];
g_slice_free1(sizeof(ObMenuEntry*) * len, ar);
}
void menu_sort_entries(ObMenu *self)
{
GList *it, *start, *end, *last;
guint len;
/* need the submenus to know their labels for sorting */
menu_find_submenus(self);
start = self->entries;
len = 0;
for (it = self->entries; it; it = g_list_next(it)) {
ObMenuEntry *e = it->data;
if (e->type == OB_MENU_ENTRY_TYPE_SEPARATOR) {
end = g_list_previous(it);
sort_range(self, start, end, len);
it = g_list_next(it); /* skip over the separator */
start = it;
len = 0;
}
else
len += 1;
last = it;
}
sort_range(self, start, last, len);
}

View file

@ -59,6 +59,7 @@ struct _ObMenu
gchar *name;
/* Displayed title */
gchar *title;
gchar *collate_key;
/*! The shortcut key that would be used to activate this menu if it was
displayed as a submenu */
gunichar shortcut;
@ -108,6 +109,7 @@ struct _ObNormalMenuEntry {
gint icon_alpha;
gchar *label;
gchar *collate_key;
/*! The shortcut key that would be used to activate this menu entry */
gunichar shortcut;
/*! The shortcut's position in the string */
@ -211,7 +213,10 @@ ObMenuEntry* menu_add_normal(ObMenu *menu, gint id, const gchar *label,
ObMenuEntry* menu_add_submenu(ObMenu *menu, gint id, const gchar *submenu);
ObMenuEntry* menu_add_separator(ObMenu *menu, gint id, const gchar *label);
void menu_clear_entries(ObMenu *menu);
/*! This sorts groups of menu entries between consecutive separators */
void menu_sort_entries(ObMenu *self);
void menu_clear_entries(ObMenu *self);
void menu_entry_remove(ObMenuEntry *self);
void menu_entry_set_label(ObMenuEntry *self, const gchar *label,