Implemented the find dialog.
authorJohn Darrington <john@darrington.wattle.id.au>
Thu, 13 Sep 2007 12:37:08 +0000 (12:37 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Thu, 13 Sep 2007 12:37:08 +0000 (12:37 +0000)
13 files changed:
src/data/ChangeLog
src/data/datasheet.c
src/data/value.c
src/data/value.h
src/ui/gui/ChangeLog
src/ui/gui/automake.mk
src/ui/gui/data-editor.c
src/ui/gui/data-editor.glade
src/ui/gui/data-editor.h
src/ui/gui/find-dialog.c [new file with mode: 0644]
src/ui/gui/find-dialog.h [new file with mode: 0644]
src/ui/gui/psppire-selector.c
src/ui/gui/psppire.glade

index bc89aef70a2b4e1a093d866d4c5e750c6c0bb168..73e611832f6665900b05880f70cb86cef2e73ba1 100644 (file)
@@ -1,3 +1,7 @@
+2007-09-13  John Darrinton <john@darrington.wattle.id.au>
+
+       * value.c value.h (create_value): New function.
+
 2007-09-12  Ben Pfaff  <blp@gnu.org>
 
        Make it clear that translator casereader and casewriter translate
index 913c8e5aff495f97055b8a7a62579716d3840f77..f76b1908d50f1dbdeeff94af7f9d6ecd2150ca16 100644 (file)
@@ -428,6 +428,7 @@ bool
 datasheet_get_value (const struct datasheet *ds, casenumber row, size_t column,
                      union value *value, int width)
 {
+  assert ( row >= 0 );
   return rw_case ((struct datasheet *) ds,
                   OP_READ, row, column, value_cnt_from_width (width), value);
 }
index e9411c8cefa976ff4a4c46d94db837e9eefffb23..cd52f147ca3a0f4fd924c40861788cfc22081623 100644 (file)
@@ -30,6 +30,16 @@ value_dup (const union value *val, int width)
   return xmemdup (val, MAX (width, sizeof *val));
 }
 
+
+/* Create a value of specified width.
+   The caller is responsible for freeing the returned value. */
+union value *
+value_create (int width)
+{
+  return xnmalloc (value_cnt_from_width (width), sizeof (union value));
+}
+
+
 /* Compares A and B, which both have the given WIDTH, and returns
    a strcmp()-type result.
    Only the short string portion of longer strings are
index 3ea55298cc2e6565eaf4d35ac5e4617e7ac4568c..118e6cd815fe012665392eeabc0b704560b52529 100644 (file)
@@ -53,6 +53,8 @@ union value
   };
 
 union value *value_dup (const union value *, int width);
+union value *value_create (int width);
+
 int compare_values (const union value *, const union value *, int width);
 unsigned hash_value (const union value  *, int width);
 
index 6c36b520ae0b5832c3aee48daa6b3bc6a4c74495..9e442432716cc3a870c4eedba7ec7d26bb105a76 100644 (file)
@@ -1,3 +1,13 @@
+2007-09-13  John Darrington <john@darrington.wattle.id.au>
+
+       * find-dialog.c find-dialog.h: New files.
+
+       * data-editor.c data-editor.h data-editor.glade: Added action for
+       the find dialog.
+
+       * psppire-selector.c: Emit the (de)selected signal when the 
+       destination entry widget's text changes.
+
 2007-09-10  Ben Pfaff  <blp@gnu.org>
 
        * var-sheet.c (psppire_variable_sheet_create): Use xstrdup to save
index b869a318fe000523df8008f3680f61c9c3236cf0..521d61fa4ad3ddac8507858762d3659fd24b0f4f 100644 (file)
@@ -86,6 +86,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/data-sheet.h \
        src/ui/gui/data-editor.c \
        src/ui/gui/data-editor.h \
+       src/ui/gui/find-dialog.c \
+       src/ui/gui/find-dialog.h \
        src/ui/gui/dialog-common.c \
        src/ui/gui/dialog-common.h \
        src/ui/gui/dict-display.c \
index 812d8fb8109a3baa098953454f1c2c7e53d02d1a..f73aa5e20de4f4a8ff57430936a389dbcfc41769 100644 (file)
@@ -36,6 +36,7 @@
 #include "select-cases-dialog.h"
 #include "compute-dialog.h"
 #include "goto-case-dialog.h"
+#include "find-dialog.h"
 #include "comments-dialog.h"
 #include "variable-info-dialog.h"
 #include "dict-display.h"
@@ -593,6 +594,16 @@ new_data_editor (void)
   g_signal_connect (de->invoke_comments_dialog, "activate",
                    G_CALLBACK (comments_dialog), de);
 
+  de->invoke_find_dialog  =
+    gtk_action_new ("find-dialog",
+                   _("Find"),
+                   _("Find Case"),
+                   "gtk-find");
+
+  g_signal_connect (de->invoke_find_dialog, "activate",
+                   G_CALLBACK (find_dialog), de);
+
+
   de->invoke_variable_info_dialog  =
     gtk_action_new ("variable-info-dialog",
                    _("Variables"),
@@ -678,6 +689,14 @@ new_data_editor (void)
                            G_CALLBACK (gtk_action_activate),
                            de->action_data_save_as);
 
+  gtk_action_connect_proxy (de->invoke_find_dialog,
+                           get_widget_assert (de->xml, "edit_find")
+                           );
+
+  gtk_action_connect_proxy (de->invoke_find_dialog,
+                           get_widget_assert (de->xml, "button-find")
+                           );
+
   gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
                            get_widget_assert (de->xml, "data_weight-cases")
                            );
index 26167ab59aec170ed67e15595da3b383412d1a23..0e911a77df6dfad7a10725370117b96c639948f6 100644 (file)
                       </widget>
                     </child>
                     <child>
-                      <widget class="GtkImageMenuItem" id="find1">
+                      <widget class="GtkImageMenuItem" id="edit_find">
                         <property name="visible">True</property>
                         <property name="sensitive">False</property>
                         <property name="label" translatable="yes">_Find</property>
index 00430e9f62e261f65033e1ad67d8ae1006c8ea60..143a2e111f7cf8dd90bdc92f48746ffb7bb59d07 100644 (file)
@@ -41,6 +41,7 @@ struct data_editor
   GtkAction *invoke_select_cases_dialog;
   GtkAction *invoke_goto_dialog;
   GtkAction *invoke_variable_info_dialog;
+  GtkAction *invoke_find_dialog;
 
   /* Actions which do things */
   GtkAction *insert_variable;
