Add html target to output viewer clipboard
[pspp] / src / ui / gui / psppire-output-window.c
index b079cf1d4ce8c1cc358cbef64eb74901383e323c..f2580b7b16ca225844caa6ecc5bb150fc8d49658 100644 (file)
@@ -32,7 +32,7 @@
 #include <output/tab.h>
 #include <stdlib.h>
 
-#include "about.h"
+#include "help-menu.h"
 
 #include "psppire-output-window.h"
 
@@ -50,6 +50,7 @@
 enum
   {
     COL_TITLE,                  /* Table title. */
+    COL_ADDR,                   /* Pointer to the table */
     COL_Y,                      /* Y position of top of title. */
     N_COLS
   };
@@ -312,6 +313,7 @@ psppire_output_submit (struct output_driver *this,
         }
       gtk_tree_store_set (store, &iter,
                           COL_TITLE, ds_cstr (&title),
+                         COL_ADDR, item, 
                           COL_Y, viewer->y,
                           -1);
       ds_destroy (&title);
@@ -525,25 +527,229 @@ psppire_output_window_export (PsppireOutputWindow *window)
   gtk_widget_destroy (dialog);
 }
 
+
+enum {
+  SELECT_FMT_NULL,
+  SELECT_FMT_TEXT,
+  SELECT_FMT_UTF8,
+  SELECT_FMT_HTML
+};
+
+
+static void
+insert_glyph (struct string_map *map, const char *opt, gunichar glyph)
+{
+  char s[6] = {0,0,0,0,0,0};
+
+  g_unichar_to_utf8 (glyph, s);
+  string_map_insert (map, opt, s);
+}
+
+struct glyph_pair
+{
+  gunichar glyph;
+  char opt[10];
+};
+
+struct glyph_pair table[] = {
+  {0x250C, "box[1100]"},
+  {0x2518, "box[0011]"},
+  {0x2510, "box[0110]"},
+  {0x2514, "box[1001]"},
+  {0x2502, "box[0101]"},
+  {0x2500, "box[1010]"},
+  {0x2534, "box[1011]"},
+  {0x252C, "box[1110]"},
+  {0x2501, "box[2020]"},
+  {0x2503, "box[0202]"},
+  {0x253F, "box[2121]"},
+  {0x2542, "box[1212]"},
+  {0x254B, "box[2222]"},
+  {0x2525, "box[0121]"},
+  {0x2530, "box[1210]"},
+  {0x2538, "box[1012]"},
+  {0x251D, "box[2101]"},
+  {0x2537, "box[2021]"},
+  {0x252F, "box[2120]"}
+};
+
+
+static void
+utf8_box_chars (struct string_map *map)
+{
+  int i;
+  for (i = 0; i < sizeof (table) / sizeof (table[0]); ++i)
+    {
+      const struct glyph_pair *p = &table[i];
+      insert_glyph (map, p->opt, p->glyph);
+    }
+}
+
+
+
+static void
+clipboard_get_cb (GtkClipboard     *clipboard,
+                 GtkSelectionData *selection_data,
+                 guint             info,
+                 gpointer          data)
+{
+  PsppireOutputWindow *window = data;
+
+  gsize length;
+  gchar *text = NULL;
+  struct output_driver *driver = NULL;
+  char *filename = NULL;
+  struct string_map options;
+
+  GtkTreeSelection *sel = gtk_tree_view_get_selection (window->overview);
+  GtkTreeModel *model = gtk_tree_view_get_model (window->overview);
+
+  GList *rows = gtk_tree_selection_get_selected_rows (sel, &model);
+  GList *n = rows;
+
+  if ( n == NULL)
+    return;
+
+  string_map_init (&options);
+  filename = tempnam (NULL, NULL);
+  string_map_insert (&options, "output-file", filename);
+
+  switch (info)
+    {
+    case SELECT_FMT_UTF8:
+      utf8_box_chars (&options);
+      /* fall-through */
+
+    case SELECT_FMT_TEXT:
+      string_map_insert (&options, "format", "txt");
+      break;
+
+    case SELECT_FMT_HTML:
+      string_map_insert (&options, "format", "html");
+      break;
+
+    default:
+      goto finish;
+      break;
+    }
+
+  driver = output_driver_create (&options);
+  if (driver == NULL)
+    goto finish;
+
+  while (n)
+    {
+      GtkTreePath *path = n->data ; 
+      GtkTreeIter iter;
+      struct output_item *item ;
+
+      gtk_tree_model_get_iter (model, &iter, path);
+      gtk_tree_model_get (model, &iter, COL_ADDR, &item, -1);
+
+      driver->class->submit (driver, item);
+
+      n = n->next;
+    }
+
+  if ( driver->class->flush)
+    driver->class->flush (driver);
+
+  if ( g_file_get_contents (filename, &text, &length, NULL) )
+    {
+      gtk_selection_data_set (selection_data, selection_data->target,
+                             8,
+                             (const guchar *) text, length);
+    }
+
+ finish:
+
+  output_driver_destroy (driver);
+  g_free (text);
+
+  unlink (filename);
+  free (filename);
+
+  g_list_free (rows);
+}
+
+static void
+clipboard_clear_cb (GtkClipboard *clipboard,
+                   gpointer data)
+{
+}
+
+static const GtkTargetEntry targets[] = {
+
+  { "STRING",        0, SELECT_FMT_TEXT },
+  { "TEXT",          0, SELECT_FMT_TEXT },
+  { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
+  { "text/plain",    0, SELECT_FMT_TEXT },
+
+  { "UTF8_STRING",   0, SELECT_FMT_UTF8 },
+  { "text/plain;charset=utf-8", 0, SELECT_FMT_UTF8 },
+
+  { "text/html",     0, SELECT_FMT_HTML }
+};
+
+static void
+on_copy (PsppireOutputWindow *window)
+{
+  {
+    GtkClipboard *clipboard =
+      gtk_widget_get_clipboard (GTK_WIDGET (window),
+                               GDK_SELECTION_CLIPBOARD);
+
+    if (!gtk_clipboard_set_with_data (clipboard, targets,
+                                      G_N_ELEMENTS (targets),
+                                      clipboard_get_cb, clipboard_clear_cb,
+                                     window))
+
+      clipboard_clear_cb (clipboard, window);
+  }
+}
+
+static void
+on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action)
+{
+  /* The Copy action is available only if there is something selected */
+  gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0);
+}
+
 static void
 psppire_output_window_init (PsppireOutputWindow *window)
 {
   GtkTreeViewColumn *column;
   GtkCellRenderer *renderer;
   GtkBuilder *xml;
+  GtkAction *copy_action;
+  GtkTreeSelection *sel;
 
   xml = builder_new ("output-viewer.ui");
 
+  copy_action = get_action_assert (xml, "edit_copy");
+
+  gtk_action_set_sensitive (copy_action, FALSE);
+
+  g_signal_connect_swapped (copy_action, "activate", G_CALLBACK (on_copy), window);
+
   gtk_widget_reparent (get_widget_assert (xml, "vbox1"), GTK_WIDGET (window));
 
   window->output = GTK_LAYOUT (get_widget_assert (xml, "output"));
   window->y = 0;
 
   window->overview = GTK_TREE_VIEW (get_widget_assert (xml, "overview"));
+
+  sel = gtk_tree_view_get_selection (window->overview);
+
+  gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
+
+  g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change), copy_action);
+
   gtk_tree_view_set_model (window->overview,
                            GTK_TREE_MODEL (gtk_tree_store_new (
                                              N_COLS,
-                                             G_TYPE_STRING, /* COL_TITLE */
+                                             G_TYPE_STRING,  /* COL_TITLE */
+                                            G_TYPE_POINTER, /* COL_ADDR */
                                              G_TYPE_LONG))); /* COL_Y */
 
   window->in_command = false;
