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"
69 #include "psppire-selector.h"
71 G_DEFINE_TYPE (PsppireSelector, psppire_selector, GTK_TYPE_BUTTON)
73 static void set_direction (PsppireSelector *, enum psppire_selector_dir);
76 enum {SELECTED, /* Emitted when an item is inserted into dest */
77 DE_SELECTED, /* Emitted when an item is removed from dest */
80 static guint signals [n_SIGNALS];
82 /* Callback for when an item disappears from the source list.
83 By implication, this means that the item has been inserted into the
87 on_row_deleted (PsppireSelector *selector)
89 g_signal_emit (selector, signals [SELECTED], 0);
92 /* Callback for when a new item appears in the source list.
93 By implication, this means that an item has been deleted from the
97 on_row_inserted (PsppireSelector *selector)
99 g_signal_emit (selector, signals [DE_SELECTED], 0);
102 static GObjectClass * parent_class = NULL;
106 dump_hash_entry (gpointer key, gpointer value, gpointer obj)
109 g_print ("Source %p; ", key);
111 for (item = g_list_first (value);
113 item = g_list_next (item))
115 g_print ("%p(%p) ", item->data, item);
120 /* This function is for debugging only */
122 psppire_selector_show_map (PsppireSelector *obj)
124 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
126 g_print ("%s %p\n", __FUNCTION__, obj);
127 g_hash_table_foreach (class->source_hash, dump_hash_entry, obj);
133 psppire_selector_dispose (GObject *obj)
135 PsppireSelector *sel = PSPPIRE_SELECTOR (obj);
136 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
139 if (sel->dispose_has_run)
142 /* Make sure dispose does not run twice. */
143 sel->dispose_has_run = TRUE;
145 /* Remove ourself from the source map. If we are the only entry for this source
146 widget, that will result in an empty list for the source. In that case, we
147 remove the entire entry too. */
148 if ((list = g_hash_table_lookup (class->source_hash, sel->source)))
150 GList *newlist = g_list_remove_link (list, sel->source_litem);
151 g_list_free (sel->source_litem);
153 g_hash_table_remove (class->source_hash, sel->source);
155 g_hash_table_replace (class->source_hash, sel->source, newlist);
157 sel->source_litem = NULL;
161 g_object_unref (sel->dest);
164 g_object_unref (sel->source);
166 /* Chain up to the parent class */
167 G_OBJECT_CLASS (parent_class)->dispose (obj);
182 static void on_click (GtkButton *b);
183 static void on_realize (GtkWidget *selector);
187 psppire_selector_set_property (GObject *object,
192 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
196 case PROP_ORIENTATION:
197 selector->orientation = g_value_get_enum (value);
198 set_direction (selector, selector->direction);
201 selector->primary_requested = TRUE;
202 psppire_selector_update_subjects (selector);
204 case PROP_SOURCE_WIDGET:
205 selector->source = g_value_dup_object (value);
206 psppire_selector_update_subjects (selector);
208 case PROP_DEST_WIDGET:
209 selector->dest = g_value_dup_object (value);
210 psppire_selector_update_subjects (selector);
213 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220 psppire_selector_get_property (GObject *object,
225 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
229 case PROP_ORIENTATION:
230 g_value_set_enum (value, selector->orientation);
232 case PROP_SOURCE_WIDGET:
233 g_value_take_object (value, selector->source);
235 case PROP_DEST_WIDGET:
236 g_value_take_object (value, selector->dest);
239 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245 psppire_selector_class_init (PsppireSelectorClass *class)
247 GObjectClass *object_class = G_OBJECT_CLASS (class);
248 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
249 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
250 GParamSpec *orientation_spec =
251 g_param_spec_enum ("orientation",
253 "Where the selector is relative to its subjects",
254 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
255 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
256 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
259 /* Meaningfull only if more than one selector shares this selectors source */
260 GParamSpec *primary_spec =
261 g_param_spec_boolean ("primary",
263 "Whether this selector should be the primary selector for the source",
267 GParamSpec *source_widget_spec =
268 g_param_spec_object ("source-widget",
270 "The widget to be used as the source for this selector",
274 GParamSpec *dest_widget_spec =
275 g_param_spec_object ("dest-widget",
276 "Destination Widget",
277 "The widget to be used as the destination for this selector",
282 button_class->clicked = on_click;
283 widget_class->realize = on_realize;
286 object_class->set_property = psppire_selector_set_property;
287 object_class->get_property = psppire_selector_get_property;
289 g_object_class_install_property (object_class,
293 g_object_class_install_property (object_class,
297 g_object_class_install_property (object_class,
301 g_object_class_install_property (object_class,
305 parent_class = g_type_class_peek_parent (class);
308 g_signal_new ("selected",
309 G_TYPE_FROM_CLASS (class),
313 g_cclosure_marshal_VOID__VOID,
317 signals [DE_SELECTED] =
318 g_signal_new ("de-selected",
319 G_TYPE_FROM_CLASS (class),
323 g_cclosure_marshal_VOID__VOID,
327 object_class->dispose = psppire_selector_dispose;
329 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
330 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
334 /* Callback for when the source treeview is activated (double clicked) */
336 on_row_activate (GtkTreeView *tree_view,
338 GtkTreeViewColumn *column,
341 on_click (GTK_BUTTON (data));
344 /* Callback for when the source selection changes */
346 on_source_select (GtkTreeSelection *treeselection, gpointer data)
348 PsppireSelector *selector = data;
350 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
352 if (selector->allow_selection)
354 gtk_widget_set_sensitive (GTK_WIDGET (selector),
355 selector->allow_selection (selector->source, selector->dest));
357 else if (GTK_IS_ENTRY (selector->dest))
359 gtk_widget_set_sensitive (GTK_WIDGET (selector),
360 gtk_tree_selection_count_selected_rows
361 (treeselection) <= 1);
367 on_realize (GtkWidget *w)
369 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
370 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
371 GtkTreeSelection* selection ;
373 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
375 if (GTK_WIDGET_CLASS (parent_class)->realize)
376 GTK_WIDGET_CLASS (parent_class)->realize (w);
381 if (g_list_first (list)->data == selector)
383 if (selector->row_activate_id)
384 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
386 selector->row_activate_id =
387 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
390 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
392 if (selector->source_select_id)
393 g_signal_handler_disconnect (selection, selector->source_select_id);
395 selector->source_select_id =
396 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
401 psppire_selector_init (PsppireSelector *selector)
403 selector->primary_requested = FALSE;
404 selector->select_user_data = NULL;
405 selector->select_items = NULL;
406 selector->allow_selection = NULL;
407 selector->filter = NULL;
409 selector->arrow = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
411 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
413 gtk_widget_show (selector->arrow);
415 selector->selecting = FALSE;
417 selector->source = NULL;
418 selector->dest = NULL;
419 selector->dispose_has_run = FALSE;
422 selector->row_activate_id = 0;
423 selector->source_select_id = 0;
425 selector->source_litem = NULL;
430 psppire_selector_new (void)
432 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
437 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
439 selector->direction = d;
441 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
443 if (d == PSPPIRE_SELECTOR_SOURCE_TO_DEST)
445 switch (selector->orientation)
447 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
448 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
450 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
451 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
453 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
454 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
456 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
457 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
460 g_assert_not_reached ();
466 switch (selector->orientation)
468 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
469 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
471 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
472 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
474 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
475 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
477 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
478 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
481 g_assert_not_reached ();
487 /* Callback for when the destination treeview selection changes */
489 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
491 PsppireSelector *selector = data;
493 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
495 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
499 /* Callback for source deselection, when the dest is GtkEntry */
501 de_select_selection_entry (PsppireSelector *selector)
503 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
507 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
509 /* Callback for source deselection, when the dest is PsppireMeansLayer */
511 de_select_selection_means_layer (PsppireSelector *selector)
513 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
514 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
515 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
517 GtkTreeModel *model = psppire_means_layer_get_model (ml);
519 g_return_if_fail (selector->select_items);
521 de_select_tree_model (selection, model);
524 /* Callback for source deselection, when the dest is GtkTreeView */
526 de_select_selection_tree_view (PsppireSelector *selector)
528 GtkTreeSelection* selection =
529 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->dest));
531 GtkTreeModel *model =
532 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
534 g_return_if_fail (selector->select_items);
536 de_select_tree_model (selection, model);
540 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
544 GList *selected_rows =
545 gtk_tree_selection_get_selected_rows (selection, NULL);
547 /* Convert paths to RowRefs */
548 for (item = g_list_first (selected_rows);
550 item = g_list_next (item))
552 GtkTreeRowReference* rowref;
553 GtkTreePath *path = item->data;
555 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
557 item->data = rowref ;
558 gtk_tree_path_free (path);
561 /* Remove each selected row from the dest widget */
562 for (item = g_list_first (selected_rows);
564 item = g_list_next (item))
567 GtkTreeRowReference *rr = item->data;
569 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
571 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
573 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
575 gtk_tree_path_free (path);
578 /* Delete list of RowRefs and its contents */
579 g_list_foreach (selected_rows, GFUNC_COMPAT_CAST (gtk_tree_row_reference_free), NULL);
580 g_list_free (selected_rows);
584 /* Callback which causes the filter to be refiltered.
585 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
589 refilter (PsppireSelector *selector)
591 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
592 if (GTK_IS_TREE_MODEL_FILTER (model))
593 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
597 /* Removes something from the DEST widget */
599 de_select_selection (PsppireSelector *selector)
601 selector->selecting = TRUE;
603 if (GTK_IS_TREE_VIEW (selector->dest))
604 de_select_selection_tree_view (selector);
606 else if (GTK_IS_ENTRY (selector->dest))
607 de_select_selection_entry (selector);
609 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
610 de_select_selection_means_layer (selector);
613 g_assert_not_reached ();
615 selector->selecting = FALSE;
619 g_signal_emit (selector, signals [DE_SELECTED], 0);
623 /* Puts something into the DEST widget */
625 select_selection (PsppireSelector *selector)
628 GtkTreeSelection* selection =
629 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
631 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
633 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
635 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
637 g_return_if_fail (selector->select_items);
639 if (selector->allow_selection &&
640 ! selector->allow_selection (selector->source, selector->dest))
643 selector->selecting = TRUE;
645 for (item = g_list_first (selected_rows);
647 item = g_list_next (item))
649 GtkTreeIter child_iter;
651 GtkTreePath *path = item->data;
653 g_return_if_fail (model);
655 gtk_tree_model_get_iter (model, &iter, path);
657 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
659 selector->select_items (child_iter,
662 selector->select_user_data
666 g_list_foreach (selected_rows, GFUNC_COMPAT_CAST (gtk_tree_path_free), NULL);
667 g_list_free (selected_rows);
671 g_signal_emit (selector, signals [SELECTED], 0);
673 selector->selecting = FALSE;
676 /* Callback for when the selector button is clicked,
677 or other event which causes the selector's action to occur.
680 on_click (GtkButton *b)
682 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
684 switch (selector->direction)
686 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
687 select_selection (selector);
689 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
690 de_select_selection (selector);
693 g_assert_not_reached ();
697 if (GTK_BUTTON_CLASS (parent_class)->clicked)
698 GTK_BUTTON_CLASS (parent_class)->clicked (b);
702 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
704 gboolean result = FALSE;
705 GtkTreeIter source_iter;
706 GtkTreeModel *source_model;
709 if (GTK_IS_TREE_MODEL_FILTER (model))
711 source_model = gtk_tree_model_filter_get_model
712 (GTK_TREE_MODEL_FILTER (model));
714 gtk_tree_model_filter_convert_iter_to_child_iter
715 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
719 source_model = model;
723 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
725 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
728 g_value_unset (&value);
735 /* Visibility function for items in the SOURCE widget.
736 Returns TRUE iff *all* the selectors for which SOURCE is associated
739 is_source_item_visible (GtkTreeModel *childmodel,
740 GtkTreeIter *iter, gpointer data)
742 PsppireSelector *selector = data;
743 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
747 list = g_hash_table_lookup (class->source_hash, selector->source);
751 PsppireSelector *selector = list->data;
753 if (selector->filter && selector->filter (childmodel, iter, selector))
763 /* set the source widget to SOURCE */
765 set_tree_view_source (PsppireSelector *selector)
769 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
771 if (! (list = g_hash_table_lookup (class->source_hash, selector->source)))
773 /* Base case: This widget is currently not the source of
774 any selector. Create a hash entry and make this selector
775 the first selector in the list */
777 list = g_list_append (list, selector);
778 g_hash_table_insert (class->source_hash, selector->source, list);
780 /* Save the list item so that it can be removed later */
781 selector->source_litem = list;
784 { /* Append this selector to the list and push the <source,list>
785 pair onto the hash table */
787 if (NULL == g_list_find (list, selector))
789 if (selector->primary_requested)
791 list = g_list_prepend (list, selector);
792 selector->source_litem = list;
796 list = g_list_append (list, selector);
797 selector->source_litem = g_list_last (list);
799 g_hash_table_replace (class->source_hash, selector->source, list);
806 /* This function is a callback which occurs when the
807 SOURCE's model has changed */
812 PsppireSelector *selector
815 GtkTreeModel *model = gtk_tree_view_get_model (source);
817 g_assert (source == GTK_TREE_VIEW (selector->source));
819 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
824 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
826 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
828 gtk_tree_view_set_model (source, new_model);
830 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
831 is_source_item_visible,
835 g_signal_connect_swapped (new_model,
837 G_CALLBACK (on_row_deleted), selector);
839 g_signal_connect_swapped (new_model,
841 G_CALLBACK (on_row_inserted), selector);
843 g_object_unref (new_model);
850 Callback for when the destination treeview's data changes
853 on_dest_data_change (GtkTreeModel *tree_model,
858 PsppireSelector *selector = user_data;
860 if (selector->selecting) return;
867 on_dest_data_delete (GtkTreeModel *tree_model,
871 PsppireSelector *selector = user_data;
873 if (selector->selecting) return;
880 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
882 g_signal_handlers_disconnect_by_data (sel, selector);
886 on_dest_model_changed (PsppireSelector *selector)
888 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
893 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
896 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
899 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
901 if (selector->selecting) return;
906 /* Set the destination widget to DEST */
908 set_tree_view_dest (PsppireSelector *selector,
911 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
914 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
916 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
919 on_dest_model_changed (selector);
920 g_signal_connect_swapped (dest, "notify::model",
921 G_CALLBACK (on_dest_model_changed), selector);
925 set_layer_dest (PsppireSelector *selector,
926 PsppireMeansLayer *dest)
928 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
930 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
933 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
938 /* Callback for when the DEST GtkEntry is selected (clicked) */
940 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
942 PsppireSelector * selector = data;
944 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
945 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
952 /* Set DEST to be the destination GtkEntry widget */
954 set_entry_dest (PsppireSelector *selector,
957 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
960 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
963 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
966 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
973 set_default_filter (PsppireSelector *selector)
975 if (selector->filter == NULL)
977 if (GTK_IS_TREE_VIEW (selector->dest))
978 selector->filter = is_item_in_dest;
984 psppire_selector_update_subjects (PsppireSelector *selector)
986 if (NULL == selector->dest)
989 set_default_filter (selector);
991 if (NULL == selector->source)
994 if (GTK_IS_TREE_VIEW (selector->source))
996 set_tree_view_source (selector);
998 g_signal_connect (selector->source, "notify::model",
999 G_CALLBACK (update_model), selector);
1001 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1004 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1006 if (NULL == selector->dest)
1008 else if (GTK_IS_TREE_VIEW (selector->dest))
1010 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1012 else if (GTK_IS_ENTRY (selector->dest))
1014 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1016 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1018 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1020 else if (GTK_IS_TEXT_VIEW (selector->dest))
1022 /* Nothing to be done */
1025 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1028 if (PSPPIRE_IS_DICT_VIEW (selector->source) && selector->select_items == NULL)
1030 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1031 GType type = G_OBJECT_TYPE (selector->dest);
1033 SelectItemsFunc *func =
1034 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1037 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1044 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1046 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1048 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1050 g_type_class_unref (class);
1056 /* Set FILTER_FUNC for this selector */
1058 psppire_selector_set_filter_func (PsppireSelector *selector,
1059 FilterItemsFunc *filter_func)
1061 selector->filter = filter_func ;
1065 /* Set SELECT_FUNC for this selector */
1067 psppire_selector_set_select_func (PsppireSelector *selector,
1068 SelectItemsFunc *select_func,
1071 selector->select_user_data = user_data;
1072 selector->select_items = select_func;
1078 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1080 selector->allow_selection = allow;
1085 psppire_selector_orientation_get_type (void)
1087 static GType etype = 0;
1090 static const GEnumValue values[] =
1092 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1093 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1094 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1095 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1098 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);