diff --git a/src/ui/gui/find-dialog.c b/src/ui/gui/find-dialog.c
new file mode 100644 (file)
index 0000000..63717df
--- /dev/null
@@ -0,0 +1,770 @@
+/* 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
+   it under the terms of the GNU General Public License as published by
+   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,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>. */
+
+
+/* This module implements the "Find" dialog; a dialog box to locate cases
+which match particular strings */
+
+#include <config.h>
+
+#include "find-dialog.h"
+#include "psppire-selector.h"
+#include "psppire-dialog.h"
+#include "helper.h"
+#include "data-editor.h"
+#include "dict-display.h"
+#include <data/value.h>
+#include <data/datasheet.h>
+#include <data/data-in.h>
+#include "psppire-data-store.h"
+#include <libpspp/alloc.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <libpspp/message.h>
+
+
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <stdlib.h>
+
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+
+/* FIXME: These shouldn't be here */
+#include <gtksheet/gtksheet.h>
+#include "psppire-var-store.h"
+
+struct find_dialog
+{
+  GladeXML *xml;
+  PsppireDict *dict;
+  GtkSheet *data_sheet;
+  struct datasheet *data;
+  struct data_editor *de;
+  GtkWidget *variable_entry;
+  GtkWidget *value_entry;
+  GtkWidget *value_labels_checkbox;
+  GtkWidget *match_regexp_checkbox;
+  GtkWidget *match_substring_checkbox;
+};
+
+static void
+find_value (const struct find_dialog *fd, casenumber current_row,
+          casenumber *row, int *column);
+
+
+/* A callback which occurs whenever the "Refresh" button is clicked,
+   and when the dialog pops up.
+   It restores the dialog to its default state.
+*/
+static void
+refresh (GObject *obj, const struct find_dialog *fd)
+{
+  gtk_toggle_button_set_active
+    (GTK_TOGGLE_BUTTON (get_widget_assert (fd->xml, "find-wrap")),
+     FALSE);
+
+  gtk_toggle_button_set_active
+    (GTK_TOGGLE_BUTTON (get_widget_assert (fd->xml, "find-backwards")),
+     FALSE);
+
+  gtk_entry_set_text (GTK_ENTRY (fd->variable_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (fd->value_entry), "");
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->match_regexp_checkbox),
+                               FALSE);
+
+  gtk_toggle_button_set_active
+    (GTK_TOGGLE_BUTTON (fd->match_substring_checkbox), FALSE);
+
+
+  gtk_toggle_button_set_active
+    (GTK_TOGGLE_BUTTON (fd->match_substring_checkbox), FALSE);
+}
+
+/* Callback on the "Find" button */
+static void
+do_find (GObject *obj, const struct find_dialog *fd)
+{
+  casenumber x;
+  gint column;
+  gint row;
+  gtk_sheet_get_active_cell (fd->data_sheet, &row, NULL);
+
+  if ( row < 0 )
+    row = 0;
+
+  find_value (fd, row, &x, &column);
+
+  if ( x != -1)
+    {
+      data_editor_select_sheet (fd->de, PAGE_DATA_SHEET);
+
+      gtk_sheet_moveto (fd->data_sheet, x, column, 0.5, 0.5);
+
+      gtk_sheet_set_active_cell (fd->data_sheet, x, column);
+    }
+}
+
+/* Callback on the selector.
+   It gets invoked whenever a variable is selected */
+static void
+on_select (GtkEntry *entry, gpointer data)
+{
+  struct find_dialog *fd = data;
+  const char *var_name = gtk_entry_get_text (GTK_ENTRY (fd->variable_entry));
+  struct variable *var = dict_lookup_var (fd->dict->dict, var_name);
+  gboolean search_labels ;
+
+  g_return_if_fail (var);
+
+  gtk_widget_set_sensitive (fd->value_labels_checkbox,
+                           var_has_value_labels (var));
+
+  search_labels =
+    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->value_labels_checkbox));
+
+  gtk_widget_set_sensitive (fd->match_regexp_checkbox,
+                           var_is_alpha (var) || search_labels);
+
+
+  gtk_widget_set_sensitive (fd->match_substring_checkbox,
+                           var_is_alpha (var) || search_labels);
+}
+
+/* Callback on the selector.
+   It gets invoked whenever a variable is unselected */
+static void
+on_deselect (GtkEntry *entry, gpointer data)
+{
+  struct find_dialog *fd = data;
+
+  gtk_widget_set_sensitive (fd->value_labels_checkbox, FALSE);
+  gtk_widget_set_sensitive (fd->match_substring_checkbox, FALSE);
+  gtk_widget_set_sensitive (fd->match_regexp_checkbox, FALSE);
+}
+
+static void
+value_labels_toggled (GtkToggleButton *tb, gpointer data)
+{
+  struct find_dialog *fd = data;
+
+  const char *var_name = gtk_entry_get_text (GTK_ENTRY (fd->variable_entry));
+  const struct variable *var = dict_lookup_var (fd->dict->dict, var_name);
+
+  gboolean active = gtk_toggle_button_get_active  (tb) ;
+
+  gtk_widget_set_sensitive (fd->match_substring_checkbox,
+                           active || (var && var_is_alpha (var)));
+
+  gtk_widget_set_sensitive (fd->match_regexp_checkbox,
+                             active || (var && var_is_alpha (var)));
+}
+
+/* Pops up the Find dialog box
+ */
+void
+find_dialog (GObject *o, gpointer data)
+{
+  struct data_editor *de = data;
+
+  struct find_dialog fd;
+
+  GtkWidget *dialog ;
+  GtkWidget *source ;
+  GtkWidget *selector;
+  GtkWidget *find_button;
+
+  GtkSheet *var_sheet;
+  GtkSheet *data_sheet ;
+  GtkWidget *buttonbox;
+
+  PsppireVarStore *vs  ;
+  PsppireDataStore *ds ;
+
+  fd.xml = XML_NEW ("psppire.glade");
+  fd.de = de;
+
+  find_button = gtk_button_new_from_stock  (GTK_STOCK_FIND);
+  gtk_widget_show (find_button);
+
+  buttonbox = get_widget_assert (fd.xml, "find-buttonbox");
+
+  gtk_box_pack_start_defaults (GTK_BOX (buttonbox), find_button);
+  gtk_box_reorder_child (GTK_BOX (buttonbox), find_button, 0);
+
+  dialog = get_widget_assert (fd.xml, "find-dialog");
+  source = get_widget_assert (fd.xml, "find-variable-treeview");
+  selector = get_widget_assert (fd.xml, "find-selector");
+
+  var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
+  data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
+
+  vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
+  ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
+
+  fd.dict = vs->dict;
+  fd.data = ds->case_file->datasheet;
+  fd.data_sheet = data_sheet;
+
+  fd.variable_entry        = get_widget_assert (fd.xml, "find-variable-entry");
+  fd.value_entry           = get_widget_assert (fd.xml, "find-value-entry");
+  fd.value_labels_checkbox =
+    get_widget_assert (fd.xml,
+                      "find-value-labels-checkbutton");
+
+  fd.match_regexp_checkbox =
+    get_widget_assert (fd.xml,
+                      "find-match-regexp-checkbutton");
+
+  fd.match_substring_checkbox =
+    get_widget_assert (fd.xml,
+                      "find-match-substring-checkbutton");
+
+
+
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), de->parent.window);
+
+
+  attach_dictionary_to_treeview (GTK_TREE_VIEW (source),
+                                fd.dict,
+                                GTK_SELECTION_SINGLE,
+                                NULL);
+
+  psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
+                                source,
+                                fd.variable_entry,
+                                insert_source_row_into_entry,
+                                is_currently_in_entry
+                                );
+
+  g_signal_connect (dialog, "refresh", G_CALLBACK (refresh),  &fd);
+
+  g_signal_connect (find_button, "clicked", G_CALLBACK (do_find),  &fd);
+
+  g_signal_connect (selector, "selected",
+                   G_CALLBACK (on_select),  &fd);
+
+  g_signal_connect (selector, "de-selected",
+                   G_CALLBACK (on_deselect),  &fd);
+
+  g_signal_connect (fd.value_labels_checkbox, "toggled",
+                   G_CALLBACK (value_labels_toggled),  &fd);
+
+
+  psppire_dialog_run (PSPPIRE_DIALOG (dialog));
+
+  g_object_unref (fd.xml);
+}
+
+\f
+/* Iterators */
+
+static void
+forward (casenumber *i, struct datasheet *data UNUSED)
+{
+  ++*i;
+}
+
+
+static void
+forward_wrap (casenumber *i, struct datasheet *data)
+{
+  if ( ++*i >=  datasheet_get_row_cnt (data) ) *i = 0;
+}
+
+static void
+backward (casenumber *i, struct datasheet *data UNUSED)
+{
+  --*i;
+}
+
+
+static void
+backward_wrap (casenumber *i, struct datasheet *data)
+{
+  if ( --*i < 0 )
+    *i = datasheet_get_row_cnt (data) - 1;
+}
+
+
+/* Current plus one */
+static casenumber
+cp1 (casenumber current, struct datasheet *data)
+{
+  return current + 1;
+}
+
+/* Current plus one, circular */
+static casenumber
+cp1c (casenumber current, struct datasheet *data)
+{
+  casenumber next = current;
+
+  forward_wrap (&next, data);
+
+  return next;
+}
+
+
+/* Current minus one */
+static casenumber
+cm1 (casenumber current, struct datasheet *data)
+{
+  return current - 1;
+}
+
+/* Current minus one, circular */
+static casenumber
+cm1c (casenumber current, struct datasheet *data)
+{
+  casenumber next = current;
+
+  backward_wrap (&next, data);
+
+  return next;
+}
+
+
+static casenumber
+last (casenumber current, struct datasheet *data)
+{
+  return datasheet_get_row_cnt (data) ;
+}
+
+static casenumber
+minus1 (casenumber current, struct datasheet *data)
+{
+  return -1;
+}
+
+/* An type to facilitate iterating through casenumbers */
+struct casenum_iterator
+{
+  /* returns the first case to access */
+  casenumber (*start) (casenumber, struct datasheet *);
+
+  /* Returns one past the last case to access */
+  casenumber (*end) (casenumber, struct datasheet *);
+
+  /* Sets the first arg to the next case to access */
+  void (*next) (casenumber *, struct datasheet *);
+};
+
+enum iteration_type{
+  FORWARD = 0,
+  FORWARD_WRAP,
+  REVERSE,
+  REVERSE_WRAP,
+  n_iterators
+};
+
+static struct casenum_iterator ip[n_iterators] =
+  {
+    {cp1, last, forward},
+    {cp1c, cm1, forward_wrap},
+    {cm1, minus1, backward},
+    {cm1c, cp1, backward_wrap}
+  };
+
+
+\f
+/* A factory returning an iterator according to the dialog box's settings */
+static struct casenum_iterator *
+get_iteration_params (const struct find_dialog *fd)
+{
+  gboolean wrap = gtk_toggle_button_get_active
+    (GTK_TOGGLE_BUTTON (get_widget_assert (fd->xml, "find-wrap")));
+
+  gboolean reverse = gtk_toggle_button_get_active
+    (GTK_TOGGLE_BUTTON (get_widget_assert (fd->xml, "find-backwards")));
+
+  if ( wrap )
+    {
+      if ( reverse )
+       return &ip[REVERSE_WRAP];
+      else
+       return &ip[FORWARD_WRAP];
+    }
+  else
+    {
+      if ( reverse )
+       return &ip[REVERSE];
+      else
+       return &ip[FORWARD];
+    }
+}
+
+
+enum string_cmp_flags
+  {
+    STR_CMP_SUBSTR = 0x01, /* Find strings which are substrings of the
+                             values */
+    STR_CMP_REGEXP = 0x02, /* Match against a regular expression */
+
+    STR_CMP_LABELS = 0x04  /* Match against the values' labels instead
+                             of the data */
+  };
+
+
+/* An abstract base type for comparing union values against a reference */
+struct comparator
+{
+  const struct variable *var;
+  enum string_cmp_flags flags;
+
+  bool (*compare) (const struct comparator *,
+                  const union value *);
+
+  void (*destroy) (struct comparator *);
+};
+
+
+/* A comparator which operates on the unadulterated union values */
+struct value_comparator
+{
+  struct comparator parent;
+  union value *pattern;
+};
+
+/* A comparator which matches string values or parts thereof */
+struct string_comparator
+{
+  struct comparator parent;
+  const char *pattern;
+};
+
+/* A comparator to match string values against a POSIX.2 regular expression */
+struct regexp_comparator
+{
+  struct comparator parent;
+  regex_t re;
+};
+
+
+static bool
+value_compare (const struct comparator *cmptr,
+              const union value *v)
+{
+  const struct value_comparator *vc = (const struct value_comparator *) cmptr;
+  return 0 == compare_values (v, vc->pattern, var_get_width (cmptr->var));
+}
+
+
+/* Return true if the label of VAL matches the reference string*/
+static bool
+string_label_compare (const struct comparator *cmptr,
+               const union value *val)
+{
+  const struct string_comparator *ssc =
+    (const struct string_comparator *) cmptr;
+
+  const char *text = var_lookup_value_label (cmptr->var, val);
+  int width = strlen (text);
+
+  assert ( cmptr->flags & STR_CMP_LABELS);
+
+  g_return_val_if_fail (width > 0, false);
+
+  if ( cmptr->flags & STR_CMP_SUBSTR)
+    return (NULL != g_strstr_len (text, width, ssc->pattern));
+  else
+    return (0 == strncmp (text, ssc->pattern, width));
+}
+
+/* Return true if VAL matches the reference string*/
+static bool
+string_value_compare (const struct comparator *cmptr,
+                     const union value *val)
+{
+  const struct string_comparator *ssc =
+    (const struct string_comparator *) cmptr;
+
+  const char *text = val->s;
+  int width = var_get_width (cmptr->var);
+
+  assert ( ! (cmptr->flags & STR_CMP_LABELS));
+
+  g_return_val_if_fail (width > 0, false);
+
+  if ( cmptr->flags & STR_CMP_SUBSTR)
+    return (NULL != g_strstr_len (text, width, ssc->pattern));
+  else
+    return (0 == strncmp (text, ssc->pattern, width));
+}
+
+
+
+/* Return true if VAL matched the regexp */
+static bool
+regexp_value_compare (const struct comparator *cmptr,
+               const union value *val)
+{
+  char *text;
+  bool retval;
+  const struct regexp_comparator *rec =
+    (const struct regexp_comparator *) cmptr;
+
+  int width = var_get_width (cmptr->var);
+
+  assert  ( ! (cmptr->flags & STR_CMP_LABELS) );
+
+  g_return_val_if_fail (width > 0, false);
+
+  /* We must remove trailing whitespace, otherwise $ will not match where
+     one would expect */
+  text = g_strndup (val->s, width);
+  g_strchomp (text);
+
+  retval = (0 == regexec (&rec->re, text, 0, 0, 0));
+
+  g_free (text);
+
+  return retval;
+}
+
+/* Return true if the label of VAL matched the regexp */
+static bool
+regexp_label_compare (const struct comparator *cmptr,
+                     const union value *val)
+{
+  const char *text;
+  const struct regexp_comparator *rec =
+    (const struct regexp_comparator *) cmptr;
+
+  int width ;
+
+  assert ( cmptr->flags & STR_CMP_LABELS);
+
+  text = var_lookup_value_label (cmptr->var, val);
+  width = strlen (text);
+
+  g_return_val_if_fail (width > 0, false);
+
+  return (0 == regexec (&rec->re, text, 0, 0, 0));
+}
+
+
+
+static void
+regexp_destroy (struct comparator *cmptr)
+{
+  struct regexp_comparator *rec = (struct regexp_comparator *) cmptr;
+
+  regfree (&rec->re);
+}
+
+static void
+value_destroy (struct comparator *cmptr)
+{
+  struct value_comparator *vc = (struct value_comparator *) cmptr;
+  free (vc->pattern);
+}
+
+
+static struct comparator *
+value_comparator_create (const struct variable *var, const char *target)
+{
+  const struct fmt_spec *fmt;
+  int width ;
+  struct value_comparator *vc = xzalloc (sizeof (*vc));
+  struct comparator *cmptr = (struct comparator *) vc;
+
+  cmptr->flags = 0;
+  cmptr->var = var;
+  cmptr->compare  = value_compare ;
+  cmptr->destroy = value_destroy;
+
+  width = var_get_width (var);
+  fmt = var_get_write_format (var);
+
+  vc->pattern = value_create (width);
+
+  if ( ! data_in (ss_cstr (target),
+                 fmt->type,
+                 0, 0,
+                 vc->pattern, width) )
+    {
+      free (vc);
+      return NULL;
+    }
+
+  return cmptr;
+}
+
+static struct comparator *
+string_comparator_create (const struct variable *var, const char *target,
+                         enum string_cmp_flags flags)
+{
+  struct string_comparator *ssc = xzalloc (sizeof (*ssc));
+  struct comparator *cmptr = (struct comparator *) ssc;
+
+  cmptr->flags = flags;
+  cmptr->var = var;
+
+  if ( flags & STR_CMP_LABELS)
+    cmptr->compare = string_label_compare;
+  else
+    cmptr->compare = string_value_compare;
+
+  ssc->pattern = target;
+
+  return cmptr;
+}
+
+
+static struct comparator *
+regexp_comparator_create (const struct variable *var, const char *target,
+                         enum string_cmp_flags flags)
+{
+  int code;
+  struct regexp_comparator *rec = xzalloc (sizeof (*rec));
+  struct comparator *cmptr = (struct comparator *) rec;
+
+  cmptr->flags = flags;
+  cmptr->var = var;
+  cmptr->compare  = (flags & STR_CMP_LABELS)
+    ? regexp_label_compare : regexp_value_compare ;
+
+  cmptr->destroy  = regexp_destroy;
+
+  code = regcomp (&rec->re, target, 0);
+  if ( code != 0 )
+    {
+      char *errbuf = NULL;
+      size_t errbuf_size = regerror (code, &rec->re, errbuf,  0);
+
+      errbuf = xmalloc (errbuf_size);
+
+      regerror (code, &rec->re, errbuf, errbuf_size);
+
+      msg (ME, _("Bad regular expression: %s"), errbuf);
+
+      free ( cmptr);
+      free (errbuf);
+      return NULL;
+    }
+
+  return cmptr;
+}
+
+
+/* Compare V against CMPTR's reference */
+static bool
+comparator_compare (const struct comparator *cmptr,
+                   const union value *v)
+{
+  return cmptr->compare (cmptr, v);
+}
+
+/* Destroy CMPTR */
+static void
+comparator_destroy (struct comparator *cmptr)
+{
+  if ( ! cmptr )
+    return ;
+
+  if ( cmptr->destroy )
+    cmptr->destroy (cmptr);
+
+  free (cmptr);
+}
+
+
+static struct comparator *
+comparator_factory (const struct variable *var, const char *str,
+                   enum string_cmp_flags flags)
+{
+  if ( flags & STR_CMP_REGEXP )
+    return regexp_comparator_create (var, str, flags);
+
+  if ( flags & (STR_CMP_SUBSTR | STR_CMP_LABELS) )
+    return string_comparator_create (var, str, flags);
+
+  return value_comparator_create (var, str);
+}
+
+
+/* Find the row and column specified by the dialog FD, starting at CURRENT_ROW.
+   After the function returns, *ROW contains the row and *COLUMN the column.
+   If no such case is found, then *ROW will be set to -1
+ */
+static void
+find_value (const struct find_dialog *fd, casenumber current_row,
+          casenumber *row, int *column)
+{
+  int width;
+  const struct variable *var;
+  const char *var_name = gtk_entry_get_text (GTK_ENTRY (fd->variable_entry));
+  const char *target_string = gtk_entry_get_text (GTK_ENTRY (fd->value_entry));
+
+  enum string_cmp_flags flags = 0;
+  g_assert (current_row >= 0);
+
+  var = dict_lookup_var (fd->dict->dict, var_name);
+  if ( ! var )
+    return ;
+
+  width = var_get_width (var);
+
+  *column = var_get_dict_index (var);
+  *row = -1;
+
+  if ( gtk_toggle_button_get_active
+       (GTK_TOGGLE_BUTTON (fd->match_substring_checkbox)))
+    flags |= STR_CMP_SUBSTR;
+
+  if ( gtk_toggle_button_get_active
+       (GTK_TOGGLE_BUTTON (fd->match_regexp_checkbox)))
+    flags |= STR_CMP_REGEXP;
+
+  if ( gtk_toggle_button_get_active
+       (GTK_TOGGLE_BUTTON (fd->value_labels_checkbox)))
+    flags |= STR_CMP_LABELS;
+
+  {
+    union value *val = value_create (width);
+    casenumber i;
+    struct casenum_iterator *ip = get_iteration_params (fd);
+    struct comparator *cmptr =
+      comparator_factory (var, target_string, flags);
+
+    if ( ! cmptr)
+      goto finish;
+
+    for (i = ip->start (current_row, fd->data);
+        i != ip->end (current_row, fd->data);
+        ip->next (&i, fd->data))
+      {
+       datasheet_get_value (fd->data, i, var_get_case_index (var),
+                            val, width);
+
+       if ( comparator_compare (cmptr, val))
+         {
+           *row = i;
+           break;
+         }
+      }
+
+  finish:
+    comparator_destroy (cmptr);
+    free (val);
+  }
+}
diff --git a/src/ui/gui/find-dialog.h b/src/ui/gui/find-dialog.h
new file mode 100644 (file)
index 0000000..3d4a50f
--- /dev/null
@@ -0,0 +1,27 @@
+/* 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
+   it under the terms of the GNU General Public License as published by
+   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,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef FIND_DIALOG_H
+#define FIND_DIALOG_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+/* Pops up the Find dialog box */
+void find_dialog (GObject *o, gpointer data);
+
+#endif
index 7f34baebafcbcbad1ff98535aa30f1fdcb293a4e..dcaac0ce031f9dcb0dd9b2a73584da2d4e506b33 100644 (file)
@@ -673,13 +673,15 @@ set_tree_view_dest (PsppireSelector *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) */
@@ -693,16 +695,50 @@ 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 (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);
 }
 
 