@@ -570,16 +776,6 @@ psppire_output_window_init (PsppireOutputWindow *window)
                    G_CALLBACK (cancel_urgency),
                    NULL);
 
-  g_signal_connect (get_action_assert (xml,"help_about"),
-                   "activate",
-                   G_CALLBACK (about_new),
-                   window);
-
-  g_signal_connect (get_action_assert (xml,"help_reference"),
-                   "activate",
-                   G_CALLBACK (reference_manual),
-                   NULL);
-
   g_signal_connect (get_action_assert (xml,"windows_minimise-all"),
                    "activate",
                    G_CALLBACK (psppire_window_minimise_all),
@@ -587,9 +783,10 @@ psppire_output_window_init (PsppireOutputWindow *window)
 
   {
     GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (xml, "uimanager1", GTK_TYPE_UI_MANAGER));
+    merge_help_menu (uim);
 
     PSPPIRE_WINDOW (window)->menu =
-      GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar1/windows_menuitem/windows_minimise-all")->parent);
+      GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows_menuitem/windows_minimise-all")->parent);
   }
 
   g_signal_connect_swapped (get_action_assert (xml, "file_export"), "activate",
@@ -617,23 +814,53 @@ psppire_output_window_new (void)
 
 
 \f
+static void
+create_xr_print_driver (GtkPrintContext *context, PsppireOutputWindow *window)
+{
+  struct string_map options;
+  GtkPageSetup *page_setup;
+  double width, height;
+  double left_margin;
+  double right_margin;
+  double top_margin;
+  double bottom_margin;
+
+  page_setup = gtk_print_context_get_page_setup (context);
+  width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
+  height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
+  left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM);
+  right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM);
+  top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM);
+  bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM);
+
+  string_map_init (&options);
+  string_map_insert_nocopy (&options, xstrdup ("paper-size"),
+                            xasprintf("%.2fx%.2fmm", width, height));
+  string_map_insert_nocopy (&options, xstrdup ("left-margin"),
+                            xasprintf ("%.2fmm", left_margin));
+  string_map_insert_nocopy (&options, xstrdup ("right-margin"),
+                            xasprintf ("%.2fmm", right_margin));
+  string_map_insert_nocopy (&options, xstrdup ("top-margin"),
+                            xasprintf ("%.2fmm", top_margin));
+  string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
+                            xasprintf ("%.2fmm", bottom_margin));
+
+  window->print_xrd =
+    xr_driver_create (gtk_print_context_get_cairo_context (context), &options);
 
