Replaced the function widget_scanf with a new widget psppire_scanf
authorJohn Darrington <john@darrington.wattle.id.au>
Sat, 30 Jul 2011 10:18:21 +0000 (12:18 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 30 Jul 2011 10:18:21 +0000 (12:18 +0200)
src/ui/gui/automake.mk
src/ui/gui/factor-dialog.c
src/ui/gui/psppire-scanf.c [new file with mode: 0644]
src/ui/gui/psppire-scanf.h [new file with mode: 0644]
src/ui/gui/select-cases-dialog.c
src/ui/gui/t-test-options.c
src/ui/gui/text-data-import-dialog.c
src/ui/gui/widget-io.c
src/ui/gui/widget-io.h

index bdb695df1a8955e37bc29572d151889e753a424d..c815be991fa5cb3c2f12928b6a7338ed6644db61 100644 (file)
@@ -123,6 +123,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-buttonbox.c \
        src/ui/gui/psppire-hbuttonbox.c \
        src/ui/gui/psppire-vbuttonbox.c \
+       src/ui/gui/psppire-scanf.c \
+       src/ui/gui/psppire-scanf.h \
        src/ui/gui/psppire-acr.c \
        src/ui/gui/autorecode-dialog.c \
        src/ui/gui/autorecode-dialog.h \
index c10fa597c18fae9a5f562b5d9f4320bb82e4c781..f3fa2234cf7630db62fe381197c451ce4699c990 100644 (file)
@@ -28,7 +28,7 @@
 #include "psppire-data-window.h"
 #include "psppire-var-view.h"
 
-#include "widget-io.h"
+#include "psppire-scanf.h"
 
 #include "executor.h"
 #include "helper.h"
@@ -340,7 +340,7 @@ factor_dialog (PsppireDataWindow *dw)
 
   {
     GtkWidget *hbox = get_widget_assert (fd.xml, "hbox6");
-    GtkWidget *eigenvalue_extraction = widget_scanf (_("Eigenvalues over %4.2f times the mean eigenvalue"), &fd.mineigen);
+    GtkWidget *eigenvalue_extraction = psppire_scanf_new (_("Eigenvalues over %4.2f times the mean eigenvalue"), &fd.mineigen);
 
     fd.nfactors_toggle = get_widget_assert (fd.xml, "nfactors-radiobutton");
     fd.mineigen_toggle = get_widget_assert (fd.xml, "mineigen-radiobutton");
diff --git a/src/ui/gui/psppire-scanf.c b/src/ui/gui/psppire-scanf.c
new file mode 100644 (file)
index 0000000..2573c2e
--- /dev/null
@@ -0,0 +1,322 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   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/>. */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include "psppire-scanf.h"
+
+#include <gl/printf-parse.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xalloc.h"
+
+
+
+
+static void psppire_scanf_class_init          (PsppireScanfClass *class);
+static void psppire_scanf_init                (PsppireScanf      *w);
+
+G_DEFINE_TYPE (PsppireScanf, psppire_scanf, GTK_TYPE_HBOX)
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_FORMAT,
+  PROP_NCONV
+};
+
+/* Create a GtkLabel and pack it into BOX.
+   The label is created using part of the string at S, and the directives
+   at DIRS[DIR_IDX] and subsequent.
+
+   After this function returns, *S points to the first unused character.
+*/
+static void
+ship_label (GtkBox *box, const char **s,
+           const char_directives *dirs, size_t dir_idx)
+{
+  GtkWidget *label ;
+  GString *str = g_string_new (*s);
+
+  if ( dirs)
+    {
+      char_directive dir = dirs->dir[dir_idx];
+      int n = 0;
+
+      while (dir_idx < dirs->count && dir.conversion == '%' )
+       {
+         g_string_erase (str, dir.dir_start - *s, 1);
+         dir = dirs->dir[++dir_idx];
+         n++;
+       }
+
+      g_string_truncate (str, dir.dir_start - *s - n);
+
+      if ( dir_idx >= dirs->count)
+       *s = NULL;
+      else
+       *s = dir.dir_end;
+    }
+
+  label = gtk_label_new (str->str);
+
+  g_string_free (str, TRUE);
+
+  gtk_box_pack_start (box, label, FALSE, FALSE, 0);
+  gtk_widget_show (label);
+}
+
+static void
+guts (PsppireScanf *scanf)
+{
+  gint i;
+  arguments a;
+  const char *s = scanf->format;
+
+  /* Get the number of args into D */
+  g_return_if_fail (0 == printf_parse (scanf->format, &scanf->d, &a));
+
+  if ( scanf->d.count > 0)
+    scanf->widgets = xcalloc (sizeof (*scanf->widgets), scanf->d.count);
+
+  /* A is not used, so get rid of it */
+  if (a.arg != a.direct_alloc_arg)
+    free (a.arg);
+
+  for (i = 0 ; i < scanf->d.count ; ++i )
+    {
+      GtkWidget **w;
+      char_directive dir = scanf->d.dir[i];
+      int precision = 0;
+      int width = 0;
+
+      if ( dir.precision_start && dir.precision_end)
+       precision = strtol (dir.precision_start + 1,
+                           (char **) &dir.precision_end, 10);
+
+      if ( dir.width_start && dir.width_end )
+       width = strtol (dir.width_start, (char **) &dir.width_end, 10);
+
+      if ( dir.dir_start > s )
+       ship_label (GTK_BOX (scanf), &s, &scanf->d, i);
+
+      if ( dir.conversion == '%')
+       {
+         if (s) s++;
+         continue;
+       }
+
+      w = &scanf->widgets [dir.arg_index];
+      switch (dir.conversion)
+       {
+       case 'd':
+       case 'i':
+       case 'f':
+         {
+           *w = gtk_spin_button_new_with_range (0, 100.0, 1.0);
+           g_object_set (*w, "digits", precision, NULL);
+         }
+         break;
+       case 's':
+         *w = gtk_entry_new ();
+         break;
+       };
+      g_object_set (*w, "width-chars", width, NULL);
+      gtk_box_pack_start (GTK_BOX (scanf), *w, FALSE, FALSE, 0);
+      gtk_widget_show (*w);
+    }
+
+  if ( s && *s )
+    ship_label (GTK_BOX (scanf), &s, NULL, 0);
+
+}
+
+
+static void
+psppire_scanf_set_property (GObject         *object,
+                           guint            prop_id,
+                           const GValue    *value,
+                           GParamSpec      *pspec)
+{
+  PsppireScanf *scanf = PSPPIRE_SCANF (object);
+
+  switch (prop_id)
+    {
+    case PROP_FORMAT:
+      scanf->format = g_value_get_string (value);
+      guts (scanf);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+
+static void
+psppire_scanf_get_property (GObject         *object,
+                           guint            prop_id,
+                           GValue          *value,
+                           GParamSpec      *pspec)
+{
+  PsppireScanf *scanf = PSPPIRE_SCANF (object);
+
+  switch (prop_id)
+    {
+    case PROP_FORMAT:
+      g_value_set_string (value, scanf->format);
+      break;
+    case PROP_NCONV:
+      g_value_set_int (value, scanf->d.count);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+
+static GObjectClass *parent_class = NULL;
+
+static void
+psppire_scanf_dispose (GObject *obj)
+{
+  PsppireScanf *w = (PsppireScanf *)obj;
+
+  if (w->dispose_has_run)
+    return;
+
+  /* Make sure dispose does not run twice. */
+  w->dispose_has_run = TRUE;
+
+
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+psppire_scanf_finalize (GObject *obj)
+{
+  PsppireScanf *w = PSPPIRE_SCANF (obj);
+
+  free (w->widgets);
+
+  if (w->d.dir != w->d.direct_alloc_dir)
+    free (w->d.dir);
+
+   /* Chain up to the parent class */
+   G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+psppire_scanf_class_init (PsppireScanfClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  GParamSpec *format_spec =
+    g_param_spec_string ("format",
+                      "Format",
+                      "A Scanf style format string",
+                      NULL,
+                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+
+  GParamSpec *nconv_spec =
+    g_param_spec_int ("n-conv",
+                      "Conversions",
+                      "The number of conversions in the format string",
+                     0, G_MAXINT, 0,
+                      G_PARAM_READABLE);
+
+
+  parent_class = g_type_class_peek_parent (class);
+
+  object_class->dispose = psppire_scanf_dispose;
+  object_class->finalize = psppire_scanf_finalize;
+
+  object_class->set_property = psppire_scanf_set_property;
+  object_class->get_property = psppire_scanf_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_NCONV,
+                                   nconv_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_FORMAT,
+                                   format_spec);
+
+}
+
+
+
+static void
+psppire_scanf_init (PsppireScanf *w)
+{
+}
+
+gchar
+psppire_get_conversion_char (PsppireScanf *w, gint n)
+{
+  g_return_val_if_fail ( n < w->d.count, '\0');
+  return w->d.dir[n].conversion;
+}
+
+GtkWidget *
+psppire_scanf_get_child (PsppireScanf *w, gint n)
+{
+  g_return_val_if_fail ( n < w->d.count, NULL);
+  return w->widgets[n];
+}
+
+
+/*
+   This widget is a GtkHBox populated with GtkLabel and GtkEntry widgets.
+   Each conversion in FMT will cause a GtkEntry (possibly a GtkSpinButton) to
+   be created.  Any text between conversions produces a GtkLabel.
+   There should be N arguments following FMT should be of type GtkEntry **,
+   where N is the number of conversions.
+   These arguments will be filled with a pointer to the corresponding widgets.
+   Their properties may be changed, but they should not be unrefed.
+ */
+GtkWidget *
+psppire_scanf_new (const gchar *fmt, ...)
+{
+  gint n, i;
+  va_list ap;
+
+  GtkWidget *w = GTK_WIDGET (g_object_new (psppire_scanf_get_type (),
+                                  "format", fmt, NULL));
+
+  g_object_get (w, "n-conv", &n, NULL);
+
+  va_start (ap, fmt);
+
+  for (i = 0 ; i < n ; ++i )
+    {
+      GtkWidget **field;
+
+      if ( psppire_get_conversion_char (PSPPIRE_SCANF (w), i) == '%')
+       continue;
+
+      field = va_arg (ap, GtkWidget **);
+
+      *field = psppire_scanf_get_child (PSPPIRE_SCANF (w), i);
+    }
+  va_end (ap);
+
+  return w;
+}
diff --git a/src/ui/gui/psppire-scanf.h b/src/ui/gui/psppire-scanf.h
new file mode 100644 (file)
index 0000000..4d22aaf
--- /dev/null
@@ -0,0 +1,65 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   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 __PSPPIRE_SCANF_H__
+#define __PSPPIRE_SCANF_H__
+
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <gl/printf-parse.h>
+
+
+G_BEGIN_DECLS
+
+#define PSPPIRE_SCANF_TYPE            (psppire_scanf_get_type ())
+#define PSPPIRE_SCANF(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_SCANF_TYPE, PsppireScanf))
+#define PSPPIRE_SCANF_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PSPPIRE_SCANF_TYPE, PsppireScanfClass))
+#define PSPPIRE_IS_SCANF(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_SCANF_TYPE))
+#define PSPPIRE_IS_SCANF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_SCANF_TYPE))
+
+
+typedef struct _PsppireScanf       PsppireScanf;
+typedef struct _PsppireScanfClass  PsppireScanfClass;
+
+/* All members are private. */
+struct _PsppireScanf
+{
+  GtkHBox parent;
+  const gchar *format;
+
+  GtkWidget **widgets;
+  char_directives d;
+
+  gboolean dispose_has_run;
+};
+
+
+struct _PsppireScanfClass
+{
+  GtkHBoxClass parent_class;
+};
+
+
+GType          psppire_scanf_get_type        (void);
+GtkWidget*     psppire_scanf_new             (const gchar *fmt, ...);
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_SCANF_H__ */
index 381fc3dd8a104649404358b1abb5a7f4a7f08735..9febcafaaa252dbb69ff950984c79640e9fcc078 100644 (file)
@@ -25,6 +25,7 @@
 #include "dict-display.h"
 #include "dialog-common.h"
 #include "widget-io.h"
+#include "psppire-scanf.h"
 #include "helper.h"
 #include <xalloc.h>
 
@@ -103,7 +104,7 @@ sample_subdialog (GtkButton *b, gpointer data)
 
   if ( ! scd->hbox1 )
     {
-      scd->hbox1 = widget_scanf (gettext (label1), &scd->spinbutton);
+      scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
 
       gtk_widget_show (scd->hbox1);
 
@@ -120,7 +121,7 @@ sample_subdialog (GtkButton *b, gpointer data)
   if ( ! scd->hbox2 )
     {
       scd->hbox2 =
-       widget_scanf (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
+       psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
 
       gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
                                 1, case_count);
index 89fe3434d54ec5827711f11da59cc99c45f32c0e..d4656bf4a457bc811a08219df7624e32ce610ca1 100644 (file)
@@ -25,6 +25,7 @@
 #include "t-test-options.h"
 
 #include "widget-io.h"
+#include "psppire-scanf.h"
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
@@ -60,8 +61,7 @@ tt_options_dialog_create (GtkWindow *parent)
   tto->xml = builder_new ("t-test.ui");
 
   tto->confidence =
-    widget_scanf (_("Confidence Interval: %2d %%"),
-                 &tto->conf_percent);
+    psppire_scanf_new (_("Confidence Interval: %2d %%"), &tto->conf_percent);
 
   tto->dialog = get_widget_assert (tto->xml, "options-dialog");
 
index 215a444c4861ba2d5d2faa0117b0608158af982a..38d23fe083abe180b415dc0152c0c6916548e5d9 100644 (file)
@@ -43,7 +43,7 @@
 #include "ui/gui/psppire-dialog.h"
 #include "ui/gui/psppire-var-sheet.h"
 #include "ui/gui/psppire-var-store.h"
-#include "ui/gui/widget-io.h"
+#include "ui/gui/psppire-scanf.h"
 #include "ui/syntax-gen.h"
 
 #include "gl/error.h"
@@ -728,7 +728,7 @@ init_intro_page (struct import_assistant *ia)
 
   p->n_cases_spin = gtk_spin_button_new_with_range (0, INT_MAX, 100);
 
-  hbox_n_cases = widget_scanf (_("Only the first %4d cases"), &p->n_cases_spin);
+  hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &p->n_cases_spin);
 
   table  = get_widget_assert (builder, "button-table");
 
@@ -738,7 +738,7 @@ init_intro_page (struct import_assistant *ia)
 
   p->percent_spin = gtk_spin_button_new_with_range (0, 100, 10);
 
-  hbox_percent = widget_scanf (_("Only the first %3d %% of file (approximately)"), &p->percent_spin);
+  hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), &p->percent_spin);
 
   gtk_table_attach_defaults (GTK_TABLE (table), hbox_percent,
                             1, 2,
index 73a7301662033e366a1d8180692c131646b82aac..e04e32222d85cdc50f4052463f44191ffc8f2824 100644 (file)
 
 #include "xalloc.h"
 
-/* Create a GtkLabel and pack it into BOX.
-   The label is created using part of the string at S, and the directives
-   at DIRS[DIR_IDX] and subsequent.
-
-   After this function returns, *S points to the first unused character.
-*/
-static void
-ship_label (GtkBox *box, const char **s,
-           const char_directives *dirs, size_t dir_idx)
-{
-  GtkWidget *label ;
-  GString *str = g_string_new (*s);
-
-  if ( dirs)
-    {
-      char_directive dir = dirs->dir[dir_idx];
-      int n = 0;
-
-      while (dir_idx < dirs->count && dir.conversion == '%' )
-       {
-         g_string_erase (str, dir.dir_start - *s, 1);
-         dir = dirs->dir[++dir_idx];
-         n++;
-       }
-
-      g_string_truncate (str, dir.dir_start - *s - n);
-
-      if ( dir_idx >= dirs->count)
-       *s = NULL;
-      else
-       *s = dir.dir_end;
-    }
-
-  label = gtk_label_new (str->str);
-
-  g_string_free (str, TRUE);
-
-  gtk_box_pack_start (box, label, FALSE, FALSE, 0);
-  gtk_widget_show (label);
-}
 
 /* Returns a string generated from FMT and a list of GtkEntry widgets.
    Each conversion in FMT will be replaced with the text from the
@@ -139,104 +99,3 @@ widget_printf (const gchar *fmt, ...)
   g_string_free (output, FALSE);
   return text;
 }
-
-/*
-   Returns a GtkHBox populated with an GtkLabel and GtkEntry widgets.
-   Each conversion in FMT will cause a GtkEntry (possibly a GtkSpinButton) to
-   be created.  Any text between conversions produces a GtkLabel.
-   There should be N arguments following FMT should be of type GtkEntry **,
-   where N is the number of conversions.
-   These arguments will be filled with a pointer to the corresponding widgets.
-   Their properties may be changed, but they should not be unrefed.
- */
-GtkWidget *
-widget_scanf (const gchar *fmt, ...)
-{
-  char_directives d;
-  arguments a;
-  int i;
-  va_list ap;
-  GtkWidget ***widgets = NULL;
-  GtkWidget *hbox = NULL;
-  GtkWidget **w;
-  const char *s = fmt;
-
-  if ( 0 !=  printf_parse (fmt, &d, &a) )
-    return NULL;
-
-  if (a.arg != a.direct_alloc_arg)
-    free (a.arg);
-
-  va_start (ap, fmt);
-
-  if ( d.count > 0 )
-    {
-      hbox = gtk_hbox_new (FALSE, 0);
-      widgets = calloc (sizeof (*widgets), d.count);
-    }
-
-  for (i = 0 ; i < d.count ; ++i )
-    {
-      if ( d.dir[i].conversion != '%')
-       widgets[i] = va_arg (ap, GtkWidget **);
-    }
-  va_end (ap);
-
-
-
-  for (i = 0 ; i < d.count ; ++i )
-    {
-      char_directive dir = d.dir[i];
-      int precision = 0;
-      int width = 0;
-
-
-      if ( dir.precision_start && dir.precision_end)
-       precision = strtol (dir.precision_start + 1,
-                           (char **) &dir.precision_end, 10);
-
-      if ( dir.width_start && dir.width_end )
-       width = strtol (dir.width_start, (char **) &dir.width_end, 10);
-
-      if ( dir.dir_start > s )
-       ship_label (GTK_BOX (hbox), &s, &d, i);
-
-      if ( dir.conversion == '%')
-       {
-         if (s) s++;
-         continue;
-       }
-
-      w = widgets [dir.arg_index];
-      switch (dir.conversion)
-       {
-       case 'd':
-       case 'i':
-       case 'f':
-         {
-           *w = gtk_spin_button_new_with_range (0, 100.0, 1.0);
-           g_object_set (*w, "digits", precision, NULL);
-         }
-         break;
-       case 's':
-         *w = gtk_entry_new ();
-         break;
-       };
-
-      g_object_set (*w, "width-chars", width, NULL);
-      gtk_box_pack_start (GTK_BOX (hbox), *w, FALSE, FALSE, 0);
-      gtk_widget_show (*w);
-    }
-
-  if ( s && *s )
-    ship_label (GTK_BOX (hbox), &s, NULL, 0);
-
-
-
-  g_free (widgets);
-
-  if (d.dir != d.direct_alloc_dir)
-    free (d.dir);
-
-  return hbox;
-}
index 0fdb8caae7941557cddb22c4fd3d732d48f484ee..ee708f5426592d7337bd552d45b59da5d75a4635 100644 (file)
    The returned string should be freed when no longer required.
  */
 gchar * widget_printf (const gchar *fmt, ...);
-
-/*
-   Returns a GtkHBox populated with an GtkLabel and GtkEntry widgets.
-   Each conversion in FMT will cause a GtkEntry (possibly a GtkSpinButton) to
-   be created.  Any text between conversions produces a GtkLabel.
-   There should be N arguments following FMT should be of type GtkEntry **,
-   where N is the number of conversions.
-   These arguments will be filled with a pointer to the corresponding widgets.
-   Their properties may be changed, but they should not be unrefed.
- */
-GtkWidget *widget_scanf (const gchar *fmt, ...);