index 0526467bba6fbcad20a481a8647a85dc397b6fe1..1ef15572ecc9df88656f417eac39b66ab106e545 100644 (file)
                 <property name="column_spacing">5</property>
                 <property name="row_spacing">5</property>
                 <child>
-                  <widget class="GtkVBox" id="vbox5">
+                  <widget class="PsppireSelector" id="psppire-selector2">
                     <property name="visible">True</property>
-                    <child>
-                      <widget class="GtkLabel" id="label4">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Name Variable:</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkEntry" id="new-name-entry">
-                        <property name="visible">True</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
+                    <property name="border_width">5</property>
+                  </widget>
+                  <packing>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="PsppireSelector" id="psppire-selector3">
+                    <property name="visible">True</property>
+                    <property name="border_width">5</property>
                   </widget>
                   <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
                     <property name="top_attach">1</property>
                     <property name="bottom_attach">2</property>
-                    <property name="y_options"></property>
+                    <property name="x_options"></property>
+                    <property name="y_options">GTK_FILL</property>
                   </packing>
                 </child>
                 <child>
                   </packing>
                 </child>
                 <child>
-                  <widget class="PsppireSelector" id="psppire-selector3">
+                  <widget class="GtkVBox" id="vbox5">
                     <property name="visible">True</property>