+  string_map_destroy (&options);
+}
 
 static gboolean
 paginate (GtkPrintOperation *operation,
          GtkPrintContext   *context,
          PsppireOutputWindow *window)
 {
-  g_print ("%s\n", __FUNCTION__);
-
   if ( window->print_item < window->n_items )
     {
-      g_print ("Passing item %d\n", window->print_item);
       xr_driver_output_item (window->print_xrd, window->items[window->print_item++]);
-      bool x = xr_driver_need_new_page (window->print_xrd);
-      if ( x )
+      if (xr_driver_need_new_page (window->print_xrd))
        {
-         g_print ("Need new page: %d\n", x);
          xr_driver_next_page (window->print_xrd, NULL);
          window->print_n_pages ++;
        }
@@ -641,36 +868,20 @@ paginate (GtkPrintOperation *operation,
     }
   else
     {
-      struct string_map options = STRING_MAP_INITIALIZER (options);
-      g_print ("Number of pages is %d\n", window->print_n_pages);
       gtk_print_operation_set_n_pages (operation, window->print_n_pages);
       window->print_item = 0;
-
-      //      xr_driver_destroy (window->print_xrd);
-
-      window->print_xrd =
-       xr_driver_create (gtk_print_context_get_cairo_context (context), &options);
-
-      string_map_destroy (&options);
-
+      create_xr_print_driver (context, window);
       return TRUE;
     }
 }
 
-
 static void
 begin_print (GtkPrintOperation *operation,
             GtkPrintContext   *context,
             PsppireOutputWindow *window)
 {
-  g_print ("%s\n", __FUNCTION__);
-
-  struct string_map options = STRING_MAP_INITIALIZER (options);
-
-  window->print_xrd =
-    xr_driver_create (gtk_print_context_get_cairo_context (context), &options);
+  create_xr_print_driver (context, window);
 
-  string_map_destroy (&options);
   window->print_item = 0;
   window->print_n_pages = 1;
 }
@@ -680,16 +891,7 @@ end_print (GtkPrintOperation *operation,
           GtkPrintContext   *context,
           PsppireOutputWindow *window)
 {
-  g_print ("%s\n", __FUNCTION__);
-  //  xr_driver_destroy (window->print_xrd);
-}
-
-static void
-done (GtkPrintOperation *operation,
-      GtkPrintOperationResult   result,
-      gpointer           user_data)    
-{
-  g_print ("%s %d\n", __FUNCTION__, result);
+  xr_driver_destroy (window->print_xrd);
 }
 
 
@@ -699,8 +901,6 @@ draw_page (GtkPrintOperation *operation,
           gint               page_number,
           PsppireOutputWindow *window)
 {
-  g_print ("%s: %d\n", __FUNCTION__, page_number);
-
   xr_driver_next_page (window->print_xrd, gtk_print_context_get_cairo_context (context));
   while ( window->print_item < window->n_items)
     {
@@ -725,7 +925,6 @@ psppire_output_window_print (PsppireOutputWindow *window)
   g_signal_connect (print, "end_print", G_CALLBACK (end_print),     window);
   g_signal_connect (print, "paginate", G_CALLBACK (paginate),       window);
   g_signal_connect (print, "draw_page", G_CALLBACK (draw_page),     window);
-  g_signal_connect (print, "done", G_CALLBACK (done),               window);
 
   res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
                                  GTK_WINDOW (window), NULL);