1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2009, 2010, 2012 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 GtkArrow, 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-var-view.h"
63 #include "psppire-dict.h"
64 #include "psppire-select-dest.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;
136 #define SELECTOR_DEBUGGING 0
139 dump_hash_entry (gpointer key, gpointer value, gpointer obj)
142 g_print ("Source %p; ", key);
144 for (item = g_list_first (value);
146 item = g_list_next (item))
148 g_print ("%p(%p) ", item->data, item);
153 /* This function is for debugging only */
155 psppire_selector_show_map (PsppireSelector *obj)
157 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
159 g_print ("%s %p\n", __FUNCTION__, obj);
160 g_hash_table_foreach (class->source_hash, dump_hash_entry, obj);
166 psppire_selector_dispose (GObject *obj)
168 PsppireSelector *sel = PSPPIRE_SELECTOR (obj);
169 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
172 if (sel->dispose_has_run)
175 /* Make sure dispose does not run twice. */
176 sel->dispose_has_run = TRUE;
178 /* Remove ourself from the source map. If we are the only entry for this source
179 widget, that will result in an empty list for the source. In that case, we
180 remove the entire entry too. */
181 if ((list = g_hash_table_lookup (class->source_hash, sel->source)))
183 GList *newlist = g_list_remove_link (list, sel->source_litem);
184 g_list_free (sel->source_litem);
186 g_hash_table_remove (class->source_hash, sel->source);
188 g_hash_table_replace (class->source_hash, sel->source, newlist);
190 sel->source_litem = NULL;
193 g_object_unref (sel->dest);
194 g_object_unref (sel->source);
196 /* Chain up to the parent class */
197 G_OBJECT_CLASS (parent_class)->dispose (obj);
212 static void on_click (GtkButton *b);
213 static void on_realize (GtkWidget *selector);
216 static void update_subjects (PsppireSelector *selector);
220 psppire_selector_set_property (GObject *object,
225 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
229 case PROP_ORIENTATION:
230 selector->orientation = g_value_get_enum (value);
231 set_direction (selector, selector->direction);
234 selector->primary_requested = TRUE;
235 update_subjects (selector);
237 case PROP_SOURCE_WIDGET:
238 selector->source = g_value_dup_object (value);
239 update_subjects (selector);
241 case PROP_DEST_WIDGET:
242 selector->dest = g_value_dup_object (value);
243 update_subjects (selector);
246 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
253 psppire_selector_get_property (GObject *object,
258 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
262 case PROP_ORIENTATION:
263 g_value_set_enum (value, selector->orientation);
265 case PROP_SOURCE_WIDGET:
266 g_value_take_object (value, selector->source);
268 case PROP_DEST_WIDGET:
269 g_value_take_object (value, selector->dest);
272 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
278 psppire_selector_class_init (PsppireSelectorClass *class)
280 GObjectClass *object_class = G_OBJECT_CLASS (class);
281 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
282 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
283 GParamSpec *orientation_spec =
284 g_param_spec_enum ("orientation",
286 "Where the selector is relative to its subjects",
287 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
288 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
289 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
292 /* Meaningfull only if more than one selector shares this selectors source */
293 GParamSpec *primary_spec =
294 g_param_spec_boolean ("primary",
296 "Whether this selector should be the primary selector for the source",
300 GParamSpec *source_widget_spec =
301 g_param_spec_object ("source-widget",
303 "The widget to be used as the source for this selector",
307 GParamSpec *dest_widget_spec =
308 g_param_spec_object ("dest-widget",
309 "Destination Widget",
310 "The widget to be used as the destination for this selector",
315 button_class->clicked = on_click;
316 widget_class->realize = on_realize;
319 object_class->set_property = psppire_selector_set_property;
320 object_class->get_property = psppire_selector_get_property;
322 g_object_class_install_property (object_class,
326 g_object_class_install_property (object_class,
330 g_object_class_install_property (object_class,
334 g_object_class_install_property (object_class,
338 parent_class = g_type_class_peek_parent (class);
341 g_signal_new ("selected",
342 G_TYPE_FROM_CLASS (class),
346 g_cclosure_marshal_VOID__VOID,
350 signals [DE_SELECTED] =
351 g_signal_new ("de-selected",
352 G_TYPE_FROM_CLASS (class),
356 g_cclosure_marshal_VOID__VOID,
360 object_class->dispose = psppire_selector_dispose;
362 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
363 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
367 /* Callback for when the source treeview is activated (double clicked) */
369 on_row_activate (GtkTreeView *tree_view,
371 GtkTreeViewColumn *column,
374 on_click (GTK_BUTTON (data));
377 /* Callback for when the source selection changes */
379 on_source_select (GtkTreeSelection *treeselection, gpointer data)
381 PsppireSelector *selector = data;
383 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
385 if ( selector->allow_selection )
387 gtk_widget_set_sensitive (GTK_WIDGET (selector),
388 selector->allow_selection (selector->source, selector->dest));
390 else if ( GTK_IS_ENTRY (selector->dest) )
392 gtk_widget_set_sensitive (GTK_WIDGET (selector),
393 gtk_tree_selection_count_selected_rows
394 (treeselection) <= 1 );
400 on_realize (GtkWidget *w)
402 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
403 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
404 GtkTreeSelection* selection ;
406 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
408 if (GTK_WIDGET_CLASS (parent_class)->realize)
409 GTK_WIDGET_CLASS (parent_class)->realize (w);
414 if ( g_list_first (list)->data == selector)
416 if ( selector->row_activate_id )
417 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
419 selector->row_activate_id =
420 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
423 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
425 if ( selector->source_select_id )
426 g_signal_handler_disconnect (selection, selector->source_select_id);
428 selector->source_select_id =
429 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
434 psppire_selector_init (PsppireSelector *selector)
436 selector->primary_requested = FALSE;
437 selector->select_user_data = NULL;
438 selector->select_items = NULL;
439 selector->allow_selection = NULL;
440 selector->filter = NULL;
442 selector->arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
445 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
447 gtk_widget_show (selector->arrow);
449 selector->selecting = FALSE;
451 selector->source = NULL;
452 selector->dest = NULL;
453 selector->dispose_has_run = FALSE;
456 selector->row_activate_id = 0;
457 selector->source_select_id = 0;
459 selector->source_litem = NULL;
464 psppire_selector_new (void)
466 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
471 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
473 selector->direction = d;
475 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
477 if ( d == PSPPIRE_SELECTOR_SOURCE_TO_DEST )
479 switch (selector->orientation)
481 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
482 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_RIGHT, NULL);
484 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
485 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_LEFT, NULL);
487 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
488 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_DOWN, NULL);
490 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
491 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_UP, NULL);
494 g_assert_not_reached ();
500 switch (selector->orientation)
502 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
503 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_LEFT, NULL);
505 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
506 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_RIGHT, NULL);
508 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
509 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_UP, NULL);
511 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
512 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_DOWN, NULL);
515 g_assert_not_reached ();
522 /* Callback for when the destination treeview selection changes */
524 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
526 PsppireSelector *selector = data;
528 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
530 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
533 /* Callback for source deselection, when the dest is GtkEntry */
535 de_select_selection_entry (PsppireSelector *selector)
537 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
540 /* Callback for source deselection, when the dest is GtkTreeView */
542 de_select_selection_tree_view (PsppireSelector *selector)
546 GtkTreeSelection* selection =
547 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->dest));
549 GtkTreeModel *model =
550 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
552 GList *selected_rows =
553 gtk_tree_selection_get_selected_rows (selection, NULL);
555 g_return_if_fail (selector->select_items);
557 /* Convert paths to RowRefs */
558 for (item = g_list_first (selected_rows);
560 item = g_list_next (item))
562 GtkTreeRowReference* rowref;
563 GtkTreePath *path = item->data;
565 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
567 item->data = rowref ;
568 gtk_tree_path_free (path);
571 /* Remove each selected row from the dest widget */
572 for (item = g_list_first (selected_rows);
574 item = g_list_next (item))
577 GtkTreeRowReference *rr = item->data;
579 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
581 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
583 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
585 gtk_tree_path_free (path);
588 /* Delete list of RowRefs and its contents */
589 g_list_foreach (selected_rows, (GFunc) gtk_tree_row_reference_free, NULL);
590 g_list_free (selected_rows);
594 /* Callback which causes the filter to be refiltered.
595 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
599 refilter (PsppireSelector *selector)
601 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
602 if (GTK_IS_TREE_MODEL_FILTER (model))
603 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
607 /* Removes something from the DEST widget */
609 de_select_selection (PsppireSelector *selector)
611 selector->selecting = TRUE;
613 if ( GTK_IS_TREE_VIEW (selector->dest ) )
614 de_select_selection_tree_view (selector);
616 else if ( GTK_IS_ENTRY (selector->dest))
617 de_select_selection_entry (selector);
620 g_assert_not_reached ();
622 selector->selecting = FALSE;
626 g_signal_emit (selector, signals [DE_SELECTED], 0);
630 /* Puts something into the DEST widget */
632 select_selection (PsppireSelector *selector)
635 GtkTreeSelection* selection =
636 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->source));
638 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
640 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
642 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
644 g_return_if_fail (selector->select_items);
646 if (selector->allow_selection &&
647 ! selector->allow_selection (selector->source, selector->dest))
650 selector->selecting = TRUE;
652 for (item = g_list_first (selected_rows);
654 item = g_list_next (item))
656 GtkTreeIter child_iter;
658 GtkTreePath *path = item->data;
660 g_return_if_fail (model);
662 gtk_tree_model_get_iter (model, &iter, path);
664 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
666 selector->select_items (child_iter,
669 selector->select_user_data
673 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
674 g_list_free (selected_rows);
678 g_signal_emit (selector, signals [SELECTED], 0);
680 selector->selecting = FALSE;
683 /* Callback for when the selector button is clicked,
684 or other event which causes the selector's action to occur.
687 on_click (GtkButton *b)
689 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
691 switch (selector->direction)
693 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
694 select_selection (selector);
696 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
697 de_select_selection (selector);
700 g_assert_not_reached ();
704 if (GTK_BUTTON_CLASS (parent_class)->clicked)
705 GTK_BUTTON_CLASS (parent_class)->clicked (b);
709 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
711 gboolean result = FALSE;
712 GtkTreeIter source_iter;
713 GtkTreeModel *source_model;
716 if (GTK_IS_TREE_MODEL_FILTER (model))
718 source_model = gtk_tree_model_filter_get_model
719 (GTK_TREE_MODEL_FILTER (model));
721 gtk_tree_model_filter_convert_iter_to_child_iter
722 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
726 source_model = model;
730 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
732 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
735 g_value_unset (&value);
742 /* Visibility function for items in the SOURCE widget.
743 Returns TRUE iff *all* the selectors for which SOURCE is associated
746 is_source_item_visible (GtkTreeModel *childmodel,
747 GtkTreeIter *iter, gpointer data)
749 PsppireSelector *selector = data;
750 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
754 list = g_hash_table_lookup (class->source_hash, selector->source);
758 PsppireSelector *selector = list->data;
760 if ( selector->filter && selector->filter (childmodel, iter, selector))
770 /* set the source widget to SOURCE */
772 set_tree_view_source (PsppireSelector *selector)
776 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
778 if ( ! (list = g_hash_table_lookup (class->source_hash, selector->source)))
780 /* Base case: This widget is currently not the source of
781 any selector. Create a hash entry and make this selector
782 the first selector in the list */
784 list = g_list_append (list, selector);
785 g_hash_table_insert (class->source_hash, selector->source, list);
787 /* Save the list item so that it can be removed later */
788 selector->source_litem = list;
791 { /* Append this selector to the list and push the <source,list>
792 pair onto the hash table */
794 if ( NULL == g_list_find (list, selector) )
796 if ( selector->primary_requested )
798 list = g_list_prepend (list, selector);
799 selector->source_litem = list;
803 list = g_list_append (list, selector);
804 selector->source_litem = g_list_last (list);
806 g_hash_table_replace (class->source_hash, selector->source, list);
813 /* This function is a callback which occurs when the
814 SOURCE's model has changed */
819 PsppireSelector *selector
822 GtkTreeModel *model = gtk_tree_view_get_model (source);
824 g_assert (source == GTK_TREE_VIEW (selector->source));
826 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
831 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
833 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
835 gtk_tree_view_set_model (source, new_model);
837 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
838 is_source_item_visible,
842 g_signal_connect_swapped (new_model,
844 G_CALLBACK (on_row_deleted), selector);
846 g_signal_connect_swapped (new_model,
848 G_CALLBACK (on_row_inserted), selector);
850 g_object_unref (new_model);
857 Callback for when the destination treeview's data changes
860 on_dest_data_change (GtkTreeModel *tree_model,
865 PsppireSelector *selector = user_data;
867 if ( selector->selecting) return;
874 on_dest_data_delete (GtkTreeModel *tree_model,
878 PsppireSelector *selector = user_data;
880 if ( selector->selecting ) return;
887 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
889 g_signal_handlers_disconnect_by_data (sel, selector);
893 on_dest_model_changed (PsppireSelector *selector)
895 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
900 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
903 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
906 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
908 if ( selector->selecting ) return;
913 /* Set the destination widget to DEST */
915 set_tree_view_dest (PsppireSelector *selector,
918 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
921 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
923 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
926 on_dest_model_changed (selector);
927 g_signal_connect_swapped (dest, "notify::model",
928 G_CALLBACK (on_dest_model_changed), selector);
934 /* Callback for when the DEST GtkEntry is selected (clicked) */
936 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
938 PsppireSelector * selector = data;
940 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
941 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
948 /* Set DEST to be the destination GtkEntry widget */
950 set_entry_dest (PsppireSelector *selector,
953 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
956 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
959 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
962 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
969 set_default_filter (PsppireSelector *selector)
971 if ( selector->filter == NULL)
973 if (GTK_IS_TREE_VIEW (selector->dest))
974 selector->filter = is_item_in_dest;
980 update_subjects (PsppireSelector *selector)
982 if ( NULL == selector->dest )
985 set_default_filter (selector);
987 if ( NULL == selector->source )
990 if ( GTK_IS_TREE_VIEW (selector->source))
992 set_tree_view_source (selector);
994 g_signal_connect (selector->source, "notify::model",
995 G_CALLBACK (update_model), selector);
997 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1000 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1002 if ( NULL == selector->dest)
1004 else if ( GTK_IS_TREE_VIEW (selector->dest))
1006 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1009 else if ( GTK_IS_ENTRY (selector->dest))
1010 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1012 else if (GTK_IS_TEXT_VIEW (selector->dest))
1014 /* Nothing to be done */
1017 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1020 /* FIXME: Remove this dependency */
1021 if ( PSPPIRE_IS_DICT_VIEW (selector->source) )
1023 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1024 GType type = G_OBJECT_TYPE (selector->dest);
1026 SelectItemsFunc *func =
1027 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1030 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1037 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1039 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1041 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1043 g_type_class_unref (class);
1049 /* Set FILTER_FUNC for this selector */
1051 psppire_selector_set_filter_func (PsppireSelector *selector,
1052 FilterItemsFunc *filter_func)
1054 selector->filter = filter_func ;
1058 /* Set SELECT_FUNC for this selector */
1060 psppire_selector_set_select_func (PsppireSelector *selector,
1061 SelectItemsFunc *select_func,
1064 selector->select_user_data = user_data;
1065 selector->select_items = select_func;
1071 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1073 selector->allow_selection = allow;
1078 psppire_selector_orientation_get_type (void)
1080 static GType etype = 0;
1082 static const GEnumValue values[] = {
1083 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1084 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1085 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1086 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1089 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);