+
+void
+psppire_dialog_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
+ psppire_dialog_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 (psppire_dialog_notify_change),
+ dialog);
+ }
+
+ if ( PSPPIRE_IS_SELECTOR (w))
+ {
+ g_signal_connect_swapped (w, "selected",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+
+ g_signal_connect_swapped (w, "de-selected",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+ }
+
+ if ( GTK_IS_EDITABLE (w))
+ {
+ g_signal_connect_swapped (w, "changed",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+ }
+
+ if ( GTK_IS_CELL_EDITABLE (w))
+ {
+ g_signal_connect_swapped (w, "editing-done",
+ G_CALLBACK (psppire_dialog_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 (psppire_dialog_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;
+ GtkTreeModel *model = gtk_tree_view_get_model (tv);
+
+ if ( model)
+ {
+ g_signal_connect_swapped (model, "row-changed",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+
+ g_signal_connect_swapped (model, "row-deleted",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+
+ g_signal_connect_swapped (model, "row-inserted",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+ }
+
+ g_signal_connect_swapped (selection, "changed",
+ G_CALLBACK (psppire_dialog_notify_change),
+ dialog);
+
+ while ((col = gtk_tree_view_get_column (tv, i++)))
+ {
+ GList *renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
+ GList *start = renderers;
+ while (renderers)
+ {
+ if ( GTK_IS_CELL_RENDERER_TOGGLE (renderers->data))
+ g_signal_connect_swapped (renderers->data, "toggled",
+ G_CALLBACK (psppire_dialog_notify_change), dialog);
+ renderers = renderers->next;
+ }
+ g_list_free (start);
+ }
+ }
+}
+
+