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;
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);
217 psppire_selector_set_property (GObject *object,
222 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
226 case PROP_ORIENTATION:
227 selector->orientation = g_value_get_enum (value);
228 set_direction (selector, selector->direction);
231 selector->primary_requested = TRUE;
232 psppire_selector_update_subjects (selector);
234 case PROP_SOURCE_WIDGET:
235 selector->source = g_value_dup_object (value);
236 psppire_selector_update_subjects (selector);
238 case PROP_DEST_WIDGET:
239 selector->dest = g_value_dup_object (value);
240 psppire_selector_update_subjects (selector);
243 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
250 psppire_selector_get_property (GObject *object,
255 PsppireSelector *selector = PSPPIRE_SELECTOR (object);
259 case PROP_ORIENTATION:
260 g_value_set_enum (value, selector->orientation);
262 case PROP_SOURCE_WIDGET:
263 g_value_take_object (value, selector->source);
265 case PROP_DEST_WIDGET:
266 g_value_take_object (value, selector->dest);
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275 psppire_selector_class_init (PsppireSelectorClass *class)
277 GObjectClass *object_class = G_OBJECT_CLASS (class);
278 GtkButtonClass *button_class = GTK_BUTTON_CLASS (class);
279 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
280 GParamSpec *orientation_spec =
281 g_param_spec_enum ("orientation",
283 "Where the selector is relative to its subjects",
284 PSPPIRE_TYPE_SELECTOR_ORIENTATION,
285 PSPPIRE_SELECT_SOURCE_BEFORE_DEST /* default value */,
286 G_PARAM_CONSTRUCT_ONLY |G_PARAM_READWRITE);
289 /* Meaningfull only if more than one selector shares this selectors source */
290 GParamSpec *primary_spec =
291 g_param_spec_boolean ("primary",
293 "Whether this selector should be the primary selector for the source",
297 GParamSpec *source_widget_spec =
298 g_param_spec_object ("source-widget",
300 "The widget to be used as the source for this selector",
304 GParamSpec *dest_widget_spec =
305 g_param_spec_object ("dest-widget",
306 "Destination Widget",
307 "The widget to be used as the destination for this selector",
312 button_class->clicked = on_click;
313 widget_class->realize = on_realize;
316 object_class->set_property = psppire_selector_set_property;
317 object_class->get_property = psppire_selector_get_property;
319 g_object_class_install_property (object_class,
323 g_object_class_install_property (object_class,
327 g_object_class_install_property (object_class,
331 g_object_class_install_property (object_class,
335 parent_class = g_type_class_peek_parent (class);
338 g_signal_new ("selected",
339 G_TYPE_FROM_CLASS (class),
343 g_cclosure_marshal_VOID__VOID,
347 signals [DE_SELECTED] =
348 g_signal_new ("de-selected",
349 G_TYPE_FROM_CLASS (class),
353 g_cclosure_marshal_VOID__VOID,
357 object_class->dispose = psppire_selector_dispose;
359 class->source_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
360 class->default_selection_funcs = g_hash_table_new (g_direct_hash, g_direct_equal);
364 /* Callback for when the source treeview is activated (double clicked) */
366 on_row_activate (GtkTreeView *tree_view,
368 GtkTreeViewColumn *column,
371 on_click (GTK_BUTTON (data));
374 /* Callback for when the source selection changes */
376 on_source_select (GtkTreeSelection *treeselection, gpointer data)
378 PsppireSelector *selector = data;
380 set_direction (selector, PSPPIRE_SELECTOR_SOURCE_TO_DEST);
382 if ( selector->allow_selection )
384 gtk_widget_set_sensitive (GTK_WIDGET (selector),
385 selector->allow_selection (selector->source, selector->dest));
387 else if ( GTK_IS_ENTRY (selector->dest) )
389 gtk_widget_set_sensitive (GTK_WIDGET (selector),
390 gtk_tree_selection_count_selected_rows
391 (treeselection) <= 1 );
397 on_realize (GtkWidget *w)
399 PsppireSelector *selector = PSPPIRE_SELECTOR (w);
400 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
401 GtkTreeSelection* selection ;
403 GList *list = g_hash_table_lookup (class->source_hash, selector->source);
405 if (GTK_WIDGET_CLASS (parent_class)->realize)
406 GTK_WIDGET_CLASS (parent_class)->realize (w);
411 if ( g_list_first (list)->data == selector)
413 if ( selector->row_activate_id )
414 g_signal_handler_disconnect (selector->source, selector->row_activate_id);
416 selector->row_activate_id =
417 g_signal_connect (selector->source, "row-activated", G_CALLBACK (on_row_activate), selector);
420 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source));
422 if ( selector->source_select_id )
423 g_signal_handler_disconnect (selection, selector->source_select_id);
425 selector->source_select_id =
426 g_signal_connect (selection, "changed", G_CALLBACK (on_source_select), selector);
431 psppire_selector_init (PsppireSelector *selector)
433 selector->primary_requested = FALSE;
434 selector->select_user_data = NULL;
435 selector->select_items = NULL;
436 selector->allow_selection = NULL;
437 selector->filter = NULL;
439 selector->arrow = gtk_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
441 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
443 gtk_widget_show (selector->arrow);
445 selector->selecting = FALSE;
447 selector->source = NULL;
448 selector->dest = NULL;
449 selector->dispose_has_run = FALSE;
452 selector->row_activate_id = 0;
453 selector->source_select_id = 0;
455 selector->source_litem = NULL;
460 psppire_selector_new (void)
462 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
467 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
469 selector->direction = d;
471 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
473 if ( d == PSPPIRE_SELECTOR_SOURCE_TO_DEST )
475 switch (selector->orientation)
477 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
478 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
480 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
481 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
483 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
484 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
486 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
487 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
490 g_assert_not_reached ();
496 switch (selector->orientation)
498 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
499 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
501 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
502 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
504 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
505 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
507 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
508 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
511 g_assert_not_reached ();
517 /* Callback for when the destination treeview selection changes */
519 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
521 PsppireSelector *selector = data;
523 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
525 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
529 /* Callback for source deselection, when the dest is GtkEntry */
531 de_select_selection_entry (PsppireSelector *selector)
533 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
537 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
539 /* Callback for source deselection, when the dest is PsppireMeansLayer */
541 de_select_selection_means_layer (PsppireSelector *selector)
543 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
544 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
545 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
547 GtkTreeModel *model = psppire_means_layer_get_model (ml);
549 g_return_if_fail (selector->select_items);
551 de_select_tree_model (selection, model);
554 /* Callback for source deselection, when the dest is GtkTreeView */
556 de_select_selection_tree_view (PsppireSelector *selector)
558 GtkTreeSelection* selection =
559 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->dest));
561 GtkTreeModel *model =
562 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
564 g_return_if_fail (selector->select_items);
566 de_select_tree_model (selection, model);
570 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
574 GList *selected_rows =
575 gtk_tree_selection_get_selected_rows (selection, NULL);
577 /* Convert paths to RowRefs */
578 for (item = g_list_first (selected_rows);
580 item = g_list_next (item))
582 GtkTreeRowReference* rowref;
583 GtkTreePath *path = item->data;
585 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
587 item->data = rowref ;
588 gtk_tree_path_free (path);
591 /* Remove each selected row from the dest widget */
592 for (item = g_list_first (selected_rows);
594 item = g_list_next (item))
597 GtkTreeRowReference *rr = item->data;
599 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
601 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
603 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
605 gtk_tree_path_free (path);
608 /* Delete list of RowRefs and its contents */
609 g_list_foreach (selected_rows, (GFunc) gtk_tree_row_reference_free, NULL);
610 g_list_free (selected_rows);
614 /* Callback which causes the filter to be refiltered.
615 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
619 refilter (PsppireSelector *selector)
621 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
622 if (GTK_IS_TREE_MODEL_FILTER (model))
623 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
627 /* Removes something from the DEST widget */
629 de_select_selection (PsppireSelector *selector)
631 selector->selecting = TRUE;
633 if ( GTK_IS_TREE_VIEW (selector->dest ) )
634 de_select_selection_tree_view (selector);
636 else if ( GTK_IS_ENTRY (selector->dest))
637 de_select_selection_entry (selector);
639 else if ( PSPPIRE_IS_MEANS_LAYER (selector->dest))
640 de_select_selection_means_layer (selector);
643 g_assert_not_reached ();
645 selector->selecting = FALSE;
649 g_signal_emit (selector, signals [DE_SELECTED], 0);
653 /* Puts something into the DEST widget */
655 select_selection (PsppireSelector *selector)
658 GtkTreeSelection* selection =
659 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->source));
661 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
663 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
665 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
667 g_return_if_fail (selector->select_items);
669 if (selector->allow_selection &&
670 ! selector->allow_selection (selector->source, selector->dest))
673 selector->selecting = TRUE;
675 for (item = g_list_first (selected_rows);
677 item = g_list_next (item))
679 GtkTreeIter child_iter;
681 GtkTreePath *path = item->data;
683 g_return_if_fail (model);
685 gtk_tree_model_get_iter (model, &iter, path);
687 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
689 selector->select_items (child_iter,
692 selector->select_user_data
696 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
697 g_list_free (selected_rows);
701 g_signal_emit (selector, signals [SELECTED], 0);
703 selector->selecting = FALSE;
706 /* Callback for when the selector button is clicked,
707 or other event which causes the selector's action to occur.
710 on_click (GtkButton *b)
712 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
714 switch (selector->direction)
716 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
717 select_selection (selector);
719 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
720 de_select_selection (selector);
723 g_assert_not_reached ();
727 if (GTK_BUTTON_CLASS (parent_class)->clicked)
728 GTK_BUTTON_CLASS (parent_class)->clicked (b);
732 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
734 gboolean result = FALSE;
735 GtkTreeIter source_iter;
736 GtkTreeModel *source_model;
739 if (GTK_IS_TREE_MODEL_FILTER (model))
741 source_model = gtk_tree_model_filter_get_model
742 (GTK_TREE_MODEL_FILTER (model));
744 gtk_tree_model_filter_convert_iter_to_child_iter
745 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
749 source_model = model;
753 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
755 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
758 g_value_unset (&value);
765 /* Visibility function for items in the SOURCE widget.
766 Returns TRUE iff *all* the selectors for which SOURCE is associated
769 is_source_item_visible (GtkTreeModel *childmodel,
770 GtkTreeIter *iter, gpointer data)
772 PsppireSelector *selector = data;
773 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
777 list = g_hash_table_lookup (class->source_hash, selector->source);
781 PsppireSelector *selector = list->data;
783 if ( selector->filter && selector->filter (childmodel, iter, selector))
793 /* set the source widget to SOURCE */
795 set_tree_view_source (PsppireSelector *selector)
799 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
801 if ( ! (list = g_hash_table_lookup (class->source_hash, selector->source)))
803 /* Base case: This widget is currently not the source of
804 any selector. Create a hash entry and make this selector
805 the first selector in the list */
807 list = g_list_append (list, selector);
808 g_hash_table_insert (class->source_hash, selector->source, list);
810 /* Save the list item so that it can be removed later */
811 selector->source_litem = list;
814 { /* Append this selector to the list and push the <source,list>
815 pair onto the hash table */
817 if ( NULL == g_list_find (list, selector) )
819 if ( selector->primary_requested )
821 list = g_list_prepend (list, selector);
822 selector->source_litem = list;
826 list = g_list_append (list, selector);
827 selector->source_litem = g_list_last (list);
829 g_hash_table_replace (class->source_hash, selector->source, list);
836 /* This function is a callback which occurs when the
837 SOURCE's model has changed */
842 PsppireSelector *selector
845 GtkTreeModel *model = gtk_tree_view_get_model (source);
847 g_assert (source == GTK_TREE_VIEW (selector->source));
849 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
854 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
856 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
858 gtk_tree_view_set_model (source, new_model);
860 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
861 is_source_item_visible,
865 g_signal_connect_swapped (new_model,
867 G_CALLBACK (on_row_deleted), selector);
869 g_signal_connect_swapped (new_model,
871 G_CALLBACK (on_row_inserted), selector);
873 g_object_unref (new_model);
880 Callback for when the destination treeview's data changes
883 on_dest_data_change (GtkTreeModel *tree_model,
888 PsppireSelector *selector = user_data;
890 if ( selector->selecting) return;
897 on_dest_data_delete (GtkTreeModel *tree_model,
901 PsppireSelector *selector = user_data;
903 if ( selector->selecting ) return;
910 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
912 g_signal_handlers_disconnect_by_data (sel, selector);
916 on_dest_model_changed (PsppireSelector *selector)
918 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
923 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
926 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
929 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
931 if ( selector->selecting ) return;
936 /* Set the destination widget to DEST */
938 set_tree_view_dest (PsppireSelector *selector,
941 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
944 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
946 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
949 on_dest_model_changed (selector);
950 g_signal_connect_swapped (dest, "notify::model",
951 G_CALLBACK (on_dest_model_changed), selector);
955 set_layer_dest (PsppireSelector *selector,
956 PsppireMeansLayer *dest)
958 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
960 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
963 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
968 /* Callback for when the DEST GtkEntry is selected (clicked) */
970 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
972 PsppireSelector * selector = data;
974 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
975 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
982 /* Set DEST to be the destination GtkEntry widget */
984 set_entry_dest (PsppireSelector *selector,
987 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
990 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
993 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
996 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
1003 set_default_filter (PsppireSelector *selector)
1005 if ( selector->filter == NULL)
1007 if (GTK_IS_TREE_VIEW (selector->dest))
1008 selector->filter = is_item_in_dest;
1014 psppire_selector_update_subjects (PsppireSelector *selector)
1016 if ( NULL == selector->dest )
1019 set_default_filter (selector);
1021 if ( NULL == selector->source )
1024 if ( GTK_IS_TREE_VIEW (selector->source))
1026 set_tree_view_source (selector);
1028 g_signal_connect (selector->source, "notify::model",
1029 G_CALLBACK (update_model), selector);
1031 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1034 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1036 if ( NULL == selector->dest)
1038 else if ( GTK_IS_TREE_VIEW (selector->dest))
1040 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1042 else if ( GTK_IS_ENTRY (selector->dest))
1044 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1046 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1048 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1050 else if (GTK_IS_TEXT_VIEW (selector->dest))
1052 /* Nothing to be done */
1055 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1058 /* FIXME: Remove this dependency */
1059 if ( PSPPIRE_IS_DICT_VIEW (selector->source) )
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);