-                    <property name="border_width">5</property>
+                    <child>
+                      <widget class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Name Variable:</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="new-name-entry">
+                        <property name="visible">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
                   </widget>
                   <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
                     <property name="top_attach">1</property>
                     <property name="bottom_attach">2</property>
-                    <property name="x_options"></property>
-                    <property name="y_options">GTK_FILL</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="PsppireSelector" id="psppire-selector2">
-                    <property name="visible">True</property>
-                    <property name="border_width">5</property>
-                  </widget>
-                  <packing>
-                    <property name="x_options"></property>
                     <property name="y_options"></property>
                   </packing>
                 </child>
                                 <property name="n_columns">2</property>
                                 <property name="row_spacing">5</property>
                                 <child>
-                                  <widget class="GtkRadioButton" id="radiobutton-all">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                    <property name="active">True</property>
-                                    <property name="draw_indicator">True</property>
-                                  </widget>
-                                </child>
-                                <child>
-                                  <widget class="GtkAlignment" id="alignment18">
-                                    <property name="visible">True</property>
-                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                    <property name="xalign">0</property>
-                                    <property name="yalign">0</property>
-                                    <property name="xscale">0</property>
-                                    <property name="yscale">0</property>
-                                    <child>
-                                      <widget class="GtkRadioButton" id="radiobutton-filter-variable">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <property name="active">True</property>
-                                        <property name="draw_indicator">True</property>
-                                        <property name="group">radiobutton-all</property>
-                                      </widget>
-                                    </child>
-                                  </widget>
-                                  <packing>
-                                    <property name="top_attach">4</property>
-                                    <property name="bottom_attach">5</property>
-                                    <property name="x_options"></property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkAlignment" id="alignment17">
+                                  <widget class="GtkLabel" id="label10">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                     <property name="xalign">0</property>
-                                    <property name="yalign">0</property>
-                                    <property name="xscale">0</property>
-                                    <property name="yscale">0</property>
-                                    <child>
-                                      <widget class="GtkRadioButton" id="radiobutton-range">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <property name="active">True</property>
-                                        <property name="draw_indicator">True</property>
-                                        <property name="group">radiobutton-all</property>
-                                      </widget>
-                                    </child>
+                                    <property name="label" translatable="yes">All Cases</property>
                                   </widget>
                                   <packing>
