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);
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_image_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
444 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
446 gtk_widget_show (selector->arrow);
448 selector->selecting = FALSE;
450 selector->source = NULL;
451 selector->dest = NULL;
452 selector->dispose_has_run = FALSE;
455 selector->row_activate_id = 0;
456 selector->source_select_id = 0;
458 selector->source_litem = NULL;
463 psppire_selector_new (void)
465 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
470 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
472 selector->direction = d;
474 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
476 if ( d == PSPPIRE_SELECTOR_SOURCE_TO_DEST )
478 switch (selector->orientation)
480 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
481 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
483 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
484 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
486 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
487 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
489 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
490 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
493 g_assert_not_reached ();
499 switch (selector->orientation)
501 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
502 g_object_set (selector->arrow, "icon-name", "pan-start-symbolic", NULL);
504 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
505 g_object_set (selector->arrow, "icon-name", "pan-end-symbolic", NULL);
507 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
508 g_object_set (selector->arrow, "icon-name", "pan-up-symbolic", NULL);
510 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
511 g_object_set (selector->arrow, "icon-name", "pan-down-symbolic", NULL);
514 g_assert_not_reached ();
520 /* Callback for when the destination treeview selection changes */
522 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
524 PsppireSelector *selector = data;
526 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
528 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
532 /* Callback for source deselection, when the dest is GtkEntry */
534 de_select_selection_entry (PsppireSelector *selector)
536 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
540 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
542 /* Callback for source deselection, when the dest is PsppireMeansLayer */
544 de_select_selection_means_layer (PsppireSelector *selector)
546 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
547 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
548 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
550 GtkTreeModel *model = psppire_means_layer_get_model (ml);
552 g_return_if_fail (selector->select_items);
554 de_select_tree_model (selection, model);
557 /* Callback for source deselection, when the dest is GtkTreeView */
559 de_select_selection_tree_view (PsppireSelector *selector)
561 GtkTreeSelection* selection =
562 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->dest));
564 GtkTreeModel *model =
565 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
567 g_return_if_fail (selector->select_items);
569 de_select_tree_model (selection, model);
573 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
577 GList *selected_rows =
578 gtk_tree_selection_get_selected_rows (selection, NULL);
580 /* Convert paths to RowRefs */
581 for (item = g_list_first (selected_rows);
583 item = g_list_next (item))
585 GtkTreeRowReference* rowref;
586 GtkTreePath *path = item->data;
588 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
590 item->data = rowref ;
591 gtk_tree_path_free (path);
594 /* Remove each selected row from the dest widget */
595 for (item = g_list_first (selected_rows);
597 item = g_list_next (item))
600 GtkTreeRowReference *rr = item->data;
602 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
604 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
606 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
608 gtk_tree_path_free (path);
611 /* Delete list of RowRefs and its contents */
612 g_list_foreach (selected_rows, (GFunc) gtk_tree_row_reference_free, NULL);
613 g_list_free (selected_rows);
617 /* Callback which causes the filter to be refiltered.
618 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
622 refilter (PsppireSelector *selector)
624 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
625 if (GTK_IS_TREE_MODEL_FILTER (model))
626 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
630 /* Removes something from the DEST widget */
632 de_select_selection (PsppireSelector *selector)
634 selector->selecting = TRUE;
636 if ( GTK_IS_TREE_VIEW (selector->dest ) )
637 de_select_selection_tree_view (selector);
639 else if ( GTK_IS_ENTRY (selector->dest))
640 de_select_selection_entry (selector);
642 else if ( PSPPIRE_IS_MEANS_LAYER (selector->dest))
643 de_select_selection_means_layer (selector);
646 g_assert_not_reached ();
648 selector->selecting = FALSE;
652 g_signal_emit (selector, signals [DE_SELECTED], 0);
656 /* Puts something into the DEST widget */
658 select_selection (PsppireSelector *selector)
661 GtkTreeSelection* selection =
662 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->source));
664 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
666 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
668 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
670 g_return_if_fail (selector->select_items);
672 if (selector->allow_selection &&
673 ! selector->allow_selection (selector->source, selector->dest))
676 selector->selecting = TRUE;
678 for (item = g_list_first (selected_rows);
680 item = g_list_next (item))
682 GtkTreeIter child_iter;
684 GtkTreePath *path = item->data;
686 g_return_if_fail (model);
688 gtk_tree_model_get_iter (model, &iter, path);
690 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
692 selector->select_items (child_iter,
695 selector->select_user_data
699 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
700 g_list_free (selected_rows);
704 g_signal_emit (selector, signals [SELECTED], 0);
706 selector->selecting = FALSE;
709 /* Callback for when the selector button is clicked,
710 or other event which causes the selector's action to occur.
713 on_click (GtkButton *b)
715 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
717 switch (selector->direction)
719 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
720 select_selection (selector);
722 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
723 de_select_selection (selector);
726 g_assert_not_reached ();
730 if (GTK_BUTTON_CLASS (parent_class)->clicked)
731 GTK_BUTTON_CLASS (parent_class)->clicked (b);
735 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
737 gboolean result = FALSE;
738 GtkTreeIter source_iter;
739 GtkTreeModel *source_model;
742 if (GTK_IS_TREE_MODEL_FILTER (model))
744 source_model = gtk_tree_model_filter_get_model
745 (GTK_TREE_MODEL_FILTER (model));
747 gtk_tree_model_filter_convert_iter_to_child_iter
748 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
752 source_model = model;
756 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
758 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
761 g_value_unset (&value);
768 /* Visibility function for items in the SOURCE widget.
769 Returns TRUE iff *all* the selectors for which SOURCE is associated
772 is_source_item_visible (GtkTreeModel *childmodel,
773 GtkTreeIter *iter, gpointer data)
775 PsppireSelector *selector = data;
776 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
780 list = g_hash_table_lookup (class->source_hash, selector->source);
784 PsppireSelector *selector = list->data;
786 if ( selector->filter && selector->filter (childmodel, iter, selector))
796 /* set the source widget to SOURCE */
798 set_tree_view_source (PsppireSelector *selector)
802 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
804 if ( ! (list = g_hash_table_lookup (class->source_hash, selector->source)))
806 /* Base case: This widget is currently not the source of
807 any selector. Create a hash entry and make this selector
808 the first selector in the list */
810 list = g_list_append (list, selector);
811 g_hash_table_insert (class->source_hash, selector->source, list);
813 /* Save the list item so that it can be removed later */
814 selector->source_litem = list;
817 { /* Append this selector to the list and push the <source,list>
818 pair onto the hash table */
820 if ( NULL == g_list_find (list, selector) )
822 if ( selector->primary_requested )
824 list = g_list_prepend (list, selector);
825 selector->source_litem = list;
829 list = g_list_append (list, selector);
830 selector->source_litem = g_list_last (list);
832 g_hash_table_replace (class->source_hash, selector->source, list);
839 /* This function is a callback which occurs when the
840 SOURCE's model has changed */
845 PsppireSelector *selector
848 GtkTreeModel *model = gtk_tree_view_get_model (source);
850 g_assert (source == GTK_TREE_VIEW (selector->source));
852 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
857 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
859 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
861 gtk_tree_view_set_model (source, new_model);
863 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
864 is_source_item_visible,
868 g_signal_connect_swapped (new_model,
870 G_CALLBACK (on_row_deleted), selector);
872 g_signal_connect_swapped (new_model,
874 G_CALLBACK (on_row_inserted), selector);
876 g_object_unref (new_model);
883 Callback for when the destination treeview's data changes
886 on_dest_data_change (GtkTreeModel *tree_model,
891 PsppireSelector *selector = user_data;
893 if ( selector->selecting) return;
900 on_dest_data_delete (GtkTreeModel *tree_model,
904 PsppireSelector *selector = user_data;
906 if ( selector->selecting ) return;
913 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
915 g_signal_handlers_disconnect_by_data (sel, selector);
919 on_dest_model_changed (PsppireSelector *selector)
921 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
926 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
929 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
932 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
934 if ( selector->selecting ) return;
939 /* Set the destination widget to DEST */
941 set_tree_view_dest (PsppireSelector *selector,
944 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
947 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
949 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
952 on_dest_model_changed (selector);
953 g_signal_connect_swapped (dest, "notify::model",
954 G_CALLBACK (on_dest_model_changed), selector);
958 set_layer_dest (PsppireSelector *selector,
959 PsppireMeansLayer *dest)
961 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
963 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
966 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
971 /* Callback for when the DEST GtkEntry is selected (clicked) */
973 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
975 PsppireSelector * selector = data;
977 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
978 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
985 /* Set DEST to be the destination GtkEntry widget */
987 set_entry_dest (PsppireSelector *selector,
990 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
993 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
996 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
999 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
1006 set_default_filter (PsppireSelector *selector)
1008 if ( selector->filter == NULL)
1010 if (GTK_IS_TREE_VIEW (selector->dest))
1011 selector->filter = is_item_in_dest;
1017 update_subjects (PsppireSelector *selector)
1019 if ( NULL == selector->dest )
1022 set_default_filter (selector);
1024 if ( NULL == selector->source )
1027 if ( GTK_IS_TREE_VIEW (selector->source))
1029 set_tree_view_source (selector);
1031 g_signal_connect (selector->source, "notify::model",
1032 G_CALLBACK (update_model), selector);
1034 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1037 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1039 if ( NULL == selector->dest)
1041 else if ( GTK_IS_TREE_VIEW (selector->dest))
1043 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1045 else if ( GTK_IS_ENTRY (selector->dest))
1047 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1049 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1051 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1053 else if (GTK_IS_TEXT_VIEW (selector->dest))
1055 /* Nothing to be done */
1058 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1061 /* FIXME: Remove this dependency */
1062 if ( PSPPIRE_IS_DICT_VIEW (selector->source) )
1064 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1065 GType type = G_OBJECT_TYPE (selector->dest);
1067 SelectItemsFunc *func =
1068 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1071 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1078 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1080 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1082 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1084 g_type_class_unref (class);
1090 /* Set FILTER_FUNC for this selector */
1092 psppire_selector_set_filter_func (PsppireSelector *selector,
1093 FilterItemsFunc *filter_func)
1095 selector->filter = filter_func ;
1099 /* Set SELECT_FUNC for this selector */
1101 psppire_selector_set_select_func (PsppireSelector *selector,
1102 SelectItemsFunc *select_func,
1105 selector->select_user_data = user_data;
1106 selector->select_items = select_func;
1112 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1114 selector->allow_selection = allow;
1119 psppire_selector_orientation_get_type (void)
1121 static GType etype = 0;
1124 static const GEnumValue values[] =
1126 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1127 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1128 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1129 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1132 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);