Fixed the refresh button on the dialogs.
[pspp-builds.git] / src / ui / gui / data-editor.c
index 077dff5b087e02d1d62dbf5dfdf5c021e378885b..111a8327c313d9f24e04dddf8c0a57b564340949 100644 (file)
 #include "helper.h"
 #include "about.h"
 #include "psppire-dialog.h"
-#include "psppire-var-select.h"
+#include "psppire-selector.h"
+#include "weight-cases-dialog.h"
+#include "split-file-dialog.h"
+#include "transpose-dialog.h"
+#include "sort-cases-dialog.h"
+#include "dict-display.h"
 
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 #include "data-editor.h"
 #include "syntax-editor.h"
+#include <language/syntax-string-source.h>
+#include <libpspp/syntax-gen.h>
 #include "window-manager.h"
 
 #include "psppire-data-store.h"
 #include "psppire-var-store.h"
 
-#include "weight-cases-dialog.h"
-
+static void register_data_editor_actions (struct data_editor *de);
 
 static void insert_variable (GtkCheckMenuItem *m, gpointer data);
 
@@ -109,8 +115,6 @@ disable_edit_clear (GtkWidget *w, gint x, gint y, gpointer data)
   return FALSE;
 }
 
-static void weight_cases_dialog (GObject *o, gpointer data);
-
 
 /*
   Create a new data editor.
@@ -123,17 +127,18 @@ new_data_editor (void)
   GtkSheet *var_sheet ;
   PsppireVarStore *vs;
 
-  de = g_malloc (sizeof (*de));
+  de = g_malloc0 (sizeof (*de));
 
   e = (struct editor_window *) de;
 
-  de->xml = glade_xml_new (PKGDATADIR "/data-editor.glade", NULL, NULL);
-
+  de->xml = XML_NEW ("data-editor.glade");
 
   var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
 
   vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
 
+  g_assert(vs); /* Traps a possible bug in win32 build */
+
   g_signal_connect (vs->dict, "weight-changed",
                    G_CALLBACK (on_weight_change),
                    de);
@@ -148,27 +153,63 @@ new_data_editor (void)
 
   connect_help (de->xml);
 
+
+  register_data_editor_actions (de);
+
   de->invoke_weight_cases_dialog =
     gtk_action_new ("weight-cases-dialog",
                    _("Weights"),
                    _("Weight cases by variable"),
                    "pspp-weight-cases");
 
-
   g_signal_connect (de->invoke_weight_cases_dialog, "activate",
                    G_CALLBACK (weight_cases_dialog), de);
 
+
+  de->invoke_transpose_dialog =
+    gtk_action_new ("transpose-dialog",
+                   _("Transpose"),
+                   _("Transpose the cases with the variables"),
+                   NULL);
+
+
+  g_signal_connect (de->invoke_transpose_dialog, "activate",
+                   G_CALLBACK (transpose_dialog), de);
+
+
+
+  de->invoke_split_file_dialog =
+    gtk_action_new ("split-file-dialog",
+                   _("Split"),
+                   _("Split the active file"),
+                   "pspp-split-file");
+
+  g_signal_connect (de->invoke_split_file_dialog, "activate",
+                   G_CALLBACK (split_file_dialog), de);
+
+
+
+  de->invoke_sort_cases_dialog =
+    gtk_action_new ("sort-cases-dialog",
+                   _("Sort"),
+                   _("Sort cases in the active file"),
+                   "pspp-sort-cases");
+
+  g_signal_connect (de->invoke_sort_cases_dialog, "activate",
+                   G_CALLBACK (sort_cases_dialog), de);
+
+
   e->window = GTK_WINDOW (get_widget_assert (de->xml, "data_editor"));
 
-  g_signal_connect (get_widget_assert (de->xml,"file_new_data"),
-                   "activate",
-                   G_CALLBACK (new_data_window),
-                   e->window);
+  g_signal_connect_swapped (get_widget_assert (de->xml,"file_new_data"),
+                           "activate",
+                           G_CALLBACK (gtk_action_activate),
+                           de->action_data_new);
 
-  g_signal_connect (get_widget_assert (de->xml,"file_open_data"),
-                   "activate",
-                   G_CALLBACK (open_data_window),
-                   e->window);
+  g_signal_connect_swapped (get_widget_assert (de->xml,"file_open_data"),
+                           "activate",
+                           G_CALLBACK (gtk_action_activate),
+                           de->action_data_open);
 
   g_signal_connect (get_widget_assert (de->xml,"file_new_syntax"),
                    "activate",
@@ -180,6 +221,16 @@ new_data_editor (void)
                    G_CALLBACK (open_syntax_window),
                    e->window);
 
