X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-output-window.c;h=b2e821e2e5060a902f7555b9b7cc261416ff2a62;hb=03d066d9f7e4f3d076a63e64708633bdf5e1c93c;hp=542e7b302c725f4caef14673e650d276382b7eeb;hpb=20f2c8b593eba29c2cca67569a5ef5bb68189c54;p=pspp-builds.git diff --git a/src/ui/gui/psppire-output-window.c b/src/ui/gui/psppire-output-window.c index 542e7b30..b2e821e2 100644 --- a/src/ui/gui/psppire-output-window.c +++ b/src/ui/gui/psppire-output-window.c @@ -20,11 +20,13 @@ #include #include "helper.h" +#include #include +#include #include -#include -#include -#include +#include +#include +#include #include #include "about.h" @@ -42,7 +44,12 @@ #define _(msgid) gettext (msgid) #define N_(msgid) msgid - +enum + { + COL_TITLE, /* Table title. */ + COL_Y, /* Y position of top of title. */ + N_COLS + }; static void psppire_output_window_base_finalize (PsppireOutputWindowClass *, gpointer); static void psppire_output_window_base_init (PsppireOutputWindowClass *class); @@ -88,10 +95,29 @@ psppire_output_window_finalize (GObject *object) } +static void +psppire_output_window_dispose (GObject *obj) +{ + PsppireOutputWindow *viewer = PSPPIRE_OUTPUT_WINDOW (obj); + size_t i; + + for (i = 0; i < viewer->n_items; i++) + output_item_unref (viewer->items[i]); + free (viewer->items); + viewer->items = NULL; + viewer->n_items = viewer->allocated_items = 0; + + /* Chain up to the parent class */ + G_OBJECT_CLASS (parent_class)->dispose (obj); +} + static void psppire_output_window_class_init (PsppireOutputWindowClass *class) { + GObjectClass *object_class = G_OBJECT_CLASS (class); + parent_class = g_type_class_peek_parent (class); + object_class->dispose = psppire_output_window_dispose; } @@ -113,107 +139,112 @@ psppire_output_window_base_finalize (PsppireOutputWindowClass *class, /* Output driver class. */ -static PsppireOutputWindow *the_output_viewer = NULL; +struct psppire_output_driver + { + struct output_driver driver; + PsppireOutputWindow *viewer; + struct xr_driver *xr; + }; + +static struct output_driver_class psppire_output_class; + +static struct psppire_output_driver * +psppire_output_cast (struct output_driver *driver) +{ + assert (driver->class == &psppire_output_class); + return UP_CAST (driver, struct psppire_output_driver, driver); +} static gboolean expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) { - struct som_entity *entity = g_object_get_data (G_OBJECT (widget), "entity"); - GdkWindow *window = widget->window; - cairo_t *cairo = gdk_cairo_create (GDK_DRAWABLE (window)); - struct outp_driver *driver = xr_create_driver (cairo); /* XXX can fail */ - struct tab_table *t = entity->ext; - void *rendering; - - rendering = entity->class->render_init (entity, driver, tab_l (t), - tab_r (t), tab_t (t), tab_b (t)); - - entity->class->title (rendering, 0, 0, - entity->table_num, entity->subtable_num, - entity->command_name); - entity->class->render (rendering, tab_l (t), tab_t (t), - tab_nc (t) - tab_r (t), - tab_nr (t) - tab_b (t)); - - entity->class->render_free (rendering); - driver->class->close_driver (driver); - outp_free_driver (driver); + struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering"); + cairo_t *cr; + + cr = gdk_cairo_create (widget->window); + xr_rendering_draw (r, cr); + cairo_destroy (cr); + return TRUE; } static void -psppire_output_submit (struct outp_driver *this, struct som_entity *entity) +psppire_output_submit (struct output_driver *this, + const struct output_item *item) { - if (the_output_viewer == NULL) + struct psppire_output_driver *pod = psppire_output_cast (this); + PsppireOutputWindow *viewer; + GtkWidget *drawing_area; + struct xr_rendering *r; + cairo_t *cr; + int tw, th; + + if (pod->viewer == NULL) { - the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ()); - gtk_widget_show_all (GTK_WIDGET (the_output_viewer)); + pod->viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ()); + gtk_widget_show_all (GTK_WIDGET (pod->viewer)); + pod->viewer->driver = pod; } + viewer = pod->viewer; - if (entity->type == SOM_TABLE) - { - GdkWindow *window = GTK_WIDGET (the_output_viewer)->window; - cairo_t *cairo = gdk_cairo_create (GDK_DRAWABLE (window)); - struct outp_driver *driver = xr_create_driver (cairo); /* XXX can fail */ - struct tab_table *t = entity->ext; - GtkWidget *drawing_area; - void *rendering; - int tw, th; - - tab_ref (t); - rendering = entity->class->render_init (entity, driver, tab_l (t), - tab_r (t), tab_t (t), tab_b (t)); - entity->class->area (rendering, &tw, &th); - - drawing_area = gtk_drawing_area_new (); - gtk_widget_modify_bg (GTK_WIDGET (drawing_area), GTK_STATE_NORMAL, - >k_widget_get_style (drawing_area)->base[GTK_STATE_NORMAL]); - g_object_set_data (G_OBJECT (drawing_area), - "entity", som_entity_clone (entity)); - gtk_widget_set_size_request (drawing_area, tw / 1024, th / 1024); - gtk_layout_put (the_output_viewer->output, drawing_area, - 0, the_output_viewer->y); - gtk_widget_show (drawing_area); - g_signal_connect (G_OBJECT (drawing_area), "expose_event", - G_CALLBACK (expose_event_callback), NULL); - - entity->class->render_free (rendering); - driver->class->close_driver (driver); - outp_free_driver (driver); - - if (tw / 1024 > the_output_viewer->max_width) - the_output_viewer->max_width = tw / 1024; - the_output_viewer->y += th / 1024; - - gtk_layout_set_size (the_output_viewer->output, - the_output_viewer->max_width, the_output_viewer->y); - } + cr = gdk_cairo_create (GTK_WIDGET (pod->viewer)->window); + if (pod->xr == NULL) + pod->xr = xr_create_driver (cr); + + r = xr_rendering_create (pod->xr, item, cr); + if (r == NULL) + goto done; - gtk_window_set_urgency_hint (GTK_WINDOW (the_output_viewer), TRUE); + if (viewer->n_items >= viewer->allocated_items) + viewer->items = x2nrealloc (viewer->items, &viewer->allocated_items, + sizeof *viewer->items); + viewer->items[viewer->n_items++] = output_item_ref (item); + + xr_rendering_measure (r, &tw, &th); + + drawing_area = gtk_drawing_area_new (); + gtk_widget_modify_bg ( + GTK_WIDGET (drawing_area), GTK_STATE_NORMAL, + >k_widget_get_style (drawing_area)->base[GTK_STATE_NORMAL]); + g_object_set_data (G_OBJECT (drawing_area), "rendering", r); + gtk_widget_set_size_request (drawing_area, tw, th); + gtk_layout_put (pod->viewer->output, drawing_area, 0, pod->viewer->y); + gtk_widget_show (drawing_area); + g_signal_connect (G_OBJECT (drawing_area), "expose_event", + G_CALLBACK (expose_event_callback), NULL); + + if (pod->viewer->max_width < tw) + pod->viewer->max_width = tw; + pod->viewer->y += th; + + gtk_layout_set_size (pod->viewer->output, + pod->viewer->max_width, pod->viewer->y); + + gtk_window_set_urgency_hint (GTK_WINDOW (pod->viewer), TRUE); + +done: + cairo_destroy (cr); } -static struct outp_class psppire_output_class = +static struct output_driver_class psppire_output_class = { "PSPPIRE", /* name */ - true, /* special */ - NULL, /* open_driver */ - NULL, /* close_driver */ - NULL, /* open_page */ - NULL, /* close_page */ - NULL, /* flush */ + NULL, /* create */ + NULL, /* destroy */ psppire_output_submit, /* submit */ - NULL, /* line */ - NULL, /* text_metrics */ - NULL, /* text_draw */ - NULL, /* initialise_chart */ - NULL, /* finalise_chart */ + NULL, /* flush */ }; void psppire_output_window_setup (void) { - outp_register_driver (outp_allocate_driver (&psppire_output_class, - "PSPPIRE", 0)); + struct psppire_output_driver *pod; + struct output_driver *d; + + pod = xzalloc (sizeof *pod); + d = &pod->driver; + output_driver_init (d, &psppire_output_class, "PSPPIRE", 0); + output_driver_register (d); } int viewer_length = 16; @@ -228,7 +259,7 @@ on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data) gtk_widget_destroy (GTK_WIDGET (ow)); - the_output_viewer = NULL; + ow->driver->viewer = NULL; return FALSE; } @@ -241,17 +272,185 @@ cancel_urgency (GtkWindow *window, gpointer data) gtk_window_set_urgency_hint (window, FALSE); } +static void +on_row_activate (GtkTreeView *overview, + GtkTreePath *path, + GtkTreeViewColumn *column, + PsppireOutputWindow *window) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GtkAdjustment *vadj; + GValue value = {0}; + double y, min, max; + + model = gtk_tree_view_get_model (overview); + if (!gtk_tree_model_get_iter (model, &iter, path)) + return; + + gtk_tree_model_get_value (model, &iter, COL_Y, &value); + y = g_value_get_long (&value); + g_value_unset (&value); + + vadj = gtk_layout_get_vadjustment (window->output); + min = vadj->lower; + max = vadj->upper - vadj->page_size; + if (y < min) + y = min; + else if (y > max) + y = max; + gtk_adjustment_set_value (vadj, y); +} + +static GtkFileFilter * +add_filter (GtkFileChooser *chooser, const char *name, const char *pattern) +{ + GtkFileFilter *filter = gtk_file_filter_new (); + g_object_ref_sink (G_OBJECT (filter)); + gtk_file_filter_set_name (filter, name); + gtk_file_filter_add_pattern (filter, pattern); + gtk_file_chooser_add_filter (chooser, filter); + return filter; +} + +static void +export_output (PsppireOutputWindow *window, struct string_map *options, + const char *class_name) +{ + struct output_driver *driver; + size_t i; + + driver = output_driver_create (class_name, options); + if (driver == NULL) + return; + + for (i = 0; i < window->n_items; i++) + driver->class->submit (driver, window->items[i]); + output_driver_destroy (driver); +} + +static void +psppire_output_window_export (PsppireOutputWindow *window) +{ + gint response; + + GtkFileFilter *pdf_filter; + GtkFileFilter *html_filter; + GtkFileFilter *odt_filter; + GtkFileFilter *txt_filter; + GtkFileFilter *ps_filter; + GtkFileFilter *csv_filter; + GtkFileChooser *chooser; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new (_("Export Output"), + GTK_WINDOW (window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER (dialog); + + pdf_filter = add_filter (chooser, _("PDF Files (*.pdf)"), "*.pdf"); + html_filter = add_filter (chooser, _("HTML Files (*.html)"), "*.html"); + odt_filter = add_filter (chooser, _("OpenDocument Files (*.odt)"), "*.odt"); + txt_filter = add_filter (chooser, _("Text Files (*.txt)"), "*.txt"); + ps_filter = add_filter (chooser, _("PostScript Files (*.ps)"), "*.ps"); + csv_filter = add_filter (chooser, _("Comma-Separated Value Files (*.csv)"), + "*.csv"); + + gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE); + gtk_file_chooser_set_filter (chooser, pdf_filter); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if ( response == GTK_RESPONSE_ACCEPT ) + { + char *filename = gtk_file_chooser_get_filename (chooser); + GtkFileFilter *filter = gtk_file_chooser_get_filter (chooser); + struct string_map options; + + g_return_if_fail (filename); + g_return_if_fail (filter); + + string_map_init (&options); + string_map_insert (&options, "output-file", filename); + if (filter == pdf_filter) + { + string_map_insert (&options, "output-type", "pdf"); + export_output (window, &options, "cairo"); + } + else if (filter == html_filter) + export_output (window, &options, "html"); + else if (filter == odt_filter) + export_output (window, &options, "odf"); + else if (filter == txt_filter) + { + string_map_insert (&options, "headers", "false"); + string_map_insert (&options, "paginate", "false"); + string_map_insert (&options, "squeeze", "true"); + string_map_insert (&options, "emphasis", "none"); + string_map_insert (&options, "chart-type", "none"); + string_map_insert (&options, "top-margin", "0"); + string_map_insert (&options, "bottom-margin", "0"); + export_output (window, &options, "ascii"); + } + else if (filter == ps_filter) + { + string_map_insert (&options, "output-type", "ps"); + export_output (window, &options, "cairo"); + } + else if (filter == csv_filter) + export_output (window, &options, "csv"); + else + g_return_if_reached (); + + free (filename); + } + + g_object_unref (G_OBJECT (pdf_filter)); + g_object_unref (G_OBJECT (html_filter)); + g_object_unref (G_OBJECT (txt_filter)); + g_object_unref (G_OBJECT (ps_filter)); + g_object_unref (G_OBJECT (csv_filter)); + + gtk_widget_destroy (dialog); +} static void psppire_output_window_init (PsppireOutputWindow *window) { - GtkBuilder *xml = builder_new ("output-viewer.ui"); + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkBuilder *xml; + + xml = builder_new ("output-viewer.ui"); 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")); + gtk_tree_view_set_model (window->overview, + GTK_TREE_MODEL (gtk_tree_store_new ( + N_COLS, + G_TYPE_STRING, /* COL_TITLE */ + G_TYPE_LONG))); /* COL_Y */ + window->last_table_num = -1; + + window->items = NULL; + window->n_items = window->allocated_items = 0; + + column = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (window->overview), column); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, "text", COL_TITLE); + + g_signal_connect (GTK_TREE_VIEW (window->overview), + "row-activated", G_CALLBACK (on_row_activate), window); + gtk_widget_modify_bg (GTK_WIDGET (window->output), GTK_STATE_NORMAL, >k_widget_get_style (GTK_WIDGET (window->output))->base[GTK_STATE_NORMAL]); @@ -284,6 +483,9 @@ psppire_output_window_init (PsppireOutputWindow *window) GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar1/windows_menuitem/windows_minimise-all")->parent); } + g_signal_connect_swapped (get_action_assert (xml, "file_export"), "activate", + G_CALLBACK (psppire_output_window_export), window); + g_object_unref (xml); g_signal_connect (window, "delete-event",