-                                    <property name="top_attach">3</property>
-                                    <property name="bottom_attach">4</property>
-                                    <property name="x_options"></property>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
                                   </packing>
                                 </child>
                                 <child>
-                                  <widget class="GtkAlignment" id="alignment16">
+                                  <widget class="GtkVBox" id="vbox14">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                    <property name="xalign">0</property>
-                                    <property name="yalign">0</property>
-                                    <property name="xscale">0</property>
-                                    <property name="yscale">0</property>
                                     <child>
-                                      <widget class="GtkRadioButton" id="radiobutton-sample">
+                                      <widget class="GtkLabel" id="label11">
                                         <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <property name="active">True</property>
-                                        <property name="draw_indicator">True</property>
-                                        <property name="group">radiobutton-all</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">If condition is satisfied</property>
                                       </widget>
                                     </child>
-                                  </widget>
-                                  <packing>
-                                    <property name="top_attach">2</property>
-                                    <property name="bottom_attach">3</property>
-                                    <property name="x_options"></property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <widget class="GtkAlignment" id="alignment13">
-                                    <property name="visible">True</property>
-                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                    <property name="xalign">0</property>
-                                    <property name="yalign">0</property>
-                                    <property name="xscale">0</property>
-                                    <property name="yscale">0</property>
                                     <child>
