(popup_message): Refer to files that contain commands as "syntax"
[pspp] / src / ui / gui / psppire-selector.c
index 68d8270db805f83193637485b581b4bb3e7b0ee4..dcaac0ce031f9dcb0dd9b2a73584da2d4e506b33 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
 
    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
    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,
    (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
    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
 
 /*
   This module provides a widget, PsppireSelector derived from
@@ -68,6 +65,7 @@
 
 #include <gtk/gtktreeview.h>
 #include <gtk/gtktreeselection.h>
 
 #include <gtk/gtktreeview.h>
 #include <gtk/gtktreeselection.h>
+#include <gtk/gtktextview.h>
 #include <gtk/gtkwidget.h>
 
 static void psppire_selector_base_finalize (PsppireSelectorClass *, gpointer);
 #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);
 
 
   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)
 {
 static void
 de_select_selection (PsppireSelector *selector)
 {
+  selector->selecting = TRUE;
+
   if ( GTK_IS_TREE_VIEW (selector->dest ) )
     de_select_selection_tree_view (selector);
 
   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 ();
 
   else
     g_assert_not_reached ();
 
+  selector->selecting = FALSE;
+
   gtk_tree_model_filter_refilter (selector->filtered_source);
 
   g_signal_emit (selector, signals [DE_SELECTED], 0);
   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);
 
 
   g_return_if_fail (selector->select_items);
 
+  selector->selecting = TRUE;
 
   for (item = g_list_first (selected_rows);
        item != NULL;
 
   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);
   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,
 static void
 on_row_activate (GtkTreeView       *tree_view,
                 GtkTreePath       *path,
@@ -556,8 +559,8 @@ is_source_item_visible (GtkTreeModel *childmodel,
     {
       PsppireSelector *selector = list->data;
 
     {
       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;
     }
 
       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);
 /* 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);
 
   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);
   gtk_tree_model_filter_refilter (selector->filtered_source);
+  return FALSE;
 }
 
 /* Callback for when the DEST GtkEntry is selected (clicked) */
 }
 
 /* Callback for when the DEST GtkEntry is selected (clicked) */
@@ -650,16 +695,50 @@ on_entry_dest_select (GtkWidget *widget, GdkEventFocus *event, gpointer data)
   return FALSE;
 }
 
   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)
 {
 /* 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 (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select),
                    selector);
                    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 +751,8 @@ psppire_selector_set_subjects (PsppireSelector *selector,
                               SelectItemsFunc *select_func,
                               FilterItemsFunc *filter_func )
 {
                               SelectItemsFunc *select_func,
                               FilterItemsFunc *filter_func )
 {
+  g_assert(selector);
+
   selector->filter = filter_func ;
 
   selector->source = source;
   selector->filter = filter_func ;
 
   selector->source = source;
@@ -698,6 +779,11 @@ psppire_selector_set_subjects (PsppireSelector *selector,
   else if ( GTK_IS_ENTRY (dest))
     set_entry_dest (selector, GTK_ENTRY (dest));
 
   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));
 
   else
     g_error ("Unsupported destination widget: %s", G_OBJECT_TYPE_NAME (dest));