1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2009, 2010, 2012, 2015 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 This module provides a widget, PsppireSelector derived from
22 It contains a GtkImage (to indicate the arrow), and is used for selecting objects from a
23 GtkTreeView and putting them into a destination widget (often
24 another GtkTreeView). Typically this is used in psppire for
25 selecting variables, thus:
28 +----------------------------------------------------------+
30 | Source Widget Dest Widget |
31 | +----------------+ +----------------+ |
32 | | Variable0 | | Variable2 | |
47 | +----------------+ +----------------+ |
49 +----------------------------------------------------------+
51 The Source Widget is always a GtkTreeView. The Dest Widget may be a
52 GtkTreeView or a GtkEntry (other destination widgets may be
53 supported in the future).
55 Widgets may be source to more than one PsppireSelector.
61 #include "psppire-dictview.h"
62 #include "psppire-dict.h"
63 #include "psppire-select-dest.h"
64 #include "psppire-means-layer.h"
68 #include "psppire-selector.h"
70 static void psppire_selector_class_init (PsppireSelectorClass *class);
71 static void psppire_selector_init (PsppireSelector *selector);
74 static void set_direction (PsppireSelector *, enum psppire_selector_dir);
77 enum {SELECTED, /* Emitted when an item is inserted into dest */
78 DE_SELECTED, /* Emitted when an item is removed from dest */
81 static guint signals [n_SIGNALS];
83 /* Callback for when an item disappears from the source list.
84 By implication, this means that the item has been inserted into the
88 on_row_deleted (PsppireSelector *selector)
90 g_signal_emit (selector, signals [SELECTED], 0);
93 /* Callback for when a new item appears in the source list.
94 By implication, this means that an item has been deleted from the
98 on_row_inserted (PsppireSelector *selector)
100 g_signal_emit (selector, signals [DE_SELECTED], 0);
105 psppire_selector_get_type (void)
107 static GType psppire_selector_type = 0;
109 if (!psppire_selector_type)
111 static const GTypeInfo psppire_selector_info =
113 sizeof (PsppireSelectorClass),
114 (GBaseInitFunc) NULL,
115 (GBaseFinalizeFunc) NULL,
116 (GClassInitFunc)psppire_selector_class_init,
117 (GClassFinalizeFunc) NULL,
119 sizeof (PsppireSelector),
121 (GInstanceInitFunc) psppire_selector_init,
124 psppire_selector_type =
125 g_type_register_static (GTK_TYPE_BUTTON, "PsppireSelector",
126 &psppire_selector_info, 0);
129 return psppire_selector_type;
132 static GObjectClass * parent_class = NULL;
137 dump_hash_entry (gpointer key, gpointer value, gpointer obj)
140 g_print ("Source %p; ", key);
142 for (item = g_list_first (value);
144 item = g_list_next (item))
146 g_print ("%p(%p) ", item->data, item);
151 /* This function is for debugging only */
153 psppire_selector_show_map (PsppireSelector *obj)
155 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
157 g_print ("%s %p\n", __FUNCTION__, obj);
158 g_hash_table_foreach (class->source_hash, dump_hash_entry, obj);
164 psppire_selector_dispose (GObject *obj)
166 PsppireSelector *sel = PSPPIRE_SELECTOR (obj);
167 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
170 if (sel->dispose_has_run)
173 /* Make sure dispose does not run twice. */
174 sel->dispose_has_run = TRUE;
176 /* Remove ourself from the source map. If we are the only entry for this source
177 widget, that will result in an empty list for the source. In that case, we
178 remove the entire entry too. */
179 if ((list = g_hash_table_lookup (class->source_hash, sel->source)))
181 GList *newlist = g_list_remove_link (list, sel->source_litem);
182 g_list_free (sel->source_litem);
184 g_hash_table_remove (class->source_hash, sel->source);
186 g_hash_table_replace (class->source_hash, sel->source, newlist);
188 sel->source_litem = NULL;
191 g_object_unref (sel->dest);
192 g_object_unref (sel->source);
194 /* Chain up to the parent class */
195 G_OBJECT_CLASS (parent_class)->dispose (obj);
210 static void on_click (GtkButton *b);
211 static void on_realize (GtkWidget *selector);
215 psppire_selector_set_property (GObject *object,
220 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
224 case PROP_ORIENTATION:
225 selector->orientation = g_value_get_enum (value);
226 set_direction (selector, selector->direction);
229 selector->primary_requested = TRUE;
230 psppire_selector_update_subjects (selector);
232 case PROP_SOURCE_WIDGET:
233 selector->source = g_value_dup_object (value);
234 psppire_selector_update_subjects (selector);
236 case PROP_DEST_WIDGET:
237 selector->dest = g_value_dup_object (value);
238 psppire_selector_update_subjects (selector);
241 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248 psppire_selector_get_property (GObject *object,
253 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
257 case PROP_ORIENTATION:
258 g_value_set_enum (value, selector->orientation);
260 case PROP_SOURCE_WIDGET:
261 g_value_take_object (value, selector->source);
263 case PROP_DEST_WIDGET:
264 g_value_take_object (value, selector->dest);
267 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273 psppire_selector_class_init (PsppireSelectorClass *class)
275 GObjectClass *object_class = G_OBJECT_CLASS (class);
276 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
277 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
278 GParamSpec *orientation_spec =
279 g_param_spec_enum ("orientation",
281 "Where the selector is relative to its subjects",
282 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
283 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
284 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
287 /* Meaningfull only if more than one selector shares this selectors source */
288 GParamSpec *primary_spec =
289 g_param_spec_boolean ("primary",
291 "Whether this selector should be the primary selector for the source",
295 GParamSpec *source_widget_spec =
296 g_param_spec_object ("source-widget",
298 "The widget to be used as the source for this selector",
302 GParamSpec *dest_widget_spec =
303 g_param_spec_object ("dest-widget",
304 "Destination Widget",
305 "The widget to be used as the destination for this selector",
310 button_class->clicked = on_click;
311 widget_class->realize = on_realize;
314 object_class->set_property = psppire_selector_set_property;
315 object_class->get_property = psppire_selector_get_property;
317 g_object_class_install_property (object_class,
321 g_object_class_install_property (object_class,
325 g_object_class_install_property (object_class,
329 g_object_class_install_property (object_class,
333 parent_class = g_type_class_peek_parent (class);
336 g_signal_new ("selected",
337 G_TYPE_FROM_CLASS (class),
341 g_cclosure_marshal_VOID__VOID,
345 signals [DE_SELECTED] =
346 g_signal_new ("de-selected",
347 G_TYPE_FROM_CLASS (class),
351 g_cclosure_marshal_VOID__VOID,
355 object_class->dispose = psppire_selector_dispose;
357 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
358 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
362 /* Callback for when the source treeview is activated (double clicked) */
364 on_row_activate (GtkTreeView *tree_view,
366 GtkTreeViewColumn *column,
369 on_click (GTK_BUTTON (data));
372 /* Callback for when the source selection changes */
374 on_source_select (GtkTreeSelection *treeselection, gpointer data)
376 PsppireSelector *selector = data;
378 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
380 if (selector->allow_selection)
382 gtk_widget_set_sensitive (GTK_WIDGET (selector),
383 selector->allow_selection (selector->source, selector->dest));
385 else if (GTK_IS_ENTRY (selector->dest))
387 gtk_widget_set_sensitive (GTK_WIDGET (selector),
388 gtk_tree_selection_count_selected_rows
389 (treeselection) <= 1);
395 on_realize (GtkWidget *w)
397 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
398 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
399 GtkTreeSelection* selection ;
401 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
403 if (GTK_WIDGET_CLASS (parent_class)->realize)
404 GTK_WIDGET_CLASS (parent_class)->realize (w);
409 if (g_list_first (list)->data == selector)
411 if (selector->row_activate_id)
412 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
414 selector->row_activate_id =
415 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
418 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
420 if (selector->source_select_id)
421 g_signal_handler_disconnect (selection, selector->source_select_id);
423 selector->source_select_id =
424 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
429 psppire_selector_init (PsppireSelector *selector)
431 selector->primary_requested = FALSE;
432 selector->select_user_data = NULL;
433 selector->select_items = NULL;
434 selector->allow_selection = NULL;
435 selector->filter = NULL;
437 selector->arrow = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
439 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
441 gtk_widget_show (selector->arrow);
443 selector->selecting = FALSE;
445 selector->source = NULL;
446 selector->dest = NULL;
447 selector->dispose_has_run = FALSE;
450 selector->row_activate_id = 0;
451 selector->source_select_id = 0;
453 selector->source_litem = NULL;
458 psppire_selector_new (void)
460 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
465 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
467 selector->direction = d;
469 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
471 if (d == PSPPIRE_SELECTOR_SOURCE_TO_DEST)
473 switch (selector->orientation)
475 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
476 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
478 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
479 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
481 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
482 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
484 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
485 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
488 g_assert_not_reached ();
494 switch (selector->orientation)
496 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
497 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
499 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
500 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
502 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
503 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
505 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
506 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
509 g_assert_not_reached ();
515 /* Callback for when the destination treeview selection changes */
517 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
519 PsppireSelector *selector = data;
521 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
523 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
527 /* Callback for source deselection, when the dest is GtkEntry */
529 de_select_selection_entry (PsppireSelector *selector)
531 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
535 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
537 /* Callback for source deselection, when the dest is PsppireMeansLayer */
539 de_select_selection_means_layer (PsppireSelector *selector)
541 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
542 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
543 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
545 GtkTreeModel *model = psppire_means_layer_get_model (ml);
547 g_return_if_fail (selector->select_items);
549 de_select_tree_model (selection, model);
552 /* Callback for source deselection, when the dest is GtkTreeView */
554 de_select_selection_tree_view (PsppireSelector *selector)
556 GtkTreeSelection* selection =
557 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->dest));
559 GtkTreeModel *model =
560 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
562 g_return_if_fail (selector->select_items);
564 de_select_tree_model (selection, model);
568 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
572 GList *selected_rows =
573 gtk_tree_selection_get_selected_rows (selection, NULL);
575 /* Convert paths to RowRefs */
576 for (item = g_list_first (selected_rows);
578 item = g_list_next (item))
580 GtkTreeRowReference* rowref;
581 GtkTreePath *path = item->data;
583 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
585 item->data = rowref ;
586 gtk_tree_path_free (path);
589 /* Remove each selected row from the dest widget */
590 for (item = g_list_first (selected_rows);
592 item = g_list_next (item))
595 GtkTreeRowReference *rr = item->data;
597 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
599 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
601 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
603 gtk_tree_path_free (path);
606 /* Delete list of RowRefs and its contents */
607 g_list_foreach (selected_rows, (GFunc) gtk_tree_row_reference_free, NULL);
608 g_list_free (selected_rows);
612 /* Callback which causes the filter to be refiltered.
613 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
617 refilter (PsppireSelector *selector)
619 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
620 if (GTK_IS_TREE_MODEL_FILTER (model))
621 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
625 /* Removes something from the DEST widget */
627 de_select_selection (PsppireSelector *selector)
629 selector->selecting = TRUE;
631 if (GTK_IS_TREE_VIEW (selector->dest))
632 de_select_selection_tree_view (selector);
634 else if (GTK_IS_ENTRY (selector->dest))
635 de_select_selection_entry (selector);
637 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
638 de_select_selection_means_layer (selector);
641 g_assert_not_reached ();
643 selector->selecting = FALSE;
647 g_signal_emit (selector, signals [DE_SELECTED], 0);
651 /* Puts something into the DEST widget */
653 select_selection (PsppireSelector *selector)
656 GtkTreeSelection* selection =
657 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
659 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
661 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
663 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
665 g_return_if_fail (selector->select_items);
667 if (selector->allow_selection &&
668 ! selector->allow_selection (selector->source, selector->dest))
671 selector->selecting = TRUE;
673 for (item = g_list_first (selected_rows);
675 item = g_list_next (item))
677 GtkTreeIter child_iter;
679 GtkTreePath *path = item->data;
681 g_return_if_fail (model);
683 gtk_tree_model_get_iter (model, &iter, path);
685 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
687 selector->select_items (child_iter,
690 selector->select_user_data
694 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
695 g_list_free (selected_rows);
699 g_signal_emit (selector, signals [SELECTED], 0);
701 selector->selecting = FALSE;
704 /* Callback for when the selector button is clicked,
705 or other event which causes the selector's action to occur.
708 on_click (GtkButton *b)
710 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
712 switch (selector->direction)
714 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
715 select_selection (selector);
717 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
718 de_select_selection (selector);
721 g_assert_not_reached ();
725 if (GTK_BUTTON_CLASS (parent_class)->clicked)
726 GTK_BUTTON_CLASS (parent_class)->clicked (b);
730 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
732 gboolean result = FALSE;
733 GtkTreeIter source_iter;
734 GtkTreeModel *source_model;
737 if (GTK_IS_TREE_MODEL_FILTER (model))
739 source_model = gtk_tree_model_filter_get_model
740 (GTK_TREE_MODEL_FILTER (model));
742 gtk_tree_model_filter_convert_iter_to_child_iter
743 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
747 source_model = model;
751 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
753 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
756 g_value_unset (&value);
763 /* Visibility function for items in the SOURCE widget.
764 Returns TRUE iff *all* the selectors for which SOURCE is associated
767 is_source_item_visible (GtkTreeModel *childmodel,
768 GtkTreeIter *iter, gpointer data)
770 PsppireSelector *selector = data;
771 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
775 list = g_hash_table_lookup (class->source_hash, selector->source);
779 PsppireSelector *selector = list->data;
781 if (selector->filter && selector->filter (childmodel, iter, selector))
791 /* set the source widget to SOURCE */
793 set_tree_view_source (PsppireSelector *selector)
797 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
799 if (! (list = g_hash_table_lookup (class->source_hash, selector->source)))
801 /* Base case: This widget is currently not the source of
802 any selector. Create a hash entry and make this selector
803 the first selector in the list */
805 list = g_list_append (list, selector);
806 g_hash_table_insert (class->source_hash, selector->source, list);
808 /* Save the list item so that it can be removed later */
809 selector->source_litem = list;
812 { /* Append this selector to the list and push the <source,list>
813 pair onto the hash table */
815 if (NULL == g_list_find (list, selector))
817 if (selector->primary_requested)
819 list = g_list_prepend (list, selector);
820 selector->source_litem = list;
824 list = g_list_append (list, selector);
825 selector->source_litem = g_list_last (list);
827 g_hash_table_replace (class->source_hash, selector->source, list);
834 /* This function is a callback which occurs when the
835 SOURCE's model has changed */
840 PsppireSelector *selector
843 GtkTreeModel *model = gtk_tree_view_get_model (source);
845 g_assert (source == GTK_TREE_VIEW (selector->source));
847 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
852 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
854 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
856 gtk_tree_view_set_model (source, new_model);
858 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
859 is_source_item_visible,
863 g_signal_connect_swapped (new_model,
865 G_CALLBACK (on_row_deleted), selector);
867 g_signal_connect_swapped (new_model,
869 G_CALLBACK (on_row_inserted), selector);
871 g_object_unref (new_model);
878 Callback for when the destination treeview's data changes
881 on_dest_data_change (GtkTreeModel *tree_model,
886 PsppireSelector *selector = user_data;
888 if (selector->selecting) return;
895 on_dest_data_delete (GtkTreeModel *tree_model,
899 PsppireSelector *selector = user_data;
901 if (selector->selecting) return;
908 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
910 g_signal_handlers_disconnect_by_data (sel, selector);
914 on_dest_model_changed (PsppireSelector *selector)
916 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
921 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
924 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
927 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
929 if (selector->selecting) return;
934 /* Set the destination widget to DEST */
936 set_tree_view_dest (PsppireSelector *selector,
939 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
942 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
944 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
947 on_dest_model_changed (selector);
948 g_signal_connect_swapped (dest, "notify::model",
949 G_CALLBACK (on_dest_model_changed), selector);
953 set_layer_dest (PsppireSelector *selector,
954 PsppireMeansLayer *dest)
956 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
958 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
961 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
966 /* Callback for when the DEST GtkEntry is selected (clicked) */
968 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
970 PsppireSelector * selector = data;
972 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
973 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
980 /* Set DEST to be the destination GtkEntry widget */
982 set_entry_dest (PsppireSelector *selector,
985 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
988 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
991 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
994 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
1001 set_default_filter (PsppireSelector *selector)
1003 if (selector->filter == NULL)
1005 if (GTK_IS_TREE_VIEW (selector->dest))
1006 selector->filter = is_item_in_dest;
1012 psppire_selector_update_subjects (PsppireSelector *selector)
1014 if (NULL == selector->dest)
1017 set_default_filter (selector);
1019 if (NULL == selector->source)
1022 if (GTK_IS_TREE_VIEW (selector->source))
1024 set_tree_view_source (selector);
1026 g_signal_connect (selector->source, "notify::model",
1027 G_CALLBACK (update_model), selector);
1029 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1032 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1034 if (NULL == selector->dest)
1036 else if (GTK_IS_TREE_VIEW (selector->dest))
1038 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1040 else if (GTK_IS_ENTRY (selector->dest))
1042 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1044 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1046 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1048 else if (GTK_IS_TEXT_VIEW (selector->dest))
1050 /* Nothing to be done */
1053 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1056 if (PSPPIRE_IS_DICT_VIEW (selector->source) && selector->select_items == NULL)
1058 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1059 GType type = G_OBJECT_TYPE (selector->dest);
1061 SelectItemsFunc *func =
1062 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1065 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1072 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1074 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1076 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1078 g_type_class_unref (class);
1084 /* Set FILTER_FUNC for this selector */
1086 psppire_selector_set_filter_func (PsppireSelector *selector,
1087 FilterItemsFunc *filter_func)
1089 selector->filter = filter_func ;
1093 /* Set SELECT_FUNC for this selector */
1095 psppire_selector_set_select_func (PsppireSelector *selector,
1096 SelectItemsFunc *select_func,
1099 selector->select_user_data = user_data;
1100 selector->select_items = select_func;
1106 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1108 selector->allow_selection = allow;
1113 psppire_selector_orientation_get_type (void)
1115 static GType etype = 0;
1118 static const GEnumValue values[] =
1120 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1121 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1122 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1123 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1126 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);