-                                      <widget class="GtkRadioButton" id="radiobutton-if">
+                                      <widget class="GtkHBox" id="hbox9">
                                         <property name="visible">True</property>
-                                        <property name="sensitive">False</property>
-                                        <property name="can_focus">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <property name="active">True</property>
-                                        <property name="draw_indicator">True</property>
-                                        <property name="group">radiobutton-all</property>
+                                        <child>
+                                          <widget class="GtkButton" id="button-if">
+                                            <property name="visible">True</property>
+                                            <property name="sensitive">False</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                            <property name="label" translatable="yes">If...</property>
+                                          </widget>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <widget class="GtkLabel" id="label26">
+                                            <property name="visible">True</property>
+                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                          </widget>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
                                       </widget>
+                                      <packing>
+                                        <property name="position">1</property>
+                                      </packing>
                                     </child>
                                   </widget>
                                   <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
                                     <property name="top_attach">1</property>
                                     <property name="bottom_attach">2</property>
-                                    <property name="x_options"></property>
                                   </packing>
                                 </child>
                                 <child>
-                                  <widget class="GtkVBox" id="vbox26">
+                                  <widget class="GtkVBox" id="vbox24">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                     <child>
-                                      <widget class="GtkLabel" id="label25">
+                                      <widget class="GtkLabel" id="label13">
                                         <property name="visible">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                         <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Use filter variable</property>
+                                        <property name="label" translatable="yes">Random sample of cases</property>
                                       </widget>
                                     </child>
                                     <child>
-                                      <widget class="GtkHBox" id="hbox19">
+                                      <widget class="GtkHBox" id="hbox11">
                                         <property name="visible">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                        <property name="spacing">5</property>
                                         <child>
-                                          <widget class="PsppireSelector" id="psppire-selector-filter">
+                                          <widget class="GtkButton" id="button-sample">
                                             <property name="visible">True</property>
                                             <property name="can_focus">True</property>
                                             <property name="receives_default">True</property>
                                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                            <property name="border_width">5</property>
+                                            <property name="label" translatable="yes">Sample...</property>
                                           </widget>
                                           <packing>
                                             <property name="expand">False</property>
                                           </packing>
                                         </child>
                                         <child>
-                                          <widget class="GtkEntry" id="filter-variable-entry">
+                                          <widget class="GtkLabel" id="random-sample-label">
                                             <property name="visible">True</property>
-                                            <property name="sensitive">False</property>
-                                            <property name="can_focus">True</property>
                                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                           </widget>
                                           <packing>
                                   <packing>
                                     <property name="left_attach">1</property>
                                     <property name="right_attach">2</property>
-                                    <property name="top_attach">4</property>
-                                    <property name="bottom_attach">5</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
                                   </packing>
                                 </child>
                                 <child>
                                   </packing>
                                 </child>
                                 <child>
