1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2009, 2010, 2012 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 This module provides a widget, PsppireSelector derived from
22 It contains a GtkArrow, and is used for selecting objects from a
23 GtkTreeView and putting them into a destination widget (often
24 another GtkTreeView). Typically this is used in psppire for
25 selecting variables, thus:
28 +----------------------------------------------------------+
30 | Source Widget Dest Widget |
31 | +----------------+ +----------------+ |
32 | | Variable0 | | Variable2 | |
47 | +----------------+ +----------------+ |
49 +----------------------------------------------------------+
51 The Source Widget is always a GtkTreeView. The Dest Widget may be a
52 GtkTreeView or a GtkEntry (other destination widgets may be
53 supported in the future).
55 Widgets may be source to more than one PsppireSelector.
61 #include "psppire-dictview.h"
62 #include "psppire-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_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
445 gtk_container_add (GTK_CONTAINER (selector), selector->arrow);
447 gtk_widget_show (selector->arrow);
449 selector->selecting = FALSE;
451 selector->source = NULL;
452 selector->dest = NULL;
453 selector->dispose_has_run = FALSE;
456 selector->row_activate_id = 0;
457 selector->source_select_id = 0;
459 selector->source_litem = NULL;
464 psppire_selector_new (void)
466 return GTK_WIDGET (g_object_new (psppire_selector_get_type (), NULL));
471 set_direction (PsppireSelector *selector, enum psppire_selector_dir d)
473 selector->direction = d;
475 /* FIXME: Need to reverse the arrow direction if an RTL locale is in
477 if ( d == PSPPIRE_SELECTOR_SOURCE_TO_DEST )
479 switch (selector->orientation)
481 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
482 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_RIGHT, NULL);
484 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
485 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_LEFT, NULL);
487 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
488 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_DOWN, NULL);
490 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
491 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_UP, NULL);
494 g_assert_not_reached ();
500 switch (selector->orientation)
502 case PSPPIRE_SELECT_SOURCE_BEFORE_DEST:
503 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_LEFT, NULL);
505 case PSPPIRE_SELECT_SOURCE_AFTER_DEST:
506 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_RIGHT, NULL);
508 case PSPPIRE_SELECT_SOURCE_ABOVE_DEST:
509 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_UP, NULL);
511 case PSPPIRE_SELECT_SOURCE_BELOW_DEST:
512 g_object_set (selector->arrow, "arrow-type", GTK_ARROW_DOWN, NULL);
515 g_assert_not_reached ();
522 /* Callback for when the destination treeview selection changes */
524 on_dest_treeview_select (GtkTreeSelection *treeselection, gpointer data)
526 PsppireSelector *selector = data;
528 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
530 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
534 /* Callback for source deselection, when the dest is GtkEntry */
536 de_select_selection_entry (PsppireSelector *selector)
538 gtk_entry_set_text (GTK_ENTRY (selector->dest), "");
542 static void de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model);
544 /* Callback for source deselection, when the dest is PsppireMeansLayer */
546 de_select_selection_means_layer (PsppireSelector *selector)
548 PsppireMeansLayer *ml = PSPPIRE_MEANS_LAYER (selector->dest);
549 GtkTreeView *tv = GTK_TREE_VIEW (ml->var_view);
550 GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
552 GtkTreeModel *model = psppire_means_layer_get_model (ml);
554 g_return_if_fail (selector->select_items);
556 de_select_tree_model (selection, model);
559 /* Callback for source deselection, when the dest is GtkTreeView */
561 de_select_selection_tree_view (PsppireSelector *selector)
563 GtkTreeSelection* selection =
564 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->dest));
566 GtkTreeModel *model =
567 gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
569 g_return_if_fail (selector->select_items);
571 de_select_tree_model (selection, model);
575 de_select_tree_model (GtkTreeSelection *selection, GtkTreeModel *model)
579 GList *selected_rows =
580 gtk_tree_selection_get_selected_rows (selection, NULL);
582 /* Convert paths to RowRefs */
583 for (item = g_list_first (selected_rows);
585 item = g_list_next (item))
587 GtkTreeRowReference* rowref;
588 GtkTreePath *path = item->data;
590 rowref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
592 item->data = rowref ;
593 gtk_tree_path_free (path);
596 /* Remove each selected row from the dest widget */
597 for (item = g_list_first (selected_rows);
599 item = g_list_next (item))
602 GtkTreeRowReference *rr = item->data;
604 GtkTreePath *path = gtk_tree_row_reference_get_path (rr);
606 gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
608 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
610 gtk_tree_path_free (path);
613 /* Delete list of RowRefs and its contents */
614 g_list_foreach (selected_rows, (GFunc) gtk_tree_row_reference_free, NULL);
615 g_list_free (selected_rows);
619 /* Callback which causes the filter to be refiltered.
620 Called when the DEST GtkEntry is activated (Enter is pressed), or when it
624 refilter (PsppireSelector *selector)
626 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
627 if (GTK_IS_TREE_MODEL_FILTER (model))
628 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
632 /* Removes something from the DEST widget */
634 de_select_selection (PsppireSelector *selector)
636 selector->selecting = TRUE;
638 if ( GTK_IS_TREE_VIEW (selector->dest ) )
639 de_select_selection_tree_view (selector);
641 else if ( GTK_IS_ENTRY (selector->dest))
642 de_select_selection_entry (selector);
644 else if ( PSPPIRE_IS_MEANS_LAYER (selector->dest))
645 de_select_selection_means_layer (selector);
648 g_assert_not_reached ();
650 selector->selecting = FALSE;
654 g_signal_emit (selector, signals [DE_SELECTED], 0);
658 /* Puts something into the DEST widget */
660 select_selection (PsppireSelector *selector)
663 GtkTreeSelection* selection =
664 gtk_tree_view_get_selection ( GTK_TREE_VIEW (selector->source));
666 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
668 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->source));
670 GtkTreeModel *childmodel = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
672 g_return_if_fail (selector->select_items);
674 if (selector->allow_selection &&
675 ! selector->allow_selection (selector->source, selector->dest))
678 selector->selecting = TRUE;
680 for (item = g_list_first (selected_rows);
682 item = g_list_next (item))
684 GtkTreeIter child_iter;
686 GtkTreePath *path = item->data;
688 g_return_if_fail (model);
690 gtk_tree_model_get_iter (model, &iter, path);
692 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
694 selector->select_items (child_iter,
697 selector->select_user_data
701 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
702 g_list_free (selected_rows);
706 g_signal_emit (selector, signals [SELECTED], 0);
708 selector->selecting = FALSE;
711 /* Callback for when the selector button is clicked,
712 or other event which causes the selector's action to occur.
715 on_click (GtkButton *b)
717 PsppireSelector *selector = PSPPIRE_SELECTOR (b);
719 switch (selector->direction)
721 case PSPPIRE_SELECTOR_SOURCE_TO_DEST:
722 select_selection (selector);
724 case PSPPIRE_SELECTOR_DEST_TO_SOURCE:
725 de_select_selection (selector);
728 g_assert_not_reached ();
732 if (GTK_BUTTON_CLASS (parent_class)->clicked)
733 GTK_BUTTON_CLASS (parent_class)->clicked (b);
737 is_item_in_dest (GtkTreeModel *model, GtkTreeIter *iter, PsppireSelector *selector)
739 gboolean result = FALSE;
740 GtkTreeIter source_iter;
741 GtkTreeModel *source_model;
744 if (GTK_IS_TREE_MODEL_FILTER (model))
746 source_model = gtk_tree_model_filter_get_model
747 (GTK_TREE_MODEL_FILTER (model));
749 gtk_tree_model_filter_convert_iter_to_child_iter
750 (GTK_TREE_MODEL_FILTER (model), &source_iter, iter);
754 source_model = model;
758 gtk_tree_model_get_value (source_model, &source_iter, DICT_TVM_COL_VAR, &value);
760 result = psppire_select_dest_widget_contains_var (PSPPIRE_SELECT_DEST_WIDGET (selector->dest),
763 g_value_unset (&value);
770 /* Visibility function for items in the SOURCE widget.
771 Returns TRUE iff *all* the selectors for which SOURCE is associated
774 is_source_item_visible (GtkTreeModel *childmodel,
775 GtkTreeIter *iter, gpointer data)
777 PsppireSelector *selector = data;
778 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
782 list = g_hash_table_lookup (class->source_hash, selector->source);
786 PsppireSelector *selector = list->data;
788 if ( selector->filter && selector->filter (childmodel, iter, selector))
798 /* set the source widget to SOURCE */
800 set_tree_view_source (PsppireSelector *selector)
804 PsppireSelectorClass *class = g_type_class_peek (PSPPIRE_SELECTOR_TYPE);
806 if ( ! (list = g_hash_table_lookup (class->source_hash, selector->source)))
808 /* Base case: This widget is currently not the source of
809 any selector. Create a hash entry and make this selector
810 the first selector in the list */
812 list = g_list_append (list, selector);
813 g_hash_table_insert (class->source_hash, selector->source, list);
815 /* Save the list item so that it can be removed later */
816 selector->source_litem = list;
819 { /* Append this selector to the list and push the <source,list>
820 pair onto the hash table */
822 if ( NULL == g_list_find (list, selector) )
824 if ( selector->primary_requested )
826 list = g_list_prepend (list, selector);
827 selector->source_litem = list;
831 list = g_list_append (list, selector);
832 selector->source_litem = g_list_last (list);
834 g_hash_table_replace (class->source_hash, selector->source, list);
841 /* This function is a callback which occurs when the
842 SOURCE's model has changed */
847 PsppireSelector *selector
850 GtkTreeModel *model = gtk_tree_view_get_model (source);
852 g_assert (source == GTK_TREE_VIEW (selector->source));
854 if (model && (model == g_object_get_data (G_OBJECT (source), "model-copy")))
859 GtkTreeModel *new_model = gtk_tree_model_filter_new (model, NULL);
861 g_object_set_data (G_OBJECT (source), "model-copy", new_model);
863 gtk_tree_view_set_model (source, new_model);
865 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_model),
866 is_source_item_visible,
870 g_signal_connect_swapped (new_model,
872 G_CALLBACK (on_row_deleted), selector);
874 g_signal_connect_swapped (new_model,
876 G_CALLBACK (on_row_inserted), selector);
878 g_object_unref (new_model);
885 Callback for when the destination treeview's data changes
888 on_dest_data_change (GtkTreeModel *tree_model,
893 PsppireSelector *selector = user_data;
895 if ( selector->selecting) return;
902 on_dest_data_delete (GtkTreeModel *tree_model,
906 PsppireSelector *selector = user_data;
908 if ( selector->selecting ) return;
915 remove_selector_handlers (PsppireSelector *selector, GObject *sel)
917 g_signal_handlers_disconnect_by_data (sel, selector);
921 on_dest_model_changed (PsppireSelector *selector)
923 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector->dest));
928 g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
931 g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
934 g_signal_connect (selector, "destroy", G_CALLBACK (remove_selector_handlers), model);
936 if ( selector->selecting ) return;
941 /* Set the destination widget to DEST */
943 set_tree_view_dest (PsppireSelector *selector,
946 GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
949 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
951 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
954 on_dest_model_changed (selector);
955 g_signal_connect_swapped (dest, "notify::model",
956 G_CALLBACK (on_dest_model_changed), selector);
960 set_layer_dest (PsppireSelector *selector,
961 PsppireMeansLayer *dest)
963 GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dest->var_view));
965 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
968 g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
973 /* Callback for when the DEST GtkEntry is selected (clicked) */
975 on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
977 PsppireSelector * selector = data;
979 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector->source)));
980 set_direction (selector, PSPPIRE_SELECTOR_DEST_TO_SOURCE);
987 /* Set DEST to be the destination GtkEntry widget */
989 set_entry_dest (PsppireSelector *selector,
992 g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
995 g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
998 g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
1001 g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
1008 set_default_filter (PsppireSelector *selector)
1010 if ( selector->filter == NULL)
1012 if (GTK_IS_TREE_VIEW (selector->dest))
1013 selector->filter = is_item_in_dest;
1019 update_subjects (PsppireSelector *selector)
1021 if ( NULL == selector->dest )
1024 set_default_filter (selector);
1026 if ( NULL == selector->source )
1029 if ( GTK_IS_TREE_VIEW (selector->source))
1031 set_tree_view_source (selector);
1033 g_signal_connect (selector->source, "notify::model",
1034 G_CALLBACK (update_model), selector);
1036 update_model (GTK_TREE_VIEW (selector->source), 0, selector);
1039 g_error ("Unsupported source widget: %s", G_OBJECT_TYPE_NAME (selector->source));
1041 if ( NULL == selector->dest)
1043 else if ( GTK_IS_TREE_VIEW (selector->dest))
1045 set_tree_view_dest (selector, GTK_TREE_VIEW (selector->dest));
1047 else if ( GTK_IS_ENTRY (selector->dest))
1049 set_entry_dest (selector, GTK_ENTRY (selector->dest));
1051 else if (PSPPIRE_IS_MEANS_LAYER (selector->dest))
1053 set_layer_dest (selector, PSPPIRE_MEANS_LAYER (selector->dest));
1055 else if (GTK_IS_TEXT_VIEW (selector->dest))
1057 /* Nothing to be done */
1060 g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (selector->dest));
1063 /* FIXME: Remove this dependency */
1064 if ( PSPPIRE_IS_DICT_VIEW (selector->source) )
1066 GObjectClass *class = G_OBJECT_GET_CLASS (selector);
1067 GType type = G_OBJECT_TYPE (selector->dest);
1069 SelectItemsFunc *func =
1070 g_hash_table_lookup (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type);
1073 psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
1080 psppire_selector_set_default_selection_func (GType type, SelectItemsFunc *func)
1082 GObjectClass *class = g_type_class_ref (PSPPIRE_SELECTOR_TYPE);
1084 g_hash_table_insert (PSPPIRE_SELECTOR_CLASS (class)->default_selection_funcs, (gpointer) type, func);
1086 g_type_class_unref (class);
1092 /* Set FILTER_FUNC for this selector */
1094 psppire_selector_set_filter_func (PsppireSelector *selector,
1095 FilterItemsFunc *filter_func)
1097 selector->filter = filter_func ;
1101 /* Set SELECT_FUNC for this selector */
1103 psppire_selector_set_select_func (PsppireSelector *selector,
1104 SelectItemsFunc *select_func,
1107 selector->select_user_data = user_data;
1108 selector->select_items = select_func;
1114 psppire_selector_set_allow (PsppireSelector *selector, AllowSelectionFunc *allow)
1116 selector->allow_selection = allow;
1121 psppire_selector_orientation_get_type (void)
1123 static GType etype = 0;
1126 static const GEnumValue values[] =
1128 { PSPPIRE_SELECT_SOURCE_BEFORE_DEST, "PSPPIRE_SELECT_SOURCE_BEFORE_DEST", "source before destination" },
1129 { PSPPIRE_SELECT_SOURCE_AFTER_DEST, "PSPPIRE_SELECT_SOURCE_AFTER_DEST", "source after destination" },
1130 { PSPPIRE_SELECT_SOURCE_ABOVE_DEST, "PSPPIRE_SELECT_SOURCE_ABOVE_DEST", "source above destination" },
1131 { PSPPIRE_SELECT_SOURCE_BELOW_DEST, "PSPPIRE_SELECT_SOURCE_BELOW_DEST", "source below destination" },
1134 etype = g_enum_register_static (g_intern_static_string ("PsppireSelectorOrientation"), values);