diff options
-rw-r--r-- | widgets/misc/ChangeLog | 28 | ||||
-rw-r--r-- | widgets/misc/e-source-selector.c | 196 |
2 files changed, 202 insertions, 22 deletions
diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog index bf49e8c238..a98b1975d6 100644 --- a/widgets/misc/ChangeLog +++ b/widgets/misc/ChangeLog @@ -1,3 +1,31 @@ +2004-01-19 JP Rosevear <jpr@ximian.com> + + * e-source-selector.c (create_rebuild_data): create the data + structure for rebuilding the model + (free_rebuild_data): free it + (rebuild_existing_cb): check for the sources that are still + existing or deleted + (rebuild_model): do incremental updates + (selection_func): if the last thing we did was toggle, we don't + actually want to highlight and if the source is not checked, check + it + (cell_toggled_callback): indicate that a toggle just occurred + (init): initial toggled last to false + (e_source_selector_set_primary_selection): set some preconditions + + Fixes #51787 + +2004-01-19 JP Rosevear <jpr@ximian.com> + + * e-source-selector.c (cell_toggled_callback): indicate that a toggle just occurred + +2004-01-19 JP Rosevear <jpr@ximian.com> + + * e-source-selector.c + + (selector_button_press_event): when right clicking, make sure the + calendar is highlighted and that groups can't be right clicked on + 2004-01-14 Rodney Dawes <dobey@ximian.com> * e-expander.[ch]: Fix remaining usages of GTK_*EXPANDER* defines diff --git a/widgets/misc/e-source-selector.c b/widgets/misc/e-source-selector.c index 443129c6d8..68ae062682 100644 --- a/widgets/misc/e-source-selector.c +++ b/widgets/misc/e-source-selector.c @@ -29,12 +29,12 @@ #include <gal/util/e-util.h> +#include <gtk/gtkmenu.h> #include <gtk/gtktreeselection.h> #include <gtk/gtktreestore.h> #include <gtk/gtkcellrenderertoggle.h> #include <gtk/gtkcellrenderertext.h> - #define PARENT_TYPE gtk_tree_view_get_type () static GtkTreeViewClass *parent_class = NULL; @@ -48,9 +48,19 @@ struct _ESourceSelectorPrivate { int rebuild_model_idle_id; + gboolean toggled_last; + gboolean checkboxes_shown; }; +typedef struct { + ESourceSelector *selector; + + GHashTable *remaining_uids; + GSList *deleted_uids; + + gboolean selection_changed; +} ESourceSelectorRebuildData; enum { SELECTION_CHANGED, @@ -70,6 +80,35 @@ create_selected_sources_hash (void) (GDestroyNotify) g_object_unref, NULL); } +static ESourceSelectorRebuildData * +create_rebuild_data (ESourceSelector *selector) +{ + ESourceSelectorRebuildData *rebuild_data; + + rebuild_data = g_new0 (ESourceSelectorRebuildData, 1); + + rebuild_data->selector = selector; + rebuild_data->remaining_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) gtk_tree_row_reference_free); + rebuild_data->deleted_uids = NULL; + + return rebuild_data; +} + + +static void +free_rebuild_data (ESourceSelectorRebuildData *rebuild_data) +{ + GSList *p; + + g_hash_table_destroy (rebuild_data->remaining_uids); + for (p = rebuild_data->deleted_uids; p; p = p->next) + gtk_tree_row_reference_free (p->data); + g_slist_free (rebuild_data->deleted_uids); + + g_free (rebuild_data); +} + static gboolean source_is_selected (ESourceSelector *selector, ESource *source) @@ -128,50 +167,121 @@ find_source_iter (ESourceSelector *selector, ESource *source, GtkTreeIter *sourc } /* Setting up the model. */ +static gboolean +rebuild_existing_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + ESourceSelectorRebuildData *rebuild_data = data; + void *node; + const char *uid; + + gtk_tree_model_get (model, iter, 0, &node, -1); + + if (E_IS_SOURCE_GROUP (node)) { + uid = e_source_group_peek_uid (E_SOURCE_GROUP (node)); + + if (e_source_list_peek_group_by_uid (rebuild_data->selector->priv->list, uid)) { + g_hash_table_insert (rebuild_data->remaining_uids, g_strdup (uid), + gtk_tree_row_reference_new (model, path)); + } else { + rebuild_data->deleted_uids = g_slist_prepend (rebuild_data->deleted_uids, + gtk_tree_row_reference_new (model, path)); + } + + return FALSE; + } + uid = e_source_peek_uid (E_SOURCE (node)); + if (e_source_list_peek_source_by_uid (rebuild_data->selector->priv->list, uid)) { + g_hash_table_insert (rebuild_data->remaining_uids, g_strdup (uid), + gtk_tree_row_reference_new (model, path)); + } else { + rebuild_data->deleted_uids = g_slist_prepend (rebuild_data->deleted_uids, + gtk_tree_row_reference_new (model, path)); + + if (g_hash_table_remove (rebuild_data->selector->priv->selected_sources, node)) + rebuild_data->selection_changed = TRUE; + } + + return FALSE; +} + static void rebuild_model (ESourceSelector *selector) { + ESourceSelectorRebuildData *rebuild_data; GtkTreeStore *tree_store; GtkTreeIter iter; GSList *groups, *p; - GHashTable *new_selected_sources; - - new_selected_sources = create_selected_sources_hash (); tree_store = selector->priv->tree_store; - gtk_tree_store_clear (GTK_TREE_STORE (tree_store)); + rebuild_data = create_rebuild_data (selector); + + /* Remove any delete sources or groups */ + gtk_tree_model_foreach (GTK_TREE_MODEL (tree_store), rebuild_existing_cb, rebuild_data); + for (p = rebuild_data->deleted_uids; p; p = p->next) { + GtkTreeRowReference *row_ref = p->data; + GtkTreePath *path; + + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &iter, path); + gtk_tree_store_remove (tree_store, &iter); + + gtk_tree_path_free (path); + } + + /* Add new sources/groups or call row_changed in case they were renamed */ groups = e_source_list_peek_groups (selector->priv->list); for (p = groups; p != NULL; p = p->next) { ESourceGroup *group = E_SOURCE_GROUP (p->data); GSList *sources, *q; + GtkTreeRowReference *row_ref; + + row_ref = g_hash_table_lookup (rebuild_data->remaining_uids, e_source_group_peek_uid (group)); + if (!row_ref) { + gtk_tree_store_append (GTK_TREE_STORE (tree_store), &iter, NULL); + gtk_tree_store_set (GTK_TREE_STORE (tree_store), &iter, 0, group, -1); + } else { + GtkTreePath *path; + + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &iter, path); - gtk_tree_store_append (GTK_TREE_STORE (tree_store), &iter, NULL); - gtk_tree_store_set (GTK_TREE_STORE (tree_store), &iter, 0, group, -1); + gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, &iter); + gtk_tree_path_free (path); + } + sources = e_source_group_peek_sources (group); for (q = sources; q != NULL; q = q->next) { ESource *source = E_SOURCE (q->data); GtkTreeIter child_iter; - gtk_tree_store_append (GTK_TREE_STORE (tree_store), &child_iter, &iter); - gtk_tree_store_set (GTK_TREE_STORE (tree_store), &child_iter, 0, source, -1); + row_ref = g_hash_table_lookup (rebuild_data->remaining_uids, e_source_peek_uid (source)); + if (!row_ref) { + gtk_tree_store_append (GTK_TREE_STORE (tree_store), &child_iter, &iter); + gtk_tree_store_set (GTK_TREE_STORE (tree_store), &child_iter, 0, source, -1); - if (g_hash_table_lookup (selector->priv->selected_sources, source) != NULL) { - g_hash_table_insert (new_selected_sources, source, source); - g_object_ref (source); + } else { + GtkTreePath *path; + + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_store), &child_iter, path); + + gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, &child_iter); + + gtk_tree_path_free (path); } } } - /* Since new_selected_sources is a subset of selected_sources, we can tell whether the overall - selection has changed just by comparing the sizes of the hash tables. */ - if (g_hash_table_size (selector->priv->selected_sources) != g_hash_table_size (new_selected_sources)) + if (rebuild_data->selection_changed) g_signal_emit (selector, signals[SELECTION_CHANGED], 0); - g_hash_table_destroy (selector->priv->selected_sources); - selector->priv->selected_sources = new_selected_sources; + if (!e_source_selector_peek_primary_selection (selector)) + e_source_selector_set_primary_selection (selector, e_source_list_peek_source_any (selector->priv->list)); + + free_rebuild_data (rebuild_data); } static int @@ -286,14 +396,28 @@ selection_func (GtkTreeSelection *selection, GtkTreeIter iter; void *data; + if (selector->priv->toggled_last) { + selector->priv->toggled_last = FALSE; + + return FALSE; + } + + if (path_currently_selected) + return TRUE; + if (! gtk_tree_model_get_iter (model, &iter, path)) return FALSE; gtk_tree_model_get (model, &iter, 0, &data, -1); if (E_IS_SOURCE_GROUP (data)) return FALSE; - else + + if (source_is_selected (selector, E_SOURCE (data))) return TRUE; + + e_source_selector_select_source (selector, E_SOURCE (data)); + + return TRUE; } @@ -327,6 +451,8 @@ cell_toggled_callback (GtkCellRendererToggle *renderer, else select_source (selector, source); + selector->priv->toggled_last = TRUE; + gtk_tree_model_row_changed (model, path, &iter); g_signal_emit (selector, signals[SELECTION_CHANGED], 0); @@ -343,12 +469,33 @@ selection_changed_callback (GtkTreeSelection *selection, static gboolean selector_button_press_event (GtkWidget *widget, GdkEventButton *event, ESourceSelector *selector) { + ESourceSelectorPrivate *priv = selector->priv; GtkWidget *menu; - + GtkTreePath *path; + ESource *source = NULL; + /* only process right-clicks */ - if (event->button != 3) + if (event->button != 3 || event->type != GDK_BUTTON_PRESS) return FALSE; + /* Get the source/group */ + if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), event->x, event->y, &path, NULL, NULL, NULL)) { + GtkTreeIter iter; + gpointer data; + + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->tree_store), &iter, path)) { + gtk_tree_model_get (GTK_TREE_MODEL (priv->tree_store), &iter, 0, &data, -1); + + if (E_IS_SOURCE_GROUP (data)) + return FALSE; + + source = E_SOURCE (data); + } + } + + if (source) + e_source_selector_set_primary_selection (selector, source); + /* create the menu */ menu = gtk_menu_new (); g_signal_emit (G_OBJECT (selector), signals[FILL_POPUP_MENU], 0, GTK_MENU (menu)); @@ -453,6 +600,7 @@ init (ESourceSelector *selector) g_signal_connect (G_OBJECT (selector), "button_press_event", G_CALLBACK (selector_button_press_event), selector); + priv->toggled_last = FALSE; priv->checkboxes_shown = TRUE; priv->selected_sources = create_selected_sources_hash (); @@ -729,11 +877,15 @@ e_source_selector_peek_primary_selection (ESourceSelector *selector) * Set the primary selected source. **/ void -e_source_selector_set_primary_selection (ESourceSelector *selector, - ESource *source) +e_source_selector_set_primary_selection (ESourceSelector *selector, ESource *source) { GtkTreeIter source_iter; + g_return_if_fail (selector != NULL); + g_return_if_fail (E_IS_SOURCE_SELECTOR (selector)); + g_return_if_fail (source != NULL); + g_return_if_fail (E_IS_SOURCE (source)); + if (find_source_iter (selector, source, &source_iter)) { GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector)); gtk_tree_selection_select_iter (selection, &source_iter); |