-                                  <widget class="GtkVBox" id="vbox24">
+                                  <widget class="GtkVBox" id="vbox26">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                     <child>
-                                      <widget class="GtkLabel" id="label13">
+                                      <widget class="GtkLabel" id="label25">
                                         <property name="visible">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                         <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">Random sample of cases</property>
+                                        <property name="label" translatable="yes">Use filter variable</property>
                                       </widget>
                                     </child>
                                     <child>
-                                      <widget class="GtkHBox" id="hbox11">
+                                      <widget class="GtkHBox" id="hbox19">
                                         <property name="visible">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <property name="spacing">5</property>
                                         <child>
-                                          <widget class="GtkButton" id="button-sample">
+                                          <widget class="PsppireSelector" id="psppire-selector-filter">
                                             <property name="visible">True</property>
                                             <property name="can_focus">True</property>
                                             <property name="receives_default">True</property>
                                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                            <property name="label" translatable="yes">Sample...</property>
+                                            <property name="border_width">5</property>
                                           </widget>
                                           <packing>
                                             <property name="expand">False</property>
                                           </packing>
                                         </child>
                                         <child>
-                                          <widget class="GtkLabel" id="random-sample-label">
+                                          <widget class="GtkEntry" id="filter-variable-entry">
                                             <property name="visible">True</property>
+                                            <property name="sensitive">False</property>
+                                            <property name="can_focus">True</property>
                                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                           </widget>
                                           <packing>
                                   <packing>
                                     <property name="left_attach">1</property>
                                     <property name="right_attach">2</property>
-                                    <property name="top_attach">2</property>
-                                    <property name="bottom_attach">3</property>
+                                    <property name="top_attach">4</property>
+                                    <property name="bottom_attach">5</property>
                                   </packing>
                                 </child>
                                 <child>
-                                  <widget class="GtkVBox" id="vbox14">
+                                  <widget class="GtkAlignment" id="alignment13">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="yalign">0</property>
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
                                     <child>
-                                      <widget class="GtkLabel" id="label11">
+                                      <widget class="GtkRadioButton" id="radiobutton-if">
                                         <property name="visible">True</property>
+                                        <property name="sensitive">False</property>
+                                        <property name="can_focus">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <property name="xalign">0</property>
-                                        <property name="label" translatable="yes">If condition is satisfied</property>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                        <property name="group">radiobutton-all</property>
                                       </widget>
                                     </child>
-                                    <child>
-                                      <widget class="GtkHBox" id="hbox9">
-                                        <property name="visible">True</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options"></property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkAlignment" id="alignment16">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="yalign">0</property>
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <widget class="GtkRadioButton" id="radiobutton-sample">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
                                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                        <child>
-                                          <widget class="GtkButton" id="button-if">
-                                            <property name="visible">True</property>
-                                            <property name="sensitive">False</property>
-                                            <property name="can_focus">True</property>
-                                            <property name="receives_default">True</property>
-                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                            <property name="label" translatable="yes">If...</property>
-                                          </widget>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                            <property name="fill">False</property>
-                                          </packing>
-                                        </child>
-                                        <child>
-                                          <widget class="GtkLabel" id="label26">
-                                            <property name="visible">True</property>
-                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                                          </widget>
-                                          <packing>
-                                            <property name="position">1</property>
-                                          </packing>
-                                        </child>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                        <property name="group">radiobutton-all</property>
                                       </widget>
-                                      <packing>
-                                        <property name="position">1</property>
-                                      </packing>
                                     </child>
                                   </widget>
                                   <packing>
-                                    <property name="left_attach">1</property>
-                                    <property name="right_attach">2</property>
-                                    <property name="top_attach">1</property>
-                                    <property name="bottom_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                    <property name="x_options"></property>
                                   </packing>
                                 </child>
                                 <child>
-                                  <widget class="GtkLabel" id="label10">
+                                  <widget class="GtkAlignment" id="alignment17">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                     <property name="xalign">0</property>
-                                    <property name="label" translatable="yes">All Cases</property>
+                                    <property name="yalign">0</property>
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <widget class="GtkRadioButton" id="radiobutton-range">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                        <property name="group">radiobutton-all</property>
+                                      </widget>
+                                    </child>
                                   </widget>
                                   <packing>
-                                    <property name="left_attach">1</property>
-                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">3</property>
+                                    <property name="bottom_attach">4</property>
+                                    <property name="x_options"></property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkAlignment" id="alignment18">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="yalign">0</property>
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <widget class="GtkRadioButton" id="radiobutton-filter-variable">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                        <property name="group">radiobutton-all</property>
+                                      </widget>
+                                    </child>
+                                  </widget>
+                                  <packing>
+                                    <property name="top_attach">4</property>
+                                    <property name="bottom_attach">5</property>
+                                    <property name="x_options"></property>
                                   </packing>
                                 </child>
+                                <child>
+                                  <widget class="GtkRadioButton" id="radiobutton-all">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </widget>
+                                </child>
                               </widget>
                             </child>
                           </widget>
             <property name="n_columns">3</property>
             <property name="column_spacing">5</property>
             <child>
-              <widget class="GtkSpinButton" id="range-dialog-last">
+              <widget class="GtkLabel" id="label14">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="truncate_multiline">True</property>
-                <property name="adjustment">1 1 100 1 10 10</property>
+                <property name="label" translatable="yes">Observation</property>
               </widget>
               <packing>
-                <property name="left_attach">2</property>
-                <property name="right_attach">3</property>
-                <property name="top_attach">1</property>
                 <property name="bottom_attach">2</property>
               </packing>
             </child>
             <child>
-              <widget class="GtkSpinButton" id="range-dialog-first">
+              <widget class="GtkLabel" id="label12">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="truncate_multiline">True</property>
-                <property name="adjustment">0 1 0 1 10 10</property>
+                <property name="label" translatable="yes">Last case</property>
               </widget>
               <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">1</property>
-                <property name="bottom_attach">2</property>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
               </packing>
             </child>
             <child>
               </packing>
             </child>
             <child>
-              <widget class="GtkLabel" id="label12">
+              <widget class="GtkSpinButton" id="range-dialog-first">
                 <property name="visible">True</property>
