Fix enhancement bug #1337: Export IO Graphs
authorStephen Fisher <steve@stephen-fisher.com>
Fri, 22 Jun 2007 22:22:10 +0000 (22:22 -0000)
committerStephen Fisher <steve@stephen-fisher.com>
Fri, 22 Jun 2007 22:22:10 +0000 (22:22 -0000)
This new code adds a save button to the Statistics IO Graphs window and
is also reusable by any other code that uses GDK Pixmaps to draw graphs.
The Gdk-pixbuf library included in GTK is used for this save function.

svn path=/trunk/; revision=22166

docbook/wsug_graphics/ws-stats-iographs.png
docbook/wsug_src/WSUG_chapter_statistics.xml
gtk/Makefile.am
gtk/Makefile.common
gtk/io_stat.c
gtk/pixmap_save.c [new file with mode: 0644]
gtk/pixmap_save.h [new file with mode: 0644]

index bb212546634565e20854ba5335d1c8f1f2693d75..13893d442a80b97c458bd856577ccca9259ce7c8 100644 (file)
Binary files a/docbook/wsug_graphics/ws-stats-iographs.png and b/docbook/wsug_graphics/ws-stats-iographs.png differ
index 16d83c6af395aa1704bc5a6f3439078c33f2041b..39b032b58125f445edadace52651b8f3f0577fe5 100644 (file)
        </para>
        </listitem>
        
-       </itemizedlist> 
+       </itemizedlist>
+       The save button will save the currently displayed portion of
+       the graph as one of various file formats.  The save feature is
+       only available when using GTK version 2.4 or higher (the
+       latest Windows versions comply with this requirement) and
+       Wireshark version 0.99.7 or higher.
+       
        XXX - describe the Advanced feature.
        </para>
   </section>
index 1a08f805882c21bdb84f71aa39ebf56a1917280e..368059f16bf9243b5d77c134279084825af6af1f 100644 (file)
@@ -91,6 +91,7 @@ noinst_HEADERS = \
        packet_history.h        \
        packet_list.h   \
        packet_win.h    \
+       pixmap_save.h   \
        plugins_dlg.h   \
        prefs_dlg.h     \
        print_prefs.h   \
index a2d2992c61393259186bed2eab44df0aae1c4281..07473ac26b35bd09eb7d81a4e0ce19ae35c7e4ce 100644 (file)
@@ -88,6 +88,7 @@ WIRESHARK_GTK_SRC = \
        packet_history.c        \
        packet_list.c   \
        packet_win.c    \
+       pixmap_save.c   \
        plugins_dlg.c   \
        prefs_dlg.c     \
        print_dlg.c     \
index f660bb0230a8c73ddc44dc73a998f38c567597f2..7bb9f74888e4b108cb042323c5b495bf567a11c6 100644 (file)
@@ -55,6 +55,7 @@
 #include "dlg_utils.h"
 #include "filter_dlg.h"
 #include "help_dlg.h"
+#include "pixmap_save.h"
 
 void protect_thread_critical_region(void);
 void unprotect_thread_critical_region(void);
