psppire-dialog: Add "acceptable" predicate.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 19 Aug 2012 17:30:36 +0000 (10:30 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 19 Aug 2012 18:37:35 +0000 (11:37 -0700)
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.

src/ui/gui/psppire-buttonbox.c
src/ui/gui/psppire-dialog.c
src/ui/gui/psppire-dialog.h

index ac40058dba77a0c219185c1bd89c78497647b8b2..24d82d27d3ac9a9b2e139cf2306880c98dd4bb81 100644 (file)
@@ -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);
 }
 
 
index 7bdcaaecf1330a3a4bb449b614b65911f15a4f47..547ff2a4da25c155411b177fbc8ded3ce8ff943b 100644 (file)
@@ -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));
+}
 
 
 
index 3b01557ec7ebe05303185cbd3b4ee9f04e291f1e..af56aac1e8a8fcff9de48d088329f8ac96c9c17a 100644 (file)
@@ -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 *);