}
}
+
+/* Return TRUE if the dialog box's widgets' state are such that clicking OK
+ might not result in erroneous syntax being generated */
+static gboolean
+contents_plausible (gpointer data)
+{
+ struct compute_dialog *cd = data;
+
+ GtkWidget *target = get_widget_assert (cd->xml, "compute-entry1");
+ GtkWidget *syntax_area = get_widget_assert (cd->xml, "compute-textview1");
+ GtkTextBuffer *buffer =
+ gtk_text_view_get_buffer (GTK_TEXT_VIEW (syntax_area));
+
+ if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (target))))
+ return FALSE;
+
+ if ( gtk_text_buffer_get_char_count (buffer) == 0 )
+ return FALSE;
+
+ return TRUE;
+}
+
/* Pops up the Compute dialog box */
void
compute_dialog (GObject *o, gpointer data)
vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
+
scd.dict = vs->dict;
scd.use_type = FALSE;
scd.xml = xml;
+ psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog),
+ contents_plausible, &scd);
+
g_signal_connect (target, "changed", G_CALLBACK (on_target_change), &scd);
g_signal_connect (dialog, "refresh", G_CALLBACK (refresh), &scd);
}
+
+static void
+on_validity_change (GtkWidget *toplevel, gboolean valid, gpointer data)
+{
+ PsppireButtonBox *bb = data;
+
+ /* Set the sensitivity of all the 'executive order' buttons */
+ gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_OK]), valid);
+ gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_PASTE]), valid);
+ gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_GOTO]), valid);
+ gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_CONTINUE]), valid);
+}
+
+static void
+on_realize (GtkWidget *buttonbox, gpointer data)
+{
+ GtkWidget *toplevel = gtk_widget_get_toplevel (buttonbox);
+
+ if ( PSPPIRE_IS_DIALOG (toplevel))
+ {
+ g_signal_connect (toplevel, "validity-changed",
+ G_CALLBACK (on_validity_change), buttonbox);
+ }
+}
+
static void
psppire_button_box_init (PsppireButtonBox *bb)
{
g_value_unset (&value);
}
+
+ g_signal_connect (bb, "realize", G_CALLBACK (on_realize), NULL);
}
#include <gtk/gtk.h>
#include <gtk/gtksignal.h>
#include "psppire-dialog.h"
+#include "psppire-buttonbox.h"
+#include "psppire-selector.h"
static void psppire_dialog_class_init (PsppireDialogClass *);
static void psppire_dialog_init (PsppireDialog *);
enum {DIALOG_REFRESH,
+ VALIDITY_CHANGED,
n_SIGNALS};
static guint signals [n_SIGNALS];
0);
+ signals [VALIDITY_CHANGED] =
+ g_signal_new ("validity-changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+
object_class->finalize = psppire_dialog_finalize;
}
{
GValue value = {0};
dialog->box = NULL;
+ dialog->contents_are_valid = NULL;
+ dialog->validity_data = NULL;
g_value_init (&value, orientation_spec->value_type);
g_param_value_set_default (orientation_spec, &value);
return GTK_WIDGET (dialog) ;
}
+
+static void
+notify_change (PsppireDialog *dialog)
+{
+ if ( dialog->contents_are_valid )
+ {
+ gboolean valid = dialog->contents_are_valid (dialog->validity_data);
+
+ g_signal_emit (dialog, signals [VALIDITY_CHANGED], 0, valid);
+ }
+}
+
+
+/* Descend the widget tree, connecting appropriate signals to the
+ notify_change callback */
+static void
+connect_notify_signal (GtkWidget *w, gpointer data)
+{
+ PsppireDialog *dialog = data;
+
+ if ( PSPPIRE_IS_BUTTONBOX (w))
+ return;
+
+
+
+ if ( GTK_IS_CONTAINER (w))
+ {
+ gtk_container_foreach (GTK_CONTAINER (w),
+ connect_notify_signal,
+ dialog);
+ }
+
+
+ /* It's unfortunate that GTK+ doesn't have a generic
+ "user-modified-state-changed" signal. Instead, we have to try and
+ predict what widgets and signals are likely to exist in our dialogs. */
+
+ if ( GTK_IS_TOGGLE_BUTTON (w))
+ {
+ g_signal_connect_swapped (w, "toggled", G_CALLBACK (notify_change),
+ dialog);
+ }
+
+ if ( PSPPIRE_IS_SELECTOR (w))
+ {
+ g_signal_connect_swapped (w, "selected", G_CALLBACK (notify_change),
+ dialog);
+
+ g_signal_connect_swapped (w, "de-selected", G_CALLBACK (notify_change),
+ dialog);
+ }
+
+ if ( GTK_IS_EDITABLE (w))
+ {
+ g_signal_connect_swapped (w, "changed", G_CALLBACK (notify_change),
+ dialog);
+ }
+
+ if ( GTK_IS_CELL_EDITABLE (w))
+ {
+ g_signal_connect_swapped (w, "editing-done", G_CALLBACK (notify_change),
+ dialog);
+ }
+
+ if ( GTK_IS_TEXT_VIEW (w))
+ {
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w));
+
+ g_signal_connect_swapped (buffer, "changed", G_CALLBACK (notify_change),
+ dialog);
+ }
+
+ if ( GTK_IS_TREE_VIEW (w))
+ {
+ gint i = 0;
+ GtkTreeView *tv = GTK_TREE_VIEW (w);
+ GtkTreeSelection *selection =
+ gtk_tree_view_get_selection (tv);
+ GtkTreeViewColumn *col;
+
+ g_signal_connect_swapped (selection, "changed",
+ G_CALLBACK (notify_change), dialog);
+
+ while ((col = gtk_tree_view_get_column (tv, i++)))
+ {
+ GList *renderers = gtk_tree_view_column_get_cell_renderers (col);
+ GList *start = renderers;
+ while (renderers)
+ {
+ if ( GTK_IS_CELL_RENDERER_TOGGLE (renderers->data))
+ g_signal_connect_swapped (renderers->data, "toggled",
+ G_CALLBACK (notify_change), dialog);
+ renderers = renderers->next;
+ }
+ g_list_free (start);
+ }
+ }
+}
+
+
gint
psppire_dialog_run (PsppireDialog *dialog)
{
+ if ( dialog->contents_are_valid != NULL )
+ gtk_container_foreach (GTK_CONTAINER (dialog->box),
+ connect_notify_signal,
+ dialog);
+
dialog->loop = g_main_loop_new (NULL, FALSE);
gtk_widget_show (GTK_WIDGET (dialog));
+ if ( dialog->contents_are_valid != NULL)
+ g_signal_emit (dialog, signals [VALIDITY_CHANGED], 0, FALSE);
+
g_signal_emit (dialog, signals [DIALOG_REFRESH], 0);
g_main_loop_run (dialog->loop);
}
return etype;
}
+
+
+void
+psppire_dialog_set_valid_predicate (PsppireDialog *dialog,
+ ContentsAreValid contents_are_valid,
+ gpointer data)
+{
+ dialog->contents_are_valid = contents_are_valid;
+ dialog->validity_data = data;
+}
+
+