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 G_DEFINE_TYPE (PsppireSelector, psppire_selector, GTK_TYPE_BUTTON)
72 static void set_direction (PsppireSelector *, enum psppire_selector_dir);
75 enum {SELECTED, /* Emitted when an item is inserted into dest */
76 DE_SELECTED, /* Emitted when an item is removed from dest */
79 static guint signals [n_SIGNALS];
81 /* Callback for when an item disappears from the source list.
82 By implication, this means that the item has been inserted into the
86 on_row_deleted (PsppireSelector *selector)
88 g_signal_emit (selector, signals [SELECTED], 0);
91 /* Callback for when a new item appears in the source list.
92 By implication, this means that an item has been deleted from the
96 on_row_inserted (PsppireSelector *selector)
98 g_signal_emit (selector, signals [DE_SELECTED], 0);
101 static GObjectClass * parent_class = NULL;
104 dump_hash_entry (gpointer key, gpointer value, gpointer obj)
107 g_print ("Source %p; ", key);
109 for (item = g_list_first (value);
111 item = g_list_next (item))
113 g_print ("%p(%p) ", item->data, item);
118 /* This function is for debugging only */
120 psppire_selector_show_map (PsppireSelector *obj)
122 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
124 g_print ("%s %p\n", __FUNCTION__, obj);
125 g_hash_table_foreach (class->source_hash, dump_hash_entry, obj);
131 psppire_selector_dispose (GObject *obj)
133 PsppireSelector *sel = PSPPIRE_SELECTOR (obj);
134 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
137 if (sel->dispose_has_run)
140 /* Make sure dispose does not run twice. */
141 sel->dispose_has_run = TRUE;
143 /* Remove ourself from the source map. If we are the only entry for this source
144 widget, that will result in an empty list for the source. In that case, we
145 remove the entire entry too. */
146 if ((list = g_hash_table_lookup (class->source_hash, sel->source)))
148 GList *newlist = g_list_remove_link (list, sel->source_litem);
149 g_list_free (sel->source_litem);
151 g_hash_table_remove (class->source_hash, sel->source);
153 g_hash_table_replace (class->source_hash, sel->source, newlist);
155 sel->source_litem = NULL;
159 g_object_unref (sel->dest);
162 g_object_unref (sel->source);
164 /* Chain up to the parent class */
165 G_OBJECT_CLASS (parent_class)->dispose (obj);
180 static void on_click (GtkButton *b);
181 static void on_realize (GtkWidget *selector);
185 psppire_selector_set_property (GObject *object,
190 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
194 case PROP_ORIENTATION:
195 selector->orientation = g_value_get_enum (value);
196 set_direction (selector, selector->direction);
199 selector->primary_requested = TRUE;
200 psppire_selector_update_subjects (selector);
202 case PROP_SOURCE_WIDGET:
203 selector->source = g_value_dup_object (value);
204 psppire_selector_update_subjects (selector);
206 case PROP_DEST_WIDGET:
207 selector->dest = g_value_dup_object (value);
208 psppire_selector_update_subjects (selector);
211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
218 psppire_selector_get_property (GObject *object,
223 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
227 case PROP_ORIENTATION:
228 g_value_set_enum (value, selector->orientation);
230 case PROP_SOURCE_WIDGET:
231 g_value_take_object (value, selector->source);
233 case PROP_DEST_WIDGET:
234 g_value_take_object (value, selector->dest);
237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243 psppire_selector_class_init (PsppireSelectorClass *class)
245 GObjectClass *object_class = G_OBJECT_CLASS (class);
246 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
247 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
248 GParamSpec *orientation_spec =
249 g_param_spec_enum ("orientation",
251 "Where the selector is relative to its subjects",
252 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
253 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
254 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
257 /* Meaningfull only if more than one selector shares this selectors source */
258 GParamSpec *primary_spec =
259 g_param_spec_boolean ("primary",
261 "Whether this selector should be the primary selector for the source",
265 GParamSpec *source_widget_spec =
266 g_param_spec_object ("source-widget",
268 "The widget to be used as the source for this selector",
272 GParamSpec *dest_widget_spec =
273 g_param_spec_object ("dest-widget",
274 "Destination Widget",
275 "The widget to be used as the destination for this selector",
280 button_class->clicked = on_click;
281 widget_class->realize = on_realize;
284 object_class->set_property = psppire_selector_set_property;
285 object_class->get_property = psppire_selector_get_property;
287 g_object_class_install_property (object_class,
291 g_object_class_install_property (object_class,
295 g_object_class_install_property (object_class,
299 g_object_class_install_property (object_class,
303 parent_class = g_type_class_peek_parent (class);
306 g_signal_new ("selected",
307 G_TYPE_FROM_CLASS (class),
311 g_cclosure_marshal_VOID__VOID,
315 signals [DE_SELECTED] =
316 g_signal_new ("de-selected",
317 G_TYPE_FROM_CLASS (class),
321 g_cclosure_marshal_VOID__VOID,
325 object_class->dispose = psppire_selector_dispose;
327 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
328 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
332 /* Callback for when the source treeview is activated (double clicked) */
334 on_row_activate (GtkTreeView *tree_view,
336 GtkTreeViewColumn *column,
339 on_click (GTK_BUTTON (data));
342 /* Callback for when the source selection changes */
344 on_source_select (GtkTreeSelection *treeselection, gpointer data)
346 PsppireSelector *selector = data;
348 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
350 if (selector->allow_selection)
352 gtk_widget_set_sensitive (GTK_WIDGET (selector),
353 selector->allow_selection (selector->source, selector->dest));
355 else if (GTK_IS_ENTRY (selector->dest))
357 gtk_widget_set_sensitive (GTK_WIDGET (selector),
358 gtk_tree_selection_count_selected_rows
359 (treeselection) <= 1);
365 on_realize (GtkWidget *w)
367 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
368 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
369 GtkTreeSelection* selection ;
371 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
373 if (GTK_WIDGET_CLASS (parent_class)->realize)
374 GTK_WIDGET_CLASS (parent_class)->realize (w);
379 if (g_list_first (list)->data == selector)
381 if (selector->row_activate_id)
382 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
384 selector->row_activate_id =
385 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
388 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
390 if (selector->source_select_id)
391 g_signal_handler_disconnect (selection, selector->source_select_id);
393 selector->source_select_id =
394 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
399 psppire_selector_init (PsppireSelector *selector)
401 selector->primary_requested = FALSE;
402 selector->select_user_data = NULL;
403 selector->select_items = NULL;
404 selector->allow_selection = NULL;
405 selector->filter = NULL;
407 selector->arrow = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
409 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
411 gtk_widget_show (selector->arrow);
413 selector->selecting = FALSE;
415 selector->source = NULL;
416 selector->dest = NULL;
417 selector->dispose_has_run = FALSE;
420 selector->row_activate_id = 0;
421 selector->source_select_id = 0;
423 selector->source_litem = NULL;
428 psppire_selector_new (void)
430 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
435 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
437 selector->direction = d;
439 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
441 if (d == PSPPIRE_SELECTOR_SOURCE_TO_DEST)
443 switch (selector->orientation)
445 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
446 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
448 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
449 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
451 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
452 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
454 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
455 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
458 g_assert_not_reached ();
464 switch (selector->orientation)
466 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
467 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
469 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
470 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
472 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
473 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
475 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
476 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
479 g_assert_not_reached ();
485 /* Callback for when the destination treeview selection changes */
487 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
489 PsppireSelector *selector = data;
491 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
493 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
497 /* Callback for source deselection, when the dest is GtkEntry */
499 de_select_selection_entry (PsppireSelector *selector)
501 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
505 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
507 /* Callback for source deselection, when the dest is PsppireMeansLayer */
509 de_select_selection_means_layer (PsppireSelector *selector)
511 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
512 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
513 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
515 GtkTreeModel *model = psppire_means_layer_get_model (ml);
517 g_return_if_fail (selector->select_items);
519 de_select_tree_model (selection, model);
522 /* Callback for source deselection, when the dest is GtkTreeView */
524 de_select_selection_tree_view (PsppireSelector *selector)
526 GtkTreeSelection* selection =
527 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->dest));
529 GtkTreeModel *model =
530 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
532 g_return_if_fail (selector->select_items);
534 de_select_tree_model (selection, model);
538 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
542 GList *selected_rows =
543 gtk_tree_selection_get_selected_rows (selection, NULL);
545 /* Convert paths to RowRefs */
546 for (item = g_list_first (selected_rows);
548 item = g_list_next (item))
550 GtkTreeRowReference* rowref;
551 GtkTreePath *path = item->data;
553 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
555 item->data = rowref ;
556 gtk_tree_path_free (path);
559 /* Remove each selected row from the dest widget */
560 for (item = g_list_first (selected_rows);
562 item = g_list_next (item))
565 GtkTreeRowReference *rr = item->data;
567 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
569 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
571 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
573 gtk_tree_path_free (path);
576 /* Delete list of RowRefs and its contents */
577 g_list_foreach (selected_rows, (GFunc) (void (*)(void)) gtk_tree_row_reference_free, NULL);
578 g_list_free (selected_rows);
582 /* Callback which causes the filter to be refiltered.
583 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
587 refilter (PsppireSelector *selector)
589 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
590 if (GTK_IS_TREE_MODEL_FILTER (model))
591 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
595 /* Removes something from the DEST widget */
597 de_select_selection (PsppireSelector *selector)
599 selector->selecting = TRUE;
601 if (GTK_IS_TREE_VIEW (selector->dest))
602 de_select_selection_tree_view (selector);
604 else if (GTK_IS_ENTRY (selector->dest))
605 de_select_selection_entry (selector);
607 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
608 de_select_selection_means_layer (selector);
611 g_assert_not_reached ();
613 selector->selecting = FALSE;
617 g_signal_emit (selector, signals [DE_SELECTED], 0);
621 /* Puts something into the DEST widget */
623 select_selection (PsppireSelector *selector)
626 GtkTreeSelection* selection =
627 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
629 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
631 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
633 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
635 g_return_if_fail (selector->select_items);
637 if (selector->allow_selection &&
638 ! selector->allow_selection (selector->source, selector->dest))
641 selector->selecting = TRUE;
643 for (item = g_list_first (selected_rows);
645 item = g_list_next (item))
647 GtkTreeIter child_iter;
649 GtkTreePath *path = item->data;
651 g_return_if_fail (model);
653 gtk_tree_model_get_iter (model, &iter, path);
655 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
657 selector->select_items (child_iter,
660 selector->select_user_data
664 g_list_foreach (selected_rows, (GFunc) (void (*)(void)) gtk_tree_path_free, NULL);
665 g_list_free (selected_rows);
669 g_signal_emit (selector, signals [SELECTED], 0);
671 selector->selecting = FALSE;
674 /* Callback for when the selector button is clicked,
675 or other event which causes the selector's action to occur.
678 on_click (GtkButton *b)
680 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
682 switch (selector->direction)
684 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
685 select_selection (selector);
687 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
688 de_select_selection (selector);
691 g_assert_not_reached ();
695 if (GTK_BUTTON_CLASS (parent_class)->clicked)
696 GTK_BUTTON_CLASS (parent_class)->clicked (b);
700 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
702 gboolean result = FALSE;
703 GtkTreeIter source_iter;
704 GtkTreeModel *source_model;
707 if (GTK_IS_TREE_MODEL_FILTER (model))
709 source_model = gtk_tree_model_filter_get_model
710 (GTK_TREE_MODEL_FILTER (model));
712 gtk_tree_model_filter_convert_iter_to_child_iter
713 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
717 source_model = model;
721 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
723 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
726 g_value_unset (&value);
733 /* Visibility function for items in the SOURCE widget.
734 Returns TRUE iff *all* the selectors for which SOURCE is associated
737 is_source_item_visible (GtkTreeModel *childmodel,
738 GtkTreeIter *iter, gpointer data)
740 PsppireSelector *selector = data;
741 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
745 list = g_hash_table_lookup (class->source_hash, selector->source);
749 PsppireSelector *selector = list->data;
751 if (selector->filter && selector->filter (childmodel, iter, selector))
761 /* set the source widget to SOURCE */
763 set_tree_view_source (PsppireSelector *selector)
767 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
769 if (! (list = g_hash_table_lookup (class->source_hash, selector->source)))
771 /* Base case: This widget is currently not the source of
772 any selector. Create a hash entry and make this selector
773 the first selector in the list */
775 list = g_list_append (list, selector);
776 g_hash_table_insert (class->source_hash, selector->source, list);
778 /* Save the list item so that it can be removed later */
779 selector->source_litem = list;
782 { /* Append this selector to the list and push the <source,list>
783 pair onto the hash table */
785 if (NULL == g_list_find (list, selector))
787 if (selector->primary_requested)
789 list = g_list_prepend (list, selector);
790 selector->source_litem = list;
794 list = g_list_append (list, selector);
795 selector->source_litem = g_list_last (list);
797 g_hash_table_replace (class->source_hash, selector->source, list);
804 /* This function is a callback which occurs when the
805 SOURCE's model has changed */
810 PsppireSelector *selector
813 GtkTreeModel *model = gtk_tree_view_get_model (source);
815 g_assert (source == GTK_TREE_VIEW (selector->source));
817 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
822 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
824 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
826 gtk_tree_view_set_model (source, new_model);
828 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
829 is_source_item_visible,
833 g_signal_connect_swapped (new_model,
835 G_CALLBACK (on_row_deleted), selector);
837 g_signal_connect_swapped (new_model,
839 G_CALLBACK (on_row_inserted), selector);
841 g_object_unref (new_model);
848 Callback for when the destination treeview's data changes
851 on_dest_data_change (GtkTreeModel *tree_model,
856 PsppireSelector *selector = user_data;
858 if (selector->selecting) return;
865 on_dest_data_delete (GtkTreeModel *tree_model,
869 PsppireSelector *selector = user_data;
871 if (selector->selecting) return;
878 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
880 g_signal_handlers_disconnect_by_data (sel, selector);
884 on_dest_model_changed (PsppireSelector *selector)
886 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
891 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
894 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
897 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
899 if (selector->selecting) return;
904 /* Set the destination widget to DEST */
906 set_tree_view_dest (PsppireSelector *selector,
909 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
912 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
914 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
917 on_dest_model_changed (selector);
918 g_signal_connect_swapped (dest, "notify::model",
919 G_CALLBACK (on_dest_model_changed), selector);
923 set_layer_dest (PsppireSelector *selector,
924 PsppireMeansLayer *dest)
926 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
928 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
931 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
936 /* Callback for when the DEST GtkEntry is selected (clicked) */
938 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
940 PsppireSelector * selector = data;
942 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
943 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
950 /* Set DEST to be the destination GtkEntry widget */
952 set_entry_dest (PsppireSelector *selector,
955 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
958 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
961 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
964 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
971 set_default_filter (PsppireSelector *selector)
973 if (selector->filter == NULL)
975 if (GTK_IS_TREE_VIEW (selector->dest))
976 selector->filter = is_item_in_dest;
982 psppire_selector_update_subjects (PsppireSelector *selector)
984 if (NULL == selector->dest)
987 set_default_filter (selector);
989 if (NULL == selector->source)
992 if (GTK_IS_TREE_VIEW (selector->source))
994 set_tree_view_source (selector);
996 g_signal_connect (selector->source, "notify::model",
997 G_CALLBACK (update_model), selector);
999 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1002 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1004 if (NULL == selector->dest)
1006 else if (GTK_IS_TREE_VIEW (selector->dest))
1008 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1010 else if (GTK_IS_ENTRY (selector->dest))
1012 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1014 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1016 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1018 else if (GTK_IS_TEXT_VIEW (selector->dest))
1020 /* Nothing to be done */
1023 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1026 if (PSPPIRE_IS_DICT_VIEW (selector->source) && selector->select_items == NULL)
1028 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1029 GType type = G_OBJECT_TYPE (selector->dest);
1031 SelectItemsFunc *func =
1032 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1035 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1042 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1044 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1046 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1048 g_type_class_unref (class);
1054 /* Set FILTER_FUNC for this selector */
1056 psppire_selector_set_filter_func (PsppireSelector *selector,
1057 FilterItemsFunc *filter_func)
1059 selector->filter = filter_func ;
1063 /* Set SELECT_FUNC for this selector */
1065 psppire_selector_set_select_func (PsppireSelector *selector,
1066 SelectItemsFunc *select_func,
1069 selector->select_user_data = user_data;
1070 selector->select_items = select_func;
1076 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1078 selector->allow_selection = allow;
1083 psppire_selector_orientation_get_type (void)
1085 static GType etype = 0;
1088 static const GEnumValue values[] =
1090 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1091 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1092 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1093 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1096 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);