Added the Independent Samples T Test dialog
[pspp-builds.git] / src / ui / gui / psppire-selector.c
index 68d8270db805f83193637485b581b4bb3e7b0ee4..5ec051bb9a98c8f83ed4a87f67bf4eab4e74399c 100644 (file)
@@ -1,10 +1,9 @@
-/*
-   PSPPIRE --- A Graphical User Interface for PSPP
+/* PSPPIRE - a graphical user interface for PSPP.
    Copyright (C) 2007  Free Software Foundation
 
-   This program is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -13,9 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 /*
   This module provides a widget, PsppireSelector derived from
@@ -68,6 +65,7 @@
 
 #include <gtk/gtktreeview.h>
 #include <gtk/gtktreeselection.h>
+#include <gtk/gtktextview.h>
 #include <gtk/gtkwidget.h>
 
 static void psppire_selector_base_finalize (PsppireSelectorClass *, gpointer);
@@ -242,9 +240,7 @@ psppire_selector_init (PsppireSelector *selector)
 
   gtk_widget_show (selector->arrow);
 
-  /* FIXME: This shouldn't be necessary, but Glade interfaces seem to
-     need it. */
-  gtk_widget_show (GTK_WIDGET (selector));
+  selector->selecting = FALSE;
 }
 
 
@@ -397,6 +393,8 @@ de_select_selection_tree_view (PsppireSelector *selector)
 static void
 de_select_selection (PsppireSelector *selector)
 {
+  selector->selecting = TRUE;
+
   if ( GTK_IS_TREE_VIEW (selector->dest ) )
     de_select_selection_tree_view (selector);
 
@@ -406,6 +404,8 @@ de_select_selection (PsppireSelector *selector)
   else
     g_assert_not_reached ();
 
+  selector->selecting = FALSE;
+
   gtk_tree_model_filter_refilter (selector->filtered_source);
 
   g_signal_emit (selector, signals [DE_SELECTED], 0);
@@ -428,6 +428,7 @@ select_selection (PsppireSelector *selector)
 
   g_return_if_fail (selector->select_items);
 
+  selector->selecting = TRUE;
 
   for (item = g_list_first (selected_rows);
        item != NULL;
@@ -456,9 +457,11 @@ select_selection (PsppireSelector *selector)
   gtk_tree_model_filter_refilter (selector->filtered_source);
 
   g_signal_emit (selector, signals [SELECTED], 0);
+
+  selector->selecting = FALSE;
 }
 
-/* Callback fro then the source treeview is activated (double clicked) */
+/* Callback for when the source treeview is activated (double clicked) */
 static void
 on_row_activate (GtkTreeView       *tree_view,
                 GtkTreePath       *path,
@@ -556,8 +559,8 @@ is_source_item_visible (GtkTreeModel *childmodel,
     {
       PsppireSelector *selector = list->data;
 
-      if ( selector->filter (childmodel, iter, selector))
-         return FALSE;
+      if ( selector->filter && selector->filter (childmodel, iter, selector))
+       return FALSE;
 
       list = list->next;
     }
@@ -617,26 +620,68 @@ set_tree_view_source (PsppireSelector *selector,
 }
 
 
+/*
+   Callback for when the destination treeview's data changes
+ */
+static void
+on_dest_data_change (GtkTreeModel *tree_model,
+                    GtkTreePath  *path,
+                    GtkTreeIter  *iter,
+                    gpointer      user_data)
+{
+  PsppireSelector *selector = user_data;
+
+  if ( selector->selecting) return;
+
+  gtk_tree_model_filter_refilter (selector->filtered_source);
+}
+
+
+static void
+on_dest_data_delete (GtkTreeModel *tree_model,
+                    GtkTreePath  *path,
+                    gpointer      user_data)
+{
+  PsppireSelector *selector = user_data;
+
+  if ( selector->selecting ) return;
+
+  gtk_tree_model_filter_refilter (selector->filtered_source);
+}
+
+
+
+
 /* Set the destination widget to DEST */
 static void
 set_tree_view_dest (PsppireSelector *selector,
                    GtkTreeView *dest)
 {
   GtkTreeSelection* selection = gtk_tree_view_get_selection (dest);
+  GtkTreeModel *model = gtk_tree_view_get_model (dest);
 
   gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
 
   g_signal_connect (selection, "changed", G_CALLBACK (on_dest_treeview_select),
                    selector);
+
+  g_signal_connect (model, "row-changed", G_CALLBACK (on_dest_data_change),
+                     selector);
+
+  g_signal_connect (model, "row-deleted", G_CALLBACK (on_dest_data_delete),
+                     selector);
+
 }
 
-/* Callback for when the DEST GtkEntry is activated (Enter is pressed) */
-static void
-on_entry_activate (GtkEntry *w, gpointer data)
+/* Callback which causes the filter to be refiltered.
+   Called when the DEST GtkEntry is activated (Enter is pressed), or when it
+   looses focus.
+*/
+static gboolean
+refilter (PsppireSelector *selector)
 {
-  PsppireSelector * selector = data;
-
   gtk_tree_model_filter_refilter (selector->filtered_source);
+  return FALSE;
 }
 
 /* Callback for when the DEST GtkEntry is selected (clicked) */
@@ -650,16 +695,53 @@ on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
   return FALSE;
 }
 
+
+
+/* Callback for when an item disappears from the source list.
+   By implication, this means that the item has been inserted into the
+   destination.
+ */
+static void
+on_row_deleted (PsppireSelector *selector)
+{
+  g_signal_emit (selector, signals [SELECTED], 0);
+}
+
+/* Callback for when a new item appears in the source list.
+   By implication, this means that an item has been deleted from the
+   destination.
+ */
+static void
+on_row_inserted (PsppireSelector *selector)
+{
+  g_signal_emit (selector, signals [DE_SELECTED], 0);
+}
+
+
+
 /* Set DEST to be the destination GtkEntry widget */
 static void
 set_entry_dest (PsppireSelector *selector,
                GtkEntry *dest)
 {
-  g_signal_connect (dest, "activate", G_CALLBACK (on_entry_activate),
+  g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter),
+                   selector);
+
+  g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter),
                    selector);
 
   g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
                    selector);
+
+  g_signal_connect_swapped (dest, "focus-out-event", G_CALLBACK (refilter),
+                   selector);
+
+
+  g_signal_connect_swapped (selector->filtered_source, "row-deleted",
+                   G_CALLBACK (on_row_deleted), selector);
+
+  g_signal_connect_swapped (selector->filtered_source, "row-inserted",
+                   G_CALLBACK (on_row_inserted), selector);
 }
 
 
@@ -672,6 +754,8 @@ psppire_selector_set_subjects (PsppireSelector *selector,
                               SelectItemsFunc *select_func,
                               FilterItemsFunc *filter_func )
 {
+  g_assert(selector);
+
   selector->filter = filter_func ;
 
   selector->source = source;
@@ -698,6 +782,11 @@ psppire_selector_set_subjects (PsppireSelector *selector,
   else if ( GTK_IS_ENTRY (dest))
     set_entry_dest (selector, GTK_ENTRY (dest));
 
+  else if (GTK_IS_TEXT_VIEW (dest))
+    {
+      /* Nothing to be done */
+    }
+
   else
     g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (dest));