From efcd93af16dfc6c6c9f60b71d94cc091d2417e17 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Sat, 30 Jul 2011 12:18:21 +0200 Subject: [PATCH] Replaced the function widget_scanf with a new widget psppire_scanf --- src/ui/gui/automake.mk | 2 + src/ui/gui/factor-dialog.c | 4 +- src/ui/gui/psppire-scanf.c | 322 +++++++++++++++++++++++++++ src/ui/gui/psppire-scanf.h | 65 ++++++ src/ui/gui/select-cases-dialog.c | 5 +- src/ui/gui/t-test-options.c | 4 +- src/ui/gui/text-data-import-dialog.c | 6 +- src/ui/gui/widget-io.c | 141 ------------ src/ui/gui/widget-io.h | 11 - 9 files changed, 399 insertions(+), 161 deletions(-) create mode 100644 src/ui/gui/psppire-scanf.c create mode 100644 src/ui/gui/psppire-scanf.h diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index bdb695df..c815be99 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -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 \ diff --git a/src/ui/gui/factor-dialog.c b/src/ui/gui/factor-dialog.c index c10fa597..f3fa2234 100644 --- a/src/ui/gui/factor-dialog.c +++ b/src/ui/gui/factor-dialog.c @@ -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 index 00000000..2573c2e3 --- /dev/null +++ b/src/ui/gui/psppire-scanf.c @@ -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 . */ + +#include +#include +#include "psppire-scanf.h" + +#include +#include +#include +#include +#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 index 00000000..4d22aafc --- /dev/null +++ b/src/ui/gui/psppire-scanf.h @@ -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 . */ + + +#ifndef __PSPPIRE_SCANF_H__ +#define __PSPPIRE_SCANF_H__ + + +#include +#include +#include + +#include + + +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__ */ diff --git a/src/ui/gui/select-cases-dialog.c b/src/ui/gui/select-cases-dialog.c index 381fc3dd..9febcafa 100644 --- a/src/ui/gui/select-cases-dialog.c +++ b/src/ui/gui/select-cases-dialog.c @@ -25,6 +25,7 @@ #include "dict-display.h" #include "dialog-common.h" #include "widget-io.h" +#include "psppire-scanf.h" #include "helper.h" #include @@ -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); diff --git a/src/ui/gui/t-test-options.c b/src/ui/gui/t-test-options.c index 89fe3434..d4656bf4 100644 --- a/src/ui/gui/t-test-options.c +++ b/src/ui/gui/t-test-options.c @@ -25,6 +25,7 @@ #include "t-test-options.h" #include "widget-io.h" +#include "psppire-scanf.h" #include #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"); diff --git a/src/ui/gui/text-data-import-dialog.c b/src/ui/gui/text-data-import-dialog.c index 215a444c..38d23fe0 100644 --- a/src/ui/gui/text-data-import-dialog.c +++ b/src/ui/gui/text-data-import-dialog.c @@ -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, diff --git a/src/ui/gui/widget-io.c b/src/ui/gui/widget-io.c index 73a73016..e04e3222 100644 --- a/src/ui/gui/widget-io.c +++ b/src/ui/gui/widget-io.c @@ -28,46 +28,6 @@ #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; -} diff --git a/src/ui/gui/widget-io.h b/src/ui/gui/widget-io.h index 0fdb8caa..ee708f54 100644 --- a/src/ui/gui/widget-io.h +++ b/src/ui/gui/widget-io.h @@ -25,14 +25,3 @@ 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, ...); -- 2.30.2