Rename GtkSheet to PsppireSheet
[pspp-builds.git] / src / ui / gui / text-data-import-dialog.c
index d8df668f197ff91dae430d4557a8aa495c1f07c3..92e3f893026ad110499eb45eb949e450356b6c45 100644 (file)
 
 #include <config.h>
 
+#include <gtk/gtk.h>
+
+
+
 #include "checkbox-treeview.h"
 #include "descriptives-dialog.h"
 
 #include <errno.h>
-#include <gtk/gtk.h>
-#include <gtksheet/gtksheet.h>
+
+#include <gtksheet/psppire-sheet.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+
+#if !GTK_CHECK_VERSION (2, 10, 0)
+
+void
+text_data_import_assistant (GObject *o, gpointer de_)
+{
+  struct data_editor *de = de_;
+
+  GtkWidget *dialog =
+    gtk_message_dialog_new  (de->parent.window,
+                            GTK_DIALOG_MODAL,
+                            GTK_MESSAGE_WARNING,
+                            GTK_BUTTONS_CLOSE,
+                            _("The text import assistant has not been "
+                              "compiled into this build of PSPPIRE, because "
+                              "GTK+ version 2.10.0 or later was not available."));
+
+  gtk_dialog_run (GTK_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog);
+}
+
+#else
+
 /* TextImportModel, a GtkTreeModel used by the text data import
    dialog. */
 enum
@@ -89,6 +117,7 @@ struct assistant
     GtkWidget *paste_button;
     GtkWidget *reset_button;
     int response;
+    int watch_cursor;
 
     GtkCellRenderer *prop_renderer;
     GtkCellRenderer *fixed_renderer;
@@ -222,6 +251,8 @@ static GtkTreeViewColumn *make_data_column (struct import_assistant *,
 static GtkTreeView *create_data_tree_view (bool input, GtkContainer *parent,
                                            struct import_assistant *);
 static void escape_underscores (const char *in, char *out);
+static void push_watch_cursor (struct import_assistant *);
+static void pop_watch_cursor (struct import_assistant *);
 
 /* Pops up the Text Data Import assistant. */
 void
@@ -229,34 +260,39 @@ text_data_import_assistant (GObject *o, gpointer de_)
 {
   struct data_editor *de = de_;
   GtkWindow *parent_window = de->parent.window;
-  struct import_assistant ia = { { 0, } };
+  struct import_assistant *ia;
 
-  if (!init_file (&ia, parent_window))
-    return;
+  ia = xzalloc (sizeof *ia);
+  if (!init_file (ia, parent_window))
+    {
+      free (ia);
+      return;
+    }
 
-  init_assistant (&ia, parent_window);
-  init_intro_page (&ia);
-  init_first_line_page (&ia);
-  init_separators_page (&ia);
-  init_formats_page (&ia);
+  init_assistant (ia, parent_window);
+  init_intro_page (ia);
+  init_first_line_page (ia);
+  init_separators_page (ia);
+  init_formats_page (ia);
 
-  gtk_widget_show_all (GTK_WIDGET (ia.asst.assistant));
+  gtk_widget_show_all (GTK_WIDGET (ia->asst.assistant));
 
-  ia.asst.main_loop = g_main_loop_new (NULL, false);
-  g_main_loop_run (ia.asst.main_loop);
+  ia->asst.main_loop = g_main_loop_new (NULL, false);
+  g_main_loop_run (ia->asst.main_loop);
+  g_main_loop_unref (ia->asst.main_loop);
 
-  switch (ia.asst.response)
+  switch (ia->asst.response)
     {
     case GTK_RESPONSE_APPLY:
       {
-       char *syntax = generate_syntax (&ia);
+       char *syntax = generate_syntax (ia);
        execute_syntax (create_syntax_string_source (syntax));
        free (syntax);
       }
       break;
     case PSPPIRE_RESPONSE_PASTE:
       {
-       char *syntax = generate_syntax (&ia);
+       char *syntax = generate_syntax (ia);
        struct syntax_editor *se =
          (struct syntax_editor *) window_create (WINDOW_SYNTAX, NULL);
        gtk_text_buffer_insert_at_cursor (se->buffer, syntax, -1);
@@ -267,10 +303,11 @@ text_data_import_assistant (GObject *o, gpointer de_)
       break;
     }
 
-  destroy_formats_page (&ia);
-  destroy_separators_page (&ia);
-  destroy_assistant (&ia);
-  destroy_file (&ia);
+  destroy_formats_page (ia);
+  destroy_separators_page (ia);
+  destroy_assistant (ia);
+  destroy_file (ia);
+  free (ia);
 }
 
 /* Emits PSPP syntax to S that applies the dictionary attributes
@@ -624,6 +661,7 @@ add_page_to_assistant (struct import_assistant *ia,
   gtk_assistant_append_page (ia->asst.assistant, content);
   gtk_assistant_set_page_type (ia->asst.assistant, content, type);
   gtk_assistant_set_page_title (ia->asst.assistant, content, title_copy);
+  gtk_assistant_set_page_complete (ia->asst.assistant, content, true);
 
   free (title_copy);
 
@@ -647,11 +685,6 @@ on_prepare (GtkAssistant *assistant, GtkWidget *page,
     gtk_widget_show (ia->asst.paste_button);
   else
     gtk_widget_hide (ia->asst.paste_button);
-
-  /* Make the user visit each page in the assistant once.  Seems
-     like a reasonable user interface, plus visiting the final
-     page is what constructs the dictionary. */
-  gtk_assistant_set_page_complete (assistant, page, true);
 }
 
 /* Called when the Cancel button in the assistant is clicked. */
@@ -1276,6 +1309,9 @@ static void
 revise_fields_preview (struct import_assistant *ia)
 {
   GtkWidget *w;
+
+  push_watch_cursor (ia);
+
   w = GTK_WIDGET (ia->separators.fields_tree_view);
   gtk_widget_destroy (w);
   get_separators (ia);
@@ -1285,6 +1321,8 @@ revise_fields_preview (struct import_assistant *ia)
     true,
     GTK_CONTAINER (get_widget_assert (ia->asst.xml, "fields-scroller")),
     ia);
+
+  pop_watch_cursor (ia);
 }
 
 /* Sets the widgets to match IA's separators substructure. */