+  g_signal_connect_swapped (get_widget_assert (de->xml,"file_save"),
+                           "activate",
+                           G_CALLBACK (gtk_action_activate),
+                           de->action_data_save);
+
+  g_signal_connect_swapped (get_widget_assert (de->xml,"file_save_as"),
+                           "activate",
+                           G_CALLBACK (gtk_action_activate),
+                           de->action_data_save_as);
+
 
   g_signal_connect (get_widget_assert (de->xml,"edit_clear"),
                    "activate",
@@ -196,12 +247,17 @@ new_data_editor (void)
                            get_widget_assert (de->xml, "data_weight-cases")
                            );
 
-  /* 
-  g_signal_connect (get_widget_assert (de->xml,"data_weight-cases"),
-                   "activate",
-                   G_CALLBACK (weight_cases_dialog),
-                   de);
-  */
+  gtk_action_connect_proxy (de->invoke_transpose_dialog,
+                           get_widget_assert (de->xml, "data_transpose")
+                           );
+
+  gtk_action_connect_proxy (de->invoke_split_file_dialog,
+                           get_widget_assert (de->xml, "data_split-file")
+                           );
+
+  gtk_action_connect_proxy (de->invoke_sort_cases_dialog,
+                           get_widget_assert (de->xml, "data_sort-cases")
+                           );
 
 
   g_signal_connect (get_widget_assert (de->xml,"help_about"),
@@ -282,11 +338,22 @@ new_data_editor (void)
                    "toggled",
                    G_CALLBACK (value_labels_toggled), de);
 
+  gtk_action_connect_proxy (de->action_data_open,
+                           get_widget_assert (de->xml, "button-open")
+                           );
+
+  gtk_action_connect_proxy (de->action_data_save,
+                           get_widget_assert (de->xml, "button-save")
+                           );
 
   gtk_action_connect_proxy (de->invoke_weight_cases_dialog,
                            get_widget_assert (de->xml, "button-weight-cases")
                            );
 
+  gtk_action_connect_proxy (de->invoke_split_file_dialog,
+                           get_widget_assert (de->xml, "button-split-file")
+                           );
+
   g_signal_connect (get_widget_assert (de->xml, "file_quit"),
                    "activate",
                    G_CALLBACK (file_quit), de);
@@ -297,7 +364,6 @@ new_data_editor (void)
                    G_CALLBACK (minimise_all_windows), NULL);
 
 
-
   select_sheet (de, PAGE_DATA_SHEET);
 
   return de;
@@ -348,8 +414,6 @@ click2column (GtkWidget *w, gint col, gpointer data)
 }
 
 
-
-
 void
 new_data_window (GtkMenuItem *menuitem, gpointer parent)
 {
@@ -412,59 +476,6 @@ data_editor_select_sheet (struct data_editor *de, gint page)
 }
 
 