@@ -1143,6 +1144,9 @@ configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
 {
        int i;
        io_stat_t *io;
+#if GTK_CHECK_VERSION(2,4,0)
+       GtkWidget *save_bt;
+#endif
 
        io=(io_stat_t *)OBJECT_GET_DATA(widget, "io_stat_t");
        if(!io){
@@ -1161,6 +1165,12 @@ configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
        io->pixmap_width=widget->allocation.width;
        io->pixmap_height=widget->allocation.height;
 
+#if GTK_CHECK_VERSION(2,4,0)
+       save_bt = OBJECT_GET_DATA(io->window, "save_bt");
+       SIGNAL_CONNECT(save_bt, "clicked", pixmap_save_cb, io->pixmap);
+       gtk_widget_set_sensitive(save_bt, TRUE);
+#endif
+    
        gdk_draw_rectangle(io->pixmap,
                        widget->style->white_gc,
                        TRUE,
@@ -1871,7 +1881,10 @@ init_io_stat_window(io_stat_t *io)
        GtkWidget *vbox;
        GtkWidget *hbox;
        GtkWidget *bbox;
-    GtkWidget *close_bt, *help_bt;
+       GtkWidget *close_bt, *help_bt;
+#if GTK_CHECK_VERSION(2,4,0)
+       GtkWidget *save_bt;
+#endif
 
        /* create the main window */
        io->window=window_new(GTK_WINDOW_TOPLEVEL, "I/O Graphs");
@@ -1894,9 +1907,18 @@ init_io_stat_window(io_stat_t *io)
        io_stat_set_title(io);
 
     if(topic_available(HELP_STATS_IO_GRAPH_DIALOG)) {
+#if GTK_CHECK_VERSION(2,4,0)
+       bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_SAVE,
+                                 GTK_STOCK_HELP, NULL);
+#else
         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
+#endif
     } else {
+#if GTK_CHECK_VERSION(2,4,0)
+       bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_SAVE, NULL);
+#else
         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
+#endif
     }
        gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
     gtk_widget_show(bbox);
@@ -1904,6 +1926,12 @@ init_io_stat_window(io_stat_t *io)
     close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
     window_set_cancel_button(io->window, close_bt, window_cancel_button_cb);
 
+#if GTK_CHECK_VERSION(2,4,0)
+    save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
+    gtk_widget_set_sensitive(save_bt, FALSE);
+    OBJECT_SET_DATA(io->window, "save_bt", save_bt);
+#endif
+
     if(topic_available(HELP_STATS_IO_GRAPH_DIALOG)) {
         help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
         SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_STATS_IO_GRAPH_DIALOG);
diff --git a/gtk/pixmap_save.c b/gtk/pixmap_save.c
new file mode 100644 (file)
index 0000000..04518ac
--- /dev/null
@@ -0,0 +1,170 @@
+/* pixmap_save.c
+ * Routines for saving pixmaps using the Gdk-Pixmap library
+ * Copyright 2007, Stephen Fisher <stephentfisher@yahoo.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+/* This feature is not available in GTK1 and includes some functions that
+ * are only available in GTK2.4+ */
+#if GTK_CHECK_VERSION(2,4,0)
+
+#include "pixmap_save.h"
+#include "simple_dialog.h"
+#include "gui_utils.h"
+#include "file_dlg.h"
+#include "compat_macros.h"
+#include <errno.h>
+#include <epan/filesystem.h>
+
+static GtkWidget *save_as_w;
+
+static void
+pixbuf_save_destroy_cb(GtkWidget *window _U_, gpointer data _U_)
+{
+       /* We no longer have a save as dialog */
+       save_as_w = NULL;
+}
+
+static void
+pixbuf_save_button_cb(GtkWidget *save_as_w, GdkPixbuf *pixbuf)
+{
+       gchar *filename, *file_type;
+       GtkWidget *type_cm, *simple_w;
+        GError *error = NULL;
+       gboolean ret;
+
+       filename = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_as_w)));
+       type_cm = OBJECT_GET_DATA(save_as_w, "type_cm");
+       file_type = gtk_combo_box_get_active_text(GTK_COMBO_BOX(type_cm));
+       
+       /* Perhaps the user specified a directory instead of a file.
+          Check whether they did. */
+       if(test_for_directory(filename) == EISDIR) {
+               /* It's a directory - set the file selection box to display that
+                  directory, and leave the selection box displayed. */
+               set_last_open_dir(filename);
+               g_free(filename);
+               file_selection_set_current_folder(save_as_w,
+                                                 get_last_open_dir());
+               return;
+       }
+
+       ret = gdk_pixbuf_save(pixbuf, filename, file_type, &error, NULL);
+       
+       if(!ret) {
+               simple_w = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                                        "%s%s%s",
+                                        simple_dialog_primary_start(),
+                                        error->message,
+                                        simple_dialog_primary_end());
+               gtk_window_set_transient_for(GTK_WINDOW(simple_w),
+                                            GTK_WINDOW(save_as_w));
+       }
+}
+
+void
+pixmap_save_cb(GtkWidget *w, gpointer pixmap_ptr)
+{
+       GdkPixmap *pixmap = pixmap_ptr;
+       GdkPixbuf *pixbuf;
+       GdkPixbufFormat *pixbuf_format;
+       GtkWidget *main_vb, *save_as_type_hb, *type_lb, *type_cm;
+       GSList *file_formats;
+       GdkWindow *parent;
+
+       pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE(pixmap), NULL,
+                                             0, 0, 0, 0, -1, -1);
+
+       if(!pixbuf) {
+               simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                             "%sCould not get image from graph%s",
+                             simple_dialog_primary_start(),
+                             simple_dialog_primary_end());
+               return;
+       }
+
+       if(save_as_w != NULL) {
+               /* If this save as window is already open, re-open it */
+               reactivate_window(save_as_w);
+               return;
+       }
+
+       save_as_w = file_selection_new("Wireshark: Save Graph As ...",
+                                      FILE_SELECTION_SAVE);
+
+       /* Container for each row of widgets */
+       main_vb = gtk_vbox_new(FALSE, 0);
+       file_selection_set_extra_widget(save_as_w, main_vb);
+       gtk_widget_show(main_vb);
+
+       save_as_type_hb = gtk_hbox_new(FALSE, 0);
+       gtk_box_pack_start(GTK_BOX(main_vb), save_as_type_hb, FALSE, FALSE, 0);
+       gtk_widget_show(save_as_type_hb);
+
+       type_lb = gtk_label_new("File type: ");
+       gtk_box_pack_start(GTK_BOX(save_as_type_hb), type_lb, FALSE, FALSE, 0);
+       gtk_widget_show(type_lb);
+
+       type_cm = gtk_combo_box_new_text();
+       gtk_box_pack_start(GTK_BOX(save_as_type_hb), type_cm, FALSE, FALSE, 0);
+       
+       /* List all of the file formats the gdk-pixbuf library supports */
+       file_formats = gdk_pixbuf_get_formats();
+
+       while(file_formats) {
+               if (gdk_pixbuf_format_is_writable(file_formats->data)) {
+                       pixbuf_format = file_formats->data;
+                       gtk_combo_box_append_text(GTK_COMBO_BOX(type_cm),
+                                                 gdk_pixbuf_format_get_name(pixbuf_format));
+               }
+
+               file_formats = file_formats->next;
+       }
+
+       g_slist_free(file_formats);
+
+       gtk_combo_box_set_active(GTK_COMBO_BOX(type_cm), 0);
+       OBJECT_SET_DATA(save_as_w, "type_cm", type_cm);
+       gtk_widget_show(type_cm);
+
+       SIGNAL_CONNECT(save_as_w, "destroy", pixbuf_save_destroy_cb, NULL);
+
+       gtk_widget_show(save_as_w);
+       window_present(save_as_w);
+       parent = gtk_widget_get_parent_window(w);
+       gdk_window_set_transient_for(save_as_w->window, parent);
+       
+       if(gtk_dialog_run(GTK_DIALOG(save_as_w)) == GTK_RESPONSE_ACCEPT)
+               pixbuf_save_button_cb(save_as_w, pixbuf);
+
+       window_destroy(save_as_w);
+}
+
+#endif /* GTK_CHECK_VERSION(2,4,0) */
diff --git a/gtk/pixmap_save.h b/gtk/pixmap_save.h
new file mode 100644 (file)
index 0000000..4aaf1ac
--- /dev/null
@@ -0,0 +1,33 @@
+/* pixmap_save.h
+ * Routines for saving pixmaps using the Gdk-Pixmap library
+ * Copyright 2007, Stephen Fisher <stephentfisher@yahoo.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __PIXMAP_SAVE_H__
+#define __PIXMAP_SAVE_H__
+
+/* Callback to be tied to a save button.  This function will pop-up a dialog
+ * asking for options to save the graph with (such as file type). */
+void pixmap_save_cb(GtkWidget *w, gpointer pixmap_ptr);
+
+#endif /* __PIXMAP_SAVE_H__ */