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;
105 dump_hash_entry (gpointer key, gpointer value, gpointer obj)
108 g_print ("Source %p; ", key);
110 for (item = g_list_first (value);
112 item = g_list_next (item))
114 g_print ("%p(%p) ", item->data, item);
119 /* This function is for debugging only */
121 psppire_selector_show_map (PsppireSelector *obj)
123 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
125 g_print ("%s %p\n", __FUNCTION__, obj);
126 g_hash_table_foreach (class->source_hash, dump_hash_entry, obj);
132 psppire_selector_dispose (GObject *obj)
134 PsppireSelector *sel = PSPPIRE_SELECTOR (obj);
135 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
138 if (sel->dispose_has_run)
141 /* Make sure dispose does not run twice. */
142 sel->dispose_has_run = TRUE;
144 /* Remove ourself from the source map. If we are the only entry for this source
145 widget, that will result in an empty list for the source. In that case, we
146 remove the entire entry too. */
147 if ((list = g_hash_table_lookup (class->source_hash, sel->source)))
149 GList *newlist = g_list_remove_link (list, sel->source_litem);
150 g_list_free (sel->source_litem);
152 g_hash_table_remove (class->source_hash, sel->source);
154 g_hash_table_replace (class->source_hash, sel->source, newlist);
156 sel->source_litem = NULL;
160 g_object_unref (sel->dest);
163 g_object_unref (sel->source);
165 /* Chain up to the parent class */
166 G_OBJECT_CLASS (parent_class)->dispose (obj);
181 static void on_click (GtkButton *b);
182 static void on_realize (GtkWidget *selector);
186 psppire_selector_set_property (GObject *object,
191 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
195 case PROP_ORIENTATION:
196 selector->orientation = g_value_get_enum (value);
197 set_direction (selector, selector->direction);
200 selector->primary_requested = TRUE;
201 psppire_selector_update_subjects (selector);
203 case PROP_SOURCE_WIDGET:
204 selector->source = g_value_dup_object (value);
205 psppire_selector_update_subjects (selector);
207 case PROP_DEST_WIDGET:
208 selector->dest = g_value_dup_object (value);
209 psppire_selector_update_subjects (selector);
212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219 psppire_selector_get_property (GObject *object,
224 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
228 case PROP_ORIENTATION:
229 g_value_set_enum (value, selector->orientation);
231 case PROP_SOURCE_WIDGET:
232 g_value_take_object (value, selector->source);
234 case PROP_DEST_WIDGET:
235 g_value_take_object (value, selector->dest);
238 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
244 psppire_selector_class_init (PsppireSelectorClass *class)
246 GObjectClass *object_class = G_OBJECT_CLASS (class);
247 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
248 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
249 GParamSpec *orientation_spec =
250 g_param_spec_enum ("orientation",
252 "Where the selector is relative to its subjects",
253 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
254 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
255 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
258 /* Meaningfull only if more than one selector shares this selectors source */
259 GParamSpec *primary_spec =
260 g_param_spec_boolean ("primary",
262 "Whether this selector should be the primary selector for the source",
266 GParamSpec *source_widget_spec =
267 g_param_spec_object ("source-widget",
269 "The widget to be used as the source for this selector",
273 GParamSpec *dest_widget_spec =
274 g_param_spec_object ("dest-widget",
275 "Destination Widget",
276 "The widget to be used as the destination for this selector",
281 button_class->clicked = on_click;
282 widget_class->realize = on_realize;
285 object_class->set_property = psppire_selector_set_property;
286 object_class->get_property = psppire_selector_get_property;
288 g_object_class_install_property (object_class,
292 g_object_class_install_property (object_class,
296 g_object_class_install_property (object_class,
300 g_object_class_install_property (object_class,
304 parent_class = g_type_class_peek_parent (class);
307 g_signal_new ("selected",
308 G_TYPE_FROM_CLASS (class),
312 g_cclosure_marshal_VOID__VOID,
316 signals [DE_SELECTED] =
317 g_signal_new ("de-selected",
318 G_TYPE_FROM_CLASS (class),
322 g_cclosure_marshal_VOID__VOID,
326 object_class->dispose = psppire_selector_dispose;
328 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
329 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
333 /* Callback for when the source treeview is activated (double clicked) */
335 on_row_activate (GtkTreeView *tree_view,
337 GtkTreeViewColumn *column,
340 on_click (GTK_BUTTON (data));
343 /* Callback for when the source selection changes */
345 on_source_select (GtkTreeSelection *treeselection, gpointer data)
347 PsppireSelector *selector = data;
349 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
351 if (selector->allow_selection)
353 gtk_widget_set_sensitive (GTK_WIDGET (selector),
354 selector->allow_selection (selector->source, selector->dest));
356 else if (GTK_IS_ENTRY (selector->dest))
358 gtk_widget_set_sensitive (GTK_WIDGET (selector),
359 gtk_tree_selection_count_selected_rows
360 (treeselection) <= 1);
366 on_realize (GtkWidget *w)
368 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
369 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
370 GtkTreeSelection* selection ;
372 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
374 if (GTK_WIDGET_CLASS (parent_class)->realize)
375 GTK_WIDGET_CLASS (parent_class)->realize (w);
380 if (g_list_first (list)->data == selector)
382 if (selector->row_activate_id)
383 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
385 selector->row_activate_id =
386 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
389 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
391 if (selector->source_select_id)
392 g_signal_handler_disconnect (selection, selector->source_select_id);
394 selector->source_select_id =
395 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
400 psppire_selector_init (PsppireSelector *selector)
402 selector->primary_requested = FALSE;
403 selector->select_user_data = NULL;
404 selector->select_items = NULL;
405 selector->allow_selection = NULL;
406 selector->filter = NULL;
408 selector->arrow = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
410 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
412 gtk_widget_show (selector->arrow);
414 selector->selecting = FALSE;
416 selector->source = NULL;
417 selector->dest = NULL;
418 selector->dispose_has_run = FALSE;
421 selector->row_activate_id = 0;
422 selector->source_select_id = 0;
424 selector->source_litem = NULL;
429 psppire_selector_new (void)
431 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
436 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
438 selector->direction = d;
440 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
442 if (d == PSPPIRE_SELECTOR_SOURCE_TO_DEST)
444 switch (selector->orientation)
446 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
447 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
449 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
450 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
452 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
453 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
455 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
456 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
459 g_assert_not_reached ();
465 switch (selector->orientation)
467 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
468 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
470 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
471 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
473 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
474 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
476 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
477 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
480 g_assert_not_reached ();
486 /* Callback for when the destination treeview selection changes */
488 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
490 PsppireSelector *selector = data;
492 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
494 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
498 /* Callback for source deselection, when the dest is GtkEntry */
500 de_select_selection_entry (PsppireSelector *selector)
502 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
506 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
508 /* Callback for source deselection, when the dest is PsppireMeansLayer */
510 de_select_selection_means_layer (PsppireSelector *selector)
512 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
513 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
514 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
516 GtkTreeModel *model = psppire_means_layer_get_model (ml);
518 g_return_if_fail (selector->select_items);
520 de_select_tree_model (selection, model);
523 /* Callback for source deselection, when the dest is GtkTreeView */
525 de_select_selection_tree_view (PsppireSelector *selector)
527 GtkTreeSelection* selection =
528 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->dest));
530 GtkTreeModel *model =
531 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
533 g_return_if_fail (selector->select_items);
535 de_select_tree_model (selection, model);
539 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
543 GList *selected_rows =
544 gtk_tree_selection_get_selected_rows (selection, NULL);
546 /* Convert paths to RowRefs */
547 for (item = g_list_first (selected_rows);
549 item = g_list_next (item))
551 GtkTreeRowReference* rowref;
552 GtkTreePath *path = item->data;
554 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
556 item->data = rowref ;
557 gtk_tree_path_free (path);
560 /* Remove each selected row from the dest widget */
561 for (item = g_list_first (selected_rows);
563 item = g_list_next (item))
566 GtkTreeRowReference *rr = item->data;
568 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
570 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
572 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
574 gtk_tree_path_free (path);
577 /* Delete list of RowRefs and its contents */
578 g_list_foreach (selected_rows, (GFunc) (void (*)(void)) gtk_tree_row_reference_free, NULL);
579 g_list_free (selected_rows);
583 /* Callback which causes the filter to be refiltered.
584 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
588 refilter (PsppireSelector *selector)
590 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
591 if (GTK_IS_TREE_MODEL_FILTER (model))
592 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
596 /* Removes something from the DEST widget */
598 de_select_selection (PsppireSelector *selector)
600 selector->selecting = TRUE;
602 if (GTK_IS_TREE_VIEW (selector->dest))
603 de_select_selection_tree_view (selector);
605 else if (GTK_IS_ENTRY (selector->dest))
606 de_select_selection_entry (selector);
608 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
609 de_select_selection_means_layer (selector);
612 g_assert_not_reached ();
614 selector->selecting = FALSE;
618 g_signal_emit (selector, signals [DE_SELECTED], 0);
622 /* Puts something into the DEST widget */
624 select_selection (PsppireSelector *selector)
627 GtkTreeSelection* selection =
628 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
630 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
632 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
634 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
636 g_return_if_fail (selector->select_items);
638 if (selector->allow_selection &&
639 ! selector->allow_selection (selector->source, selector->dest))
642 selector->selecting = TRUE;
644 for (item = g_list_first (selected_rows);
646 item = g_list_next (item))
648 GtkTreeIter child_iter;
650 GtkTreePath *path = item->data;
652 g_return_if_fail (model);
654 gtk_tree_model_get_iter (model, &iter, path);
656 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
658 selector->select_items (child_iter,
661 selector->select_user_data
665 g_list_foreach (selected_rows, (GFunc) (void (*)(void)) gtk_tree_path_free, NULL);
666 g_list_free (selected_rows);
670 g_signal_emit (selector, signals [SELECTED], 0);
672 selector->selecting = FALSE;
675 /* Callback for when the selector button is clicked,
676 or other event which causes the selector's action to occur.
679 on_click (GtkButton *b)
681 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
683 switch (selector->direction)
685 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
686 select_selection (selector);
688 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
689 de_select_selection (selector);
692 g_assert_not_reached ();
696 if (GTK_BUTTON_CLASS (parent_class)->clicked)
697 GTK_BUTTON_CLASS (parent_class)->clicked (b);
701 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
703 gboolean result = FALSE;
704 GtkTreeIter source_iter;
705 GtkTreeModel *source_model;
708 if (GTK_IS_TREE_MODEL_FILTER (model))
710 source_model = gtk_tree_model_filter_get_model
711 (GTK_TREE_MODEL_FILTER (model));
713 gtk_tree_model_filter_convert_iter_to_child_iter
714 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
718 source_model = model;
722 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
724 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
727 g_value_unset (&value);
734 /* Visibility function for items in the SOURCE widget.
735 Returns TRUE iff *all* the selectors for which SOURCE is associated
738 is_source_item_visible (GtkTreeModel *childmodel,
739 GtkTreeIter *iter, gpointer data)
741 PsppireSelector *selector = data;
742 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
746 list = g_hash_table_lookup (class->source_hash, selector->source);
750 PsppireSelector *selector = list->data;
752 if (selector->filter && selector->filter (childmodel, iter, selector))
762 /* set the source widget to SOURCE */
764 set_tree_view_source (PsppireSelector *selector)
768 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
770 if (! (list = g_hash_table_lookup (class->source_hash, selector->source)))
772 /* Base case: This widget is currently not the source of
773 any selector. Create a hash entry and make this selector
774 the first selector in the list */
776 list = g_list_append (list, selector);
777 g_hash_table_insert (class->source_hash, selector->source, list);
779 /* Save the list item so that it can be removed later */
780 selector->source_litem = list;
783 { /* Append this selector to the list and push the <source,list>
784 pair onto the hash table */
786 if (NULL == g_list_find (list, selector))
788 if (selector->primary_requested)
790 list = g_list_prepend (list, selector);
791 selector->source_litem = list;
795 list = g_list_append (list, selector);
796 selector->source_litem = g_list_last (list);
798 g_hash_table_replace (class->source_hash, selector->source, list);
805 /* This function is a callback which occurs when the
806 SOURCE's model has changed */
811 PsppireSelector *selector
814 GtkTreeModel *model = gtk_tree_view_get_model (source);
816 g_assert (source == GTK_TREE_VIEW (selector->source));
818 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
823 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
825 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
827 gtk_tree_view_set_model (source, new_model);
829 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
830 is_source_item_visible,
834 g_signal_connect_swapped (new_model,
836 G_CALLBACK (on_row_deleted), selector);
838 g_signal_connect_swapped (new_model,
840 G_CALLBACK (on_row_inserted), selector);
842 g_object_unref (new_model);
849 Callback for when the destination treeview's data changes
852 on_dest_data_change (GtkTreeModel *tree_model,
857 PsppireSelector *selector = user_data;
859 if (selector->selecting) return;
866 on_dest_data_delete (GtkTreeModel *tree_model,
870 PsppireSelector *selector = user_data;
872 if (selector->selecting) return;
879 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
881 g_signal_handlers_disconnect_by_data (sel, selector);
885 on_dest_model_changed (PsppireSelector *selector)
887 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
892 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
895 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
898 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
900 if (selector->selecting) return;
905 /* Set the destination widget to DEST */
907 set_tree_view_dest (PsppireSelector *selector,
910 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
913 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
915 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
918 on_dest_model_changed (selector);
919 g_signal_connect_swapped (dest, "notify::model",
920 G_CALLBACK (on_dest_model_changed), selector);
924 set_layer_dest (PsppireSelector *selector,
925 PsppireMeansLayer *dest)
927 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
929 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
932 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
937 /* Callback for when the DEST GtkEntry is selected (clicked) */
939 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
941 PsppireSelector * selector = data;
943 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
944 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
951 /* Set DEST to be the destination GtkEntry widget */
953 set_entry_dest (PsppireSelector *selector,
956 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
959 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
962 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
965 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
972 set_default_filter (PsppireSelector *selector)
974 if (selector->filter == NULL)
976 if (GTK_IS_TREE_VIEW (selector->dest))
977 selector->filter = is_item_in_dest;
983 psppire_selector_update_subjects (PsppireSelector *selector)
985 if (NULL == selector->dest)
988 set_default_filter (selector);
990 if (NULL == selector->source)
993 if (GTK_IS_TREE_VIEW (selector->source))
995 set_tree_view_source (selector);
997 g_signal_connect (selector->source, "notify::model",
998 G_CALLBACK (update_model), selector);
1000 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1003 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1005 if (NULL == selector->dest)
1007 else if (GTK_IS_TREE_VIEW (selector->dest))
1009 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1011 else if (GTK_IS_ENTRY (selector->dest))
1013 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1015 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1017 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1019 else if (GTK_IS_TEXT_VIEW (selector->dest))
1021 /* Nothing to be done */
1024 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1027 if (PSPPIRE_IS_DICT_VIEW (selector->source) && selector->select_items == NULL)
1029 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1030 GType type = G_OBJECT_TYPE (selector->dest);
1032 SelectItemsFunc *func =
1033 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1036 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1043 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1045 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1047 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1049 g_type_class_unref (class);
1055 /* Set FILTER_FUNC for this selector */
1057 psppire_selector_set_filter_func (PsppireSelector *selector,
1058 FilterItemsFunc *filter_func)
1060 selector->filter = filter_func ;
1064 /* Set SELECT_FUNC for this selector */
1066 psppire_selector_set_select_func (PsppireSelector *selector,
1067 SelectItemsFunc *select_func,
1070 selector->select_user_data = user_data;
1071 selector->select_items = select_func;
1077 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1079 selector->allow_selection = allow;
1084 psppire_selector_orientation_get_type (void)
1086 static GType etype = 0;
1089 static const GEnumValue values[] =
1091 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1092 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1093 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1094 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1097 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);