@@ -1530,6 +1568,8 @@ prepare_formats_page (struct import_assistant *ia)
   unsigned long int number = 0;
   size_t column_idx;
 
+  push_watch_cursor (ia);
+
   dict = dict_create ();
   fg = fmt_guesser_create ();
   for (column_idx = 0; column_idx < s->column_cnt; column_idx++)
@@ -1583,12 +1623,10 @@ prepare_formats_page (struct import_assistant *ia)
      hold a reference via ia->formats.dict. */
   var_store = psppire_var_store_new (psppire_dict);
   g_object_set (var_store,
-                "trailing-rows", 1,
                 "format-type", PSPPIRE_VAR_STORE_INPUT_FORMATS,
                 (void *) NULL);
   var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
   g_object_set (var_sheet,
-                "row-geometry", var_store,
                 "model", var_store,
                 "may-create-vars", FALSE,
                 (void *) NULL);
@@ -1605,6 +1643,8 @@ prepare_formats_page (struct import_assistant *ia)
     false,
     GTK_CONTAINER (get_widget_assert (ia->asst.xml, "data-scroller")),
     ia);
+
+  pop_watch_cursor (ia);
 }
 
 /* Clears the set of user-modified variables from IA's formats
@@ -1643,6 +1683,8 @@ on_variable_change (PsppireDict *dict, int dict_idx,
   GtkTreeView *tv = ia->formats.data_tree_view;
   gint column_idx = dict_idx + 1;
 
+  push_watch_cursor (ia);
+
   /* Remove previous column and replace with new column. */
   gtk_tree_view_remove_column (tv, gtk_tree_view_get_column (tv, column_idx));
   gtk_tree_view_insert_column (tv, make_data_column (ia, tv, false, dict_idx),
@@ -1665,6 +1707,8 @@ on_variable_change (PsppireDict *dict, int dict_idx,
     var_destroy (p->modified_vars[dict_idx]);
   p->modified_vars[dict_idx]
     = var_clone (psppire_dict_get_variable (dict, dict_idx));
+
+  pop_watch_cursor (ia);
 }
 
 /* Parses the contents of the field at (ROW,COLUMN) according to
@@ -1802,6 +1846,19 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
   GtkTreeModel *tree_model;
   bool ok;
 
+  /* Check that WIDGET is really visible on the screen before we
+     do anything else.  This is a bug fix for a sticky situation:
+     when text_data_import_assistant() returns, it frees the data
+     necessary to compose the tool tip message, but there may be
+     a tool tip under preparation at that point (even if there is
+     no visible tool tip) that will call back into us a little
+     bit later.  Perhaps the correct solution to this problem is
+     to make the data related to the tool tips part of a GObject
+     that only gets destroyed when all references are released,
+     but this solution appears to be effective too. */
+  if (!GTK_WIDGET_MAPPED (widget))
+    return FALSE;
+
   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
                                                      wx, wy, &bx, &by);
   if (!gtk_tree_view_get_path_at_pos (tree_view, bx, by,
@@ -2223,3 +2280,34 @@ text_import_model_iter_to_row (const GtkTreeIter *iter)
   assert (iter->stamp == TREE_MODEL_STAMP);
   return GPOINTER_TO_INT (iter->user_data);
 }
+
+/* Increments the "watch cursor" level, setting the cursor for
+   the assistant window to a watch face to indicate to the user
+   that the ongoing operation may take some time. */
+static void
+push_watch_cursor (struct import_assistant *ia)
+{
+  if (++ia->asst.watch_cursor == 1)
+    {
+      GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);
+      GdkDisplay *display = gtk_widget_get_display (widget);
+      GdkCursor *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+      gdk_window_set_cursor (widget->window, cursor);
+      gdk_cursor_unref (cursor);
+      gdk_display_flush (display);
+    }
+}
+
+/* Decrements the "watch cursor" level.  If the level reaches
+   zero, the cursor is reset to its default shape. */
+static void
+pop_watch_cursor (struct import_assistant *ia)
+{
+  if (--ia->asst.watch_cursor == 0)
+    {
+      GtkWidget *widget = GTK_WIDGET (ia->asst.assistant);;
+      gdk_window_set_cursor (widget->window, NULL);
+    }
+}
+
+#endif