1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2009, 2010, 2012, 2015 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 This module provides a widget, PsppireSelector derived from
22 It contains a GtkImage (to indicate the arrow), and is used for selecting objects from a
23 GtkTreeView and putting them into a destination widget (often
24 another GtkTreeView). Typically this is used in psppire for
25 selecting variables, thus:
28 +----------------------------------------------------------+
30 | Source Widget Dest Widget |
31 | +----------------+ +----------------+ |
32 | | Variable0 | | Variable2 | |
47 | +----------------+ +----------------+ |
49 +----------------------------------------------------------+
51 The Source Widget is always a GtkTreeView. The Dest Widget may be a
52 GtkTreeView or a GtkEntry (other destination widgets may be
53 supported in the future).
55 Widgets may be source to more than one PsppireSelector.
61 #include "psppire-dictview.h"
62 #include "psppire-dict.h"
63 #include "psppire-select-dest.h"
64 #include "psppire-means-layer.h"
68 #include "psppire-selector.h"
70 static void psppire_selector_class_init (PsppireSelectorClass *class);
71 static void psppire_selector_init (PsppireSelector *selector);
74 static void set_direction (PsppireSelector *, enum psppire_selector_dir);
77 enum {SELECTED, /* Emitted when an item is inserted into dest */
78 DE_SELECTED, /* Emitted when an item is removed from dest */
81 static guint signals [n_SIGNALS];
83 /* Callback for when an item disappears from the source list.
84 By implication, this means that the item has been inserted into the
88 on_row_deleted (PsppireSelector *selector)
90 g_signal_emit (selector, signals [SELECTED], 0);
93 /* Callback for when a new item appears in the source list.
94 By implication, this means that an item has been deleted from the
98 on_row_inserted (PsppireSelector *selector)
100 g_signal_emit (selector, signals [DE_SELECTED], 0);
105 psppire_selector_get_type (void)
107 static GType psppire_selector_type = 0;
109 if (!psppire_selector_type)
111 static const GTypeInfo psppire_selector_info =
113 sizeof (PsppireSelectorClass),
114 (GBaseInitFunc) NULL,
115 (GBaseFinalizeFunc) NULL,
116 (GClassInitFunc)psppire_selector_class_init,
117 (GClassFinalizeFunc) NULL,
119 sizeof (PsppireSelector),
121 (GInstanceInitFunc) psppire_selector_init,
124 psppire_selector_type =
125 g_type_register_static (GTK_TYPE_BUTTON, "PsppireSelector",
126 &psppire_selector_info, 0);
129 return psppire_selector_type;
132 static GObjectClass * parent_class = NULL;
137 dump_hash_entry (gpointer key, gpointer value, gpointer obj)
140 g_print ("Source %p; ", key);
142 for (item = g_list_first (value);
144 item = g_list_next (item))
146 g_print ("%p(%p) ", item->data, item);
151 /* This function is for debugging only */
153 psppire_selector_show_map (PsppireSelector *obj)
155 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
157 g_print ("%s %p\n", __FUNCTION__, obj);
158 g_hash_table_foreach (class->source_hash, dump_hash_entry, obj);
164 psppire_selector_dispose (GObject *obj)
166 PsppireSelector *sel = PSPPIRE_SELECTOR (obj);
167 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
170 if (sel->dispose_has_run)
173 /* Make sure dispose does not run twice. */
174 sel->dispose_has_run = TRUE;
176 /* Remove ourself from the source map. If we are the only entry for this source
177 widget, that will result in an empty list for the source. In that case, we
178 remove the entire entry too. */
179 if ((list = g_hash_table_lookup (class->source_hash, sel->source)))
181 GList *newlist = g_list_remove_link (list, sel->source_litem);
182 g_list_free (sel->source_litem);
184 g_hash_table_remove (class->source_hash, sel->source);
186 g_hash_table_replace (class->source_hash, sel->source, newlist);
188 sel->source_litem = NULL;
192 g_object_unref (sel->dest);
195 g_object_unref (sel->source);
197 /* Chain up to the parent class */
198 G_OBJECT_CLASS (parent_class)->dispose (obj);
213 static void on_click (GtkButton *b);
214 static void on_realize (GtkWidget *selector);
218 psppire_selector_set_property (GObject *object,
223 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
227 case PROP_ORIENTATION:
228 selector->orientation = g_value_get_enum (value);
229 set_direction (selector, selector->direction);
232 selector->primary_requested = TRUE;
233 psppire_selector_update_subjects (selector);
235 case PROP_SOURCE_WIDGET:
236 selector->source = g_value_dup_object (value);
237 psppire_selector_update_subjects (selector);
239 case PROP_DEST_WIDGET:
240 selector->dest = g_value_dup_object (value);
241 psppire_selector_update_subjects (selector);
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
251 psppire_selector_get_property (GObject *object,
256 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
260 case PROP_ORIENTATION:
261 g_value_set_enum (value, selector->orientation);
263 case PROP_SOURCE_WIDGET:
264 g_value_take_object (value, selector->source);
266 case PROP_DEST_WIDGET:
267 g_value_take_object (value, selector->dest);
270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276 psppire_selector_class_init (PsppireSelectorClass *class)
278 GObjectClass *object_class = G_OBJECT_CLASS (class);
279 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
280 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
281 GParamSpec *orientation_spec =
282 g_param_spec_enum ("orientation",
284 "Where the selector is relative to its subjects",
285 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
286 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
287 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
290 /* Meaningfull only if more than one selector shares this selectors source */
291 GParamSpec *primary_spec =
292 g_param_spec_boolean ("primary",
294 "Whether this selector should be the primary selector for the source",
298 GParamSpec *source_widget_spec =
299 g_param_spec_object ("source-widget",
301 "The widget to be used as the source for this selector",
305 GParamSpec *dest_widget_spec =
306 g_param_spec_object ("dest-widget",
307 "Destination Widget",
308 "The widget to be used as the destination for this selector",
313 button_class->clicked = on_click;
314 widget_class->realize = on_realize;
317 object_class->set_property = psppire_selector_set_property;
318 object_class->get_property = psppire_selector_get_property;
320 g_object_class_install_property (object_class,
324 g_object_class_install_property (object_class,
328 g_object_class_install_property (object_class,
332 g_object_class_install_property (object_class,
336 parent_class = g_type_class_peek_parent (class);
339 g_signal_new ("selected",
340 G_TYPE_FROM_CLASS (class),
344 g_cclosure_marshal_VOID__VOID,
348 signals [DE_SELECTED] =
349 g_signal_new ("de-selected",
350 G_TYPE_FROM_CLASS (class),
354 g_cclosure_marshal_VOID__VOID,
358 object_class->dispose = psppire_selector_dispose;
360 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
361 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
365 /* Callback for when the source treeview is activated (double clicked) */
367 on_row_activate (GtkTreeView *tree_view,
369 GtkTreeViewColumn *column,
372 on_click (GTK_BUTTON (data));
375 /* Callback for when the source selection changes */
377 on_source_select (GtkTreeSelection *treeselection, gpointer data)
379 PsppireSelector *selector = data;
381 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
383 if (selector->allow_selection)
385 gtk_widget_set_sensitive (GTK_WIDGET (selector),
386 selector->allow_selection (selector->source, selector->dest));
388 else if (GTK_IS_ENTRY (selector->dest))
390 gtk_widget_set_sensitive (GTK_WIDGET (selector),
391 gtk_tree_selection_count_selected_rows
392 (treeselection) <= 1);
398 on_realize (GtkWidget *w)
400 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
401 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
402 GtkTreeSelection* selection ;
404 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
406 if (GTK_WIDGET_CLASS (parent_class)->realize)
407 GTK_WIDGET_CLASS (parent_class)->realize (w);
412 if (g_list_first (list)->data == selector)
414 if (selector->row_activate_id)
415 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
417 selector->row_activate_id =
418 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
421 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
423 if (selector->source_select_id)
424 g_signal_handler_disconnect (selection, selector->source_select_id);
426 selector->source_select_id =
427 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
432 psppire_selector_init (PsppireSelector *selector)
434 selector->primary_requested = FALSE;
435 selector->select_user_data = NULL;
436 selector->select_items = NULL;
437 selector->allow_selection = NULL;
438 selector->filter = NULL;
440 selector->arrow = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
442 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
444 gtk_widget_show (selector->arrow);
446 selector->selecting = FALSE;
448 selector->source = NULL;
449 selector->dest = NULL;
450 selector->dispose_has_run = FALSE;
453 selector->row_activate_id = 0;
454 selector->source_select_id = 0;
456 selector->source_litem = NULL;
461 psppire_selector_new (void)
463 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
468 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
470 selector->direction = d;
472 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
474 if (d == PSPPIRE_SELECTOR_SOURCE_TO_DEST)
476 switch (selector->orientation)
478 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
479 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
481 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
482 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
484 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
485 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
487 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
488 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
491 g_assert_not_reached ();
497 switch (selector->orientation)
499 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
500 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
502 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
503 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
505 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
506 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
508 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
509 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
512 g_assert_not_reached ();
518 /* Callback for when the destination treeview selection changes */
520 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
522 PsppireSelector *selector = data;
524 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
526 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
530 /* Callback for source deselection, when the dest is GtkEntry */
532 de_select_selection_entry (PsppireSelector *selector)
534 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
538 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
540 /* Callback for source deselection, when the dest is PsppireMeansLayer */
542 de_select_selection_means_layer (PsppireSelector *selector)
544 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
545 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
546 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
548 GtkTreeModel *model = psppire_means_layer_get_model (ml);
550 g_return_if_fail (selector->select_items);
552 de_select_tree_model (selection, model);
555 /* Callback for source deselection, when the dest is GtkTreeView */
557 de_select_selection_tree_view (PsppireSelector *selector)
559 GtkTreeSelection* selection =
560 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->dest));
562 GtkTreeModel *model =
563 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
565 g_return_if_fail (selector->select_items);
567 de_select_tree_model (selection, model);
571 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
575 GList *selected_rows =
576 gtk_tree_selection_get_selected_rows (selection, NULL);
578 /* Convert paths to RowRefs */
579 for (item = g_list_first (selected_rows);
581 item = g_list_next (item))
583 GtkTreeRowReference* rowref;
584 GtkTreePath *path = item->data;
586 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
588 item->data = rowref ;
589 gtk_tree_path_free (path);
592 /* Remove each selected row from the dest widget */
593 for (item = g_list_first (selected_rows);
595 item = g_list_next (item))
598 GtkTreeRowReference *rr = item->data;
600 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
602 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
604 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
606 gtk_tree_path_free (path);
609 /* Delete list of RowRefs and its contents */
610 g_list_foreach (selected_rows, (GFunc) gtk_tree_row_reference_free, NULL);
611 g_list_free (selected_rows);
615 /* Callback which causes the filter to be refiltered.
616 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
620 refilter (PsppireSelector *selector)
622 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
623 if (GTK_IS_TREE_MODEL_FILTER (model))
624 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
628 /* Removes something from the DEST widget */
630 de_select_selection (PsppireSelector *selector)
632 selector->selecting = TRUE;
634 if (GTK_IS_TREE_VIEW (selector->dest))
635 de_select_selection_tree_view (selector);
637 else if (GTK_IS_ENTRY (selector->dest))
638 de_select_selection_entry (selector);
640 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
641 de_select_selection_means_layer (selector);
644 g_assert_not_reached ();
646 selector->selecting = FALSE;
650 g_signal_emit (selector, signals [DE_SELECTED], 0);
654 /* Puts something into the DEST widget */
656 select_selection (PsppireSelector *selector)
659 GtkTreeSelection* selection =
660 gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
662 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
664 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
666 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
668 g_return_if_fail (selector->select_items);
670 if (selector->allow_selection &&
671 ! selector->allow_selection (selector->source, selector->dest))
674 selector->selecting = TRUE;
676 for (item = g_list_first (selected_rows);
678 item = g_list_next (item))
680 GtkTreeIter child_iter;
682 GtkTreePath *path = item->data;
684 g_return_if_fail (model);
686 gtk_tree_model_get_iter (model, &iter, path);
688 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
690 selector->select_items (child_iter,
693 selector->select_user_data
697 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
698 g_list_free (selected_rows);
702 g_signal_emit (selector, signals [SELECTED], 0);
704 selector->selecting = FALSE;
707 /* Callback for when the selector button is clicked,
708 or other event which causes the selector's action to occur.
711 on_click (GtkButton *b)
713 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
715 switch (selector->direction)
717 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
718 select_selection (selector);
720 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
721 de_select_selection (selector);
724 g_assert_not_reached ();
728 if (GTK_BUTTON_CLASS (parent_class)->clicked)
729 GTK_BUTTON_CLASS (parent_class)->clicked (b);
733 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
735 gboolean result = FALSE;
736 GtkTreeIter source_iter;
737 GtkTreeModel *source_model;
740 if (GTK_IS_TREE_MODEL_FILTER (model))
742 source_model = gtk_tree_model_filter_get_model
743 (GTK_TREE_MODEL_FILTER (model));
745 gtk_tree_model_filter_convert_iter_to_child_iter
746 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
750 source_model = model;
754 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
756 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
759 g_value_unset (&value);
766 /* Visibility function for items in the SOURCE widget.
767 Returns TRUE iff *all* the selectors for which SOURCE is associated
770 is_source_item_visible (GtkTreeModel *childmodel,
771 GtkTreeIter *iter, gpointer data)
773 PsppireSelector *selector = data;
774 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
778 list = g_hash_table_lookup (class->source_hash, selector->source);
782 PsppireSelector *selector = list->data;
784 if (selector->filter && selector->filter (childmodel, iter, selector))
794 /* set the source widget to SOURCE */
796 set_tree_view_source (PsppireSelector *selector)
800 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
802 if (! (list = g_hash_table_lookup (class->source_hash, selector->source)))
804 /* Base case: This widget is currently not the source of
805 any selector. Create a hash entry and make this selector
806 the first selector in the list */
808 list = g_list_append (list, selector);
809 g_hash_table_insert (class->source_hash, selector->source, list);
811 /* Save the list item so that it can be removed later */
812 selector->source_litem = list;
815 { /* Append this selector to the list and push the <source,list>
816 pair onto the hash table */
818 if (NULL == g_list_find (list, selector))
820 if (selector->primary_requested)
822 list = g_list_prepend (list, selector);
823 selector->source_litem = list;
827 list = g_list_append (list, selector);
828 selector->source_litem = g_list_last (list);
830 g_hash_table_replace (class->source_hash, selector->source, list);
837 /* This function is a callback which occurs when the
838 SOURCE's model has changed */
843 PsppireSelector *selector
846 GtkTreeModel *model = gtk_tree_view_get_model (source);
848 g_assert (source == GTK_TREE_VIEW (selector->source));
850 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
855 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
857 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
859 gtk_tree_view_set_model (source, new_model);
861 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
862 is_source_item_visible,
866 g_signal_connect_swapped (new_model,
868 G_CALLBACK (on_row_deleted), selector);
870 g_signal_connect_swapped (new_model,
872 G_CALLBACK (on_row_inserted), selector);
874 g_object_unref (new_model);
881 Callback for when the destination treeview's data changes
884 on_dest_data_change (GtkTreeModel *tree_model,
889 PsppireSelector *selector = user_data;
891 if (selector->selecting) return;
898 on_dest_data_delete (GtkTreeModel *tree_model,
902 PsppireSelector *selector = user_data;
904 if (selector->selecting) return;
911 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
913 g_signal_handlers_disconnect_by_data (sel, selector);
917 on_dest_model_changed (PsppireSelector *selector)
919 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
924 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
927 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
930 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
932 if (selector->selecting) return;
937 /* Set the destination widget to DEST */
939 set_tree_view_dest (PsppireSelector *selector,
942 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
945 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
947 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
950 on_dest_model_changed (selector);
951 g_signal_connect_swapped (dest, "notify::model",
952 G_CALLBACK (on_dest_model_changed), selector);
956 set_layer_dest (PsppireSelector *selector,
957 PsppireMeansLayer *dest)
959 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
961 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
964 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
969 /* Callback for when the DEST GtkEntry is selected (clicked) */
971 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
973 PsppireSelector * selector = data;
975 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
976 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
983 /* Set DEST to be the destination GtkEntry widget */
985 set_entry_dest (PsppireSelector *selector,
988 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
991 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
994 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
997 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
1004 set_default_filter (PsppireSelector *selector)
1006 if (selector->filter == NULL)
1008 if (GTK_IS_TREE_VIEW (selector->dest))
1009 selector->filter = is_item_in_dest;
1015 psppire_selector_update_subjects (PsppireSelector *selector)
1017 if (NULL == selector->dest)
1020 set_default_filter (selector);
1022 if (NULL == selector->source)
1025 if (GTK_IS_TREE_VIEW (selector->source))
1027 set_tree_view_source (selector);
1029 g_signal_connect (selector->source, "notify::model",
1030 G_CALLBACK (update_model), selector);
1032 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1035 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1037 if (NULL == selector->dest)
1039 else if (GTK_IS_TREE_VIEW (selector->dest))
1041 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1043 else if (GTK_IS_ENTRY (selector->dest))
1045 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1047 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1049 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1051 else if (GTK_IS_TEXT_VIEW (selector->dest))
1053 /* Nothing to be done */
1056 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1059 if (PSPPIRE_IS_DICT_VIEW (selector->source) && selector->select_items == NULL)
1061 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1062 GType type = G_OBJECT_TYPE (selector->dest);
1064 SelectItemsFunc *func =
1065 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1068 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1075 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1077 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1079 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1081 g_type_class_unref (class);
1087 /* Set FILTER_FUNC for this selector */
1089 psppire_selector_set_filter_func (PsppireSelector *selector,
1090 FilterItemsFunc *filter_func)
1092 selector->filter = filter_func ;
1096 /* Set SELECT_FUNC for this selector */
1098 psppire_selector_set_select_func (PsppireSelector *selector,
1099 SelectItemsFunc *select_func,
1102 selector->select_user_data = user_data;
1103 selector->select_items = select_func;
1109 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1111 selector->allow_selection = allow;
1116 psppire_selector_orientation_get_type (void)
1118 static GType etype = 0;
1121 static const GEnumValue values[] =
1123 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1124 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1125 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1126 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1129 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);