From: Ben Pfaff <blp@cs.stanford.edu>
Date: Sun, 19 Aug 2012 17:30:36 +0000 (-0700)
Subject: psppire-dialog: Add "acceptable" predicate.
X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3f06028950f69cd695062fe01a64ba73e164b3e;p=pspp

psppire-dialog: Add "acceptable" predicate.

PsppireDialog already has a validity predicate that allows a dialog
to easily disable "OK" and other buttons when the dialog has not
yet been completely filled.  It should usually be obvious to the
user why this is the case.

The upcoming GObjectification of the missing value dialog calls for
a different kind of predicate, one where the reason is not obvious
to the user (typically because he has just made a typo or does not
understand a variable's format).  In this case, the user needs more
feedback, such as a message explaining the problem.

This commit therefore introduces a second kind of predicate, the
"accept" predicate.  This predicate is only checked when the user
clicks on the "OK" button.
---

diff --git a/src/ui/gui/psppire-buttonbox.c b/src/ui/gui/psppire-buttonbox.c
index ac40058dba..24d82d27d3 100644
--- a/src/ui/gui/psppire-buttonbox.c
+++ b/src/ui/gui/psppire-buttonbox.c
@@ -215,6 +215,14 @@ close_and_respond (GtkWidget *w, gint response)
   psppire_dialog_close (dialog);
 }
 
+static gboolean
+is_acceptable (GtkWidget *w)
+{
+  GtkWidget *toplevel = gtk_widget_get_toplevel (w);
+
+  return (PSPPIRE_IS_DIALOG (toplevel)
+          && psppire_dialog_is_acceptable (PSPPIRE_DIALOG (toplevel)));
+}
 
 static void
 close_dialog (GtkWidget *w, gpointer data)
@@ -225,27 +233,31 @@ close_dialog (GtkWidget *w, gpointer data)
 static void
 continue_button_clicked (GtkWidget *w, gpointer data)
 {
-  close_and_respond (w, PSPPIRE_RESPONSE_CONTINUE);
+  if (is_acceptable (w))
+    close_and_respond (w, PSPPIRE_RESPONSE_CONTINUE);
 }
 
 
 static void
 ok_button_clicked (GtkWidget *w, gpointer data)
 {
-  close_and_respond (w, GTK_RESPONSE_OK);
+  if (is_acceptable (w))
+    close_and_respond (w, GTK_RESPONSE_OK);
 }
 
 
 static void
 paste_button_clicked (GtkWidget *w, gpointer data)
 {
-  close_and_respond (w, PSPPIRE_RESPONSE_PASTE);
+  if (is_acceptable (w))
+    close_and_respond (w, PSPPIRE_RESPONSE_PASTE);
 }
 
 static void
 goto_button_clicked (GtkWidget *w, gpointer data)
 {
-  close_and_respond (w, PSPPIRE_RESPONSE_GOTO);
+  if (is_acceptable (w))
+    close_and_respond (w, PSPPIRE_RESPONSE_GOTO);
 }
 
 
diff --git a/src/ui/gui/psppire-dialog.c b/src/ui/gui/psppire-dialog.c
index 7bdcaaecf1..547ff2a4da 100644
--- a/src/ui/gui/psppire-dialog.c
+++ b/src/ui/gui/psppire-dialog.c
@@ -324,6 +324,8 @@ psppire_dialog_init (PsppireDialog *dialog)
   dialog->box = NULL;
   dialog->contents_are_valid = NULL;
   dialog->validity_data = NULL;
+  dialog->contents_are_acceptable = NULL;
+  dialog->acceptable_data = NULL;
   dialog->slidable = FALSE;
 
   g_value_init (&value, orientation_spec->value_type);
@@ -547,6 +549,10 @@ psppire_orientation_get_type (void)
 }
 
 
+/* Sets a predicate function that is checked after each change that the user
+   makes to the dialog's state.  If the predicate function returns false, then
+   "OK" and other buttons that accept the dialog's settings will be
+   disabled. */
 void
 psppire_dialog_set_valid_predicate (PsppireDialog *dialog,
 				    ContentsAreValid contents_are_valid,
@@ -556,6 +562,30 @@ psppire_dialog_set_valid_predicate (PsppireDialog *dialog,
   dialog->validity_data = data;
 }
 
+/* Sets a predicate function that is called after "OK" or another button that
+   accepts the dialog's settings is pushed.  If the predicate function returns
+   false, then the button push is ignored.  (If the predicate function returns
+   false, then it should take some action to notify the user why the contents
+   are unacceptable, e.g. pop up a dialog box.)
+
+   An accept predicate is preferred over a validity predicate when the reason
+   why the dialog settings are unacceptable may not be obvious to the user, so
+   that the user needs a helpful message to explain. */
+void
+psppire_dialog_set_accept_predicate (PsppireDialog *dialog,
+                                     ContentsAreValid contents_are_acceptable,
+                                     gpointer data)
+{
+  dialog->contents_are_acceptable = contents_are_acceptable;
+  dialog->acceptable_data = data;
+}
+
+gboolean
+psppire_dialog_is_acceptable (const PsppireDialog *dialog)
+{
+  return (dialog->contents_are_acceptable == NULL
+          || dialog->contents_are_acceptable (dialog->acceptable_data));
+}
 
 
 
diff --git a/src/ui/gui/psppire-dialog.h b/src/ui/gui/psppire-dialog.h
index 3b01557ec7..af56aac1e8 100644
--- a/src/ui/gui/psppire-dialog.h
+++ b/src/ui/gui/psppire-dialog.h
@@ -63,6 +63,8 @@ struct _PsppireDialog
 
   ContentsAreValid contents_are_valid;
   gpointer validity_data;
+  ContentsAreValid contents_are_acceptable;
+  gpointer acceptable_data;
   gboolean slidable;
   PsppireOrientation orientation;
 };
@@ -82,6 +84,10 @@ gint           psppire_dialog_run             (PsppireDialog *);
 void           psppire_dialog_set_valid_predicate (PsppireDialog *,
 						   ContentsAreValid,
 						   gpointer );
+void           psppire_dialog_set_accept_predicate (PsppireDialog *,
+                                                    ContentsAreValid,
+                                                    gpointer );
+gboolean       psppire_dialog_is_acceptable (const PsppireDialog *);
 void           psppire_dialog_notify_change (PsppireDialog *);