-void
-open_data_window (GtkMenuItem *menuitem, gpointer parent)
-{
-  bool finished = FALSE;
-
-  GtkWidget *dialog;
-
-  GtkFileFilter *filter ;
-
-  dialog = gtk_file_chooser_dialog_new (_("Open"),
-                                       GTK_WINDOW (parent),
-                                       GTK_FILE_CHOOSER_ACTION_OPEN,
-                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-                                       NULL);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
-  gtk_file_filter_add_pattern (filter, "*.sav");
-  gtk_file_filter_add_pattern (filter, "*.SAV");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
-  gtk_file_filter_add_pattern (filter, "*.por");
-  gtk_file_filter_add_pattern (filter, "*.POR");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("All Files"));
-  gtk_file_filter_add_pattern (filter, "*");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  do {
-
-    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
-      {
-       gchar *file_name =
-         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
-
-       g_free (file_name);
-      }
-    else
-      finished = TRUE;
-
-  } while ( ! finished ) ;
-
-  gtk_widget_destroy (dialog);
-}
-
-
-
-
 static void
 status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data)
 {
@@ -701,12 +712,6 @@ on_split_change (PsppireDict *dict, gpointer data)
     {
       gint i;
       GString *text;
-      GtkSheet *var_sheet =
-       GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
-
-      PsppireVarStore *vs = PSPPIRE_VAR_STORE
-       (gtk_sheet_get_model (var_sheet) );
-
       struct variable *const * split_vars = dict_get_split_vars (dict->dict);
 
       text = g_string_new (_("Split by "));
@@ -787,50 +792,285 @@ on_weight_change (GObject *o, gint weight_index, gpointer data)
 }
 
 
+
+\f
+static void data_save_as_dialog (GtkAction *, struct data_editor *de);
+static void new_file (GtkAction *, struct editor_window *de);
+static void open_data_dialog (GtkAction *, struct data_editor *de);
+static void data_save (GtkAction *action, struct data_editor *e);
+
+
+/* Create the GtkActions and connect to their signals */
 static void
-weight_cases_dialog (GObject *o, gpointer data)
+register_data_editor_actions (struct data_editor *de)
 {
-  gint response;
-  struct data_editor *de = data;
-  GtkSheet *var_sheet =
-    GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
+  de->action_data_open =
+    gtk_action_new ("data-open-dialog",
+                   _("Open"),
+                   _("Open a data file"),
+                   "gtk-open");
 
+  g_signal_connect (de->action_data_open, "activate",
+                   G_CALLBACK (open_data_dialog), de);
 
-  GladeXML *xml = glade_xml_new (PKGDATADIR "/psppire.glade",
-                                "weight-cases-dialog", NULL);
 
+  de->action_data_save = gtk_action_new ("data-save",
+                                           _("Save"),
+                                           _("Save data to file"),
+                                           "gtk-save");
 
-  GtkWidget *treeview =  get_widget_assert (xml, "treeview");
-  GtkWidget *entry =  get_widget_assert (xml, "entry1");
+  g_signal_connect (de->action_data_save, "activate",
+                   G_CALLBACK (data_save), de);
 
 
-  PsppireVarStore *vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
 
-  PsppireVarSelect *select = psppire_var_select_new (treeview,
-                                                    entry, vs->dict);
+  de->action_data_save_as = gtk_action_new ("data-save-as-dialog",
+                                           _("Save As"),
+                                           _("Save data to file"),
+                                           "gtk-save");
 
+  g_signal_connect (de->action_data_save_as, "activate",
+                   G_CALLBACK (data_save_as_dialog), de);
 
-  PsppireDialog *dialog = create_weight_dialog (select, xml);
+  de->action_data_new =
+    gtk_action_new ("data-new",
+                   _("New"),
+                   _("New data file"),
+                   NULL);
 
-  response = psppire_dialog_run (dialog);
+  g_signal_connect (de->action_data_new, "activate",
+                   G_CALLBACK (new_file), de);
+}
 
-  g_object_unref (xml);
+/* Returns true if NAME has a suffix which might denote a PSPP file */
+static gboolean
+name_has_suffix (const gchar *name)
+{
+  if ( g_str_has_suffix (name, ".sav"))
+    return TRUE;
+  if ( g_str_has_suffix (name, ".SAV"))
+    return TRUE;
+  if ( g_str_has_suffix (name, ".por"))
+    return TRUE;
+  if ( g_str_has_suffix (name, ".POR"))
+    return TRUE;
 
-  if (response == GTK_RESPONSE_OK)
+  return FALSE;
+}
+
+/* Append SUFFIX to the filename of DE */
+static void
+append_filename_suffix (struct data_editor *de, const gchar *suffix)
+{
+  if ( ! name_has_suffix (de->file_name))
     {
-      const GList *list = psppire_var_select_get_variables (select);
+      gchar *s = de->file_name;
+      de->file_name = g_strconcat (de->file_name, suffix, NULL);
+      g_free (s);
+    }
+}
 
-      g_assert ( g_list_length (list) <= 1 );
+/* Save DE to file */
+static void
+save_file (struct data_editor *de)
+{
+  struct getl_interface *sss;
+  struct string file_name ;
 
-      if ( list == NULL)
-       psppire_dict_set_weight_variable (select->dict, NULL);
-      else
-       {
-         struct variable *var = list->data;
+  g_assert (de->file_name);
 
-         psppire_dict_set_weight_variable (select->dict, var);
-       }
+  ds_init_cstr (&file_name, de->file_name);
+  gen_quoted_string (&file_name);
+
+  if ( de->save_as_portable )
+    {
+      append_filename_suffix (de, ".por");
+      sss = create_syntax_string_source ("EXPORT OUTFILE=%s.",
+                                        ds_cstr (&file_name));
     }
+  else
+    {
+      append_filename_suffix (de, ".sav");
+      sss = create_syntax_string_source ("SAVE OUTFILE=%s.",
+                                        ds_cstr (&file_name));
+    }
+
+  ds_destroy (&file_name);
+
+  execute_syntax (sss);
+}
+
+
+/* Callback for data_save action.
+   If there's an existing file name, then just save,
+   otherwise prompt for a file name, then save */
+static void
+data_save (GtkAction *action, struct data_editor *de)
+{
+  if ( de->file_name)
+    save_file (de);
+  else
+    data_save_as_dialog (action, de);
 }
 
 
+/* Callback for data_save_as action. Prompt for a filename and save */
+static void
+data_save_as_dialog (GtkAction *action, struct data_editor *de)
+{
+  struct editor_window *e = (struct editor_window *) de;
+
+  GtkWidget *button_sys;
+  GtkWidget *dialog =
+    gtk_file_chooser_dialog_new (_("Save"),
+                                GTK_WINDOW (e->window),
+                                GTK_FILE_CHOOSER_ACTION_SAVE,
+                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                NULL);
+
+  GtkFileFilter *filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
+  gtk_file_filter_add_pattern (filter, "*.sav");
+  gtk_file_filter_add_pattern (filter, "*.SAV");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
+  gtk_file_filter_add_pattern (filter, "*.por");
+  gtk_file_filter_add_pattern (filter, "*.POR");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("All Files"));
+  gtk_file_filter_add_pattern (filter, "*");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  {
+    GtkWidget *button_por;
+    GtkWidget *vbox = gtk_vbox_new (TRUE, 5);
+    button_sys =
+      gtk_radio_button_new_with_label (NULL, _("System File"));
+
+    button_por =
+      gtk_radio_button_new_with_label
+      (gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_sys)),
+       _("Portable File"));
+
+    gtk_box_pack_start_defaults (GTK_BOX (vbox), button_sys);
+    gtk_box_pack_start_defaults (GTK_BOX (vbox), button_por);
+
+    gtk_widget_show_all (vbox);
+
+    gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
+  }
+
+  switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+    {
+    case GTK_RESPONSE_ACCEPT:
+      {
+       g_free (de->file_name);
+
+       de->file_name =
+         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+       de->save_as_portable =
+         ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_sys));
+
+       save_file (de);
+
+       window_set_name_from_filename (e, de->file_name);
+      }
+      break;
+    default:
+      break;
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+
+/* Callback for data_new action.
+   Performs the NEW FILE command */
+static void
+new_file (GtkAction *action, struct editor_window *e)
+{
+  struct data_editor *de = (struct data_editor *) e;
+
+  struct getl_interface *sss =
+    create_syntax_string_source ("NEW FILE.");
+
+  execute_syntax (sss);
+
+  g_free (de->file_name);
+  de->file_name = NULL;
+
+  default_window_name (e);
+}
+
+
+/* Callback for the data_open action.
+   Prompts for a filename and opens it */
+static void
+open_data_dialog (GtkAction *action, struct data_editor *de)
+{
+  struct editor_window *e = (struct editor_window *) de;
+
+  GtkWidget *dialog =
+    gtk_file_chooser_dialog_new (_("Open"),
+                                GTK_WINDOW (e->window),
+                                GTK_FILE_CHOOSER_ACTION_OPEN,
+                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                NULL);
+
+  GtkFileFilter *filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
+  gtk_file_filter_add_pattern (filter, "*.sav");
+  gtk_file_filter_add_pattern (filter, "*.SAV");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
+  gtk_file_filter_add_pattern (filter, "*.por");
+  gtk_file_filter_add_pattern (filter, "*.POR");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("All Files"));
+  gtk_file_filter_add_pattern (filter, "*");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+    {
+    case GTK_RESPONSE_ACCEPT:
+      {
+       struct getl_interface *sss;
+       struct string filename;
+       g_free (de->file_name);
+       de->file_name =
+         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+       ds_init_cstr (&filename, de->file_name);
+
+       gen_quoted_string (&filename);
+
+       sss = create_syntax_string_source ("GET FILE=%s.",
+                                          ds_cstr (&filename));
+
+       execute_syntax (sss);
+       ds_destroy (&filename);
+
+       window_set_name_from_filename (e, de->file_name);
+      }
+      break;
+    default:
+      break;
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+
+
+