+                <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="label" translatable="yes">Last case</property>
+                <property name="truncate_multiline">True</property>
+                <property name="adjustment">1 1 0 1 10 10</property>
               </widget>
               <packing>
-                <property name="left_attach">2</property>
-                <property name="right_attach">3</property>
-                <property name="x_options"></property>
-                <property name="y_options"></property>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
               </packing>
             </child>
             <child>
-              <widget class="GtkLabel" id="label14">
+              <widget class="GtkSpinButton" id="range-dialog-last">
                 <property name="visible">True</property>
+                <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="label" translatable="yes">Observation</property>
+                <property name="truncate_multiline">True</property>
+                <property name="adjustment">1 1 100 1 10 10</property>
               </widget>
               <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">1</property>
                 <property name="bottom_attach">2</property>
               </packing>
             </child>
                         <property name="n_rows">2</property>
                         <property name="n_columns">2</property>
                         <child>
-                          <widget class="GtkLabel" id="label27">
+                          <widget class="GtkRadioButton" id="radio-button-user-label">
                             <property name="visible">True</property>
+                            <property name="can_focus">True</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Use expression as label</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="x_options"></property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkRadioButton" id="radio-button-expression-label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">radio-button-user-label</property>
                           </widget>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
                             <property name="top_attach">1</property>
                             <property name="bottom_attach">2</property>
-                            <property name="y_options"></property>
+                            <property name="x_options"></property>
                           </packing>
                         </child>
                         <child>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkRadioButton" id="radio-button-expression-label">
+                          <widget class="GtkLabel" id="label27">
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                            <property name="group">radio-button-user-label</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Use expression as label</property>
                           </widget>
                           <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
                             <property name="top_attach">1</property>
                             <property name="bottom_attach">2</property>
-                            <property name="x_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <widget class="GtkRadioButton" id="radio-button-user-label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                          </widget>
-                          <packing>
-                            <property name="x_options"></property>
+                            <property name="y_options"></property>
                           </packing>
                         </child>
                       </widget>
                         <property name="border_width">5</property>
                         <property name="n_rows">2</property>
                         <property name="n_columns">2</property>
+                        <child>
+                          <widget class="GtkLabel" id="label28">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Numeric</property>
+                          </widget>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkRadioButton" id="radio-button-numeric">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">radio-button-string</property>
+                          </widget>
+                          <packing>
+                            <property name="x_options"></property>
+                            <property name="y_options"></property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkRadioButton" id="radio-button-string">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options"></property>
+                            <property name="y_options"></property>
+                          </packing>
+                        </child>
                         <child>
                           <widget class="GtkHBox" id="hbox20">
                             <property name="visible">True</property>
                             <property name="x_options">GTK_FILL</property>
                           </packing>
                         </child>
-                        <child>
-                          <widget class="GtkRadioButton" id="radio-button-string">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                          </widget>
-                          <packing>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="x_options"></property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <widget class="GtkRadioButton" id="radio-button-numeric">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                            <property name="group">radio-button-string</property>
-                          </widget>
-                          <packing>
-                            <property name="x_options"></property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <widget class="GtkLabel" id="label28">
-                            <property name="visible">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Numeric</property>
-                          </widget>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                          </packing>
-                        </child>
                       </widget>
                     </child>
                   </widget>
                     <property name="column_spacing">5</property>
                     <property name="row_spacing">5</property>
                     <child>
-                      <widget class="GtkRadioButton" id="radiobutton-sample-percent">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                      </widget>
-                      <packing>
-                        <property name="x_options"></property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkRadioButton" id="radiobutton-sample-n-cases">
+                      <widget class="GtkAlignment" id="alignment9">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                        <property name="group">radiobutton-sample-percent</property>
+                        <property name="xalign">0</property>
+                        <property name="xscale">0</property>
+                        <child>
+                          <placeholder/>
+                        </child>
                       </widget>
                       <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
                         <property name="top_attach">1</property>
                         <property name="bottom_attach">2</property>
-                        <property name="x_options"></property>
                       </packing>
                     </child>
                     <child>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkAlignment" id="alignment9">
+                      <widget class="GtkRadioButton" id="radiobutton-sample-n-cases">
                         <property name="visible">True</property>
+                        <property name="can_focus">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="xalign">0</property>
-                        <property name="xscale">0</property>
-                        <child>
-                          <placeholder/>
-                        </child>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton-sample-percent</property>
                       </widget>
                       <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
                         <property name="top_attach">1</property>
                         <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkRadioButton" id="radiobutton-sample-percent">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options"></property>
                       </packing>
                     </child>
                   </widget>
       </widget>
     </child>
   </widget>
+  <widget class="PsppireDialog" id="find-dialog">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title">Find Case</property>
+    <property name="modal">True</property>
+    <child internal-child="hbox">
+      <widget class="GtkHBox" id="dialog-hbox14">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkHBox" id="hbox10">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="border_width">5</property>
+            <property name="spacing">5</property>
+            <child>
+              <widget class="GtkScrolledWindow" id="scrolledwindow13">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+                <child>
+                  <widget class="GtkTreeView" id="find-variable-treeview">
+                    <property name="height_request">300</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="headers_visible">False</property>
+                    <property name="fixed_height_mode">True</property>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox27">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="PsppireSelector" id="find-selector">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="border_width">5</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox10">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkVBox" id="vbox11">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <widget class="GtkLabel" id="label33">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Variable:</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="find-variable-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVBox" id="vbox15">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <widget class="GtkLabel" id="label34">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Value:</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="find-value-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="find-value-labels-checkbutton">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Search value labels</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="bb1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <widget class="GtkCheckButton" id="find-match-regexp-checkbutton">
+                        <property name="sensitive">False</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Regular expression Match</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="find-match-substring-checkbutton">
+                        <property name="sensitive">False</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Search substrings</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="find-wrap">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Wrap around</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="find-backwards">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Search backward</property>
+                        <property name="draw_indicator">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+        <child>
+          <widget class="PsppireVButtonBox" id="find-buttonbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="border_width">5</property>
+            <property name="buttons">PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK | PSPPIRE_BUTTON_RESET_MASK</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
 </glade-interface>