Code

Implement object-snapping for clones (see bug #1511260)
[inkscape.git] / src / dialogs / export.cpp
index 3b1943c4ff23234f0a02c42227a1b667f57e8f11..da5a8c541306e6ee7eb6b770b7684d065751a9de 100644 (file)
@@ -8,8 +8,9 @@
  * Authors:
  *   Lauris Kaplinski <lauris@kaplinski.com>
  *   bulia byak <buliabyak@users.sf.net>
+ *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
  *
- * Copyright (C) 1999-2005 Authors
+ * Copyright (C) 1999-2007 Authors
  * Copyright (C) 2001-2002 Ximian, Inc.
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
@@ -43,6 +44,7 @@
 #include "file.h"
 #include "macros.h"
 #include "sp-namedview.h"
+#include "selection-chemistry.h"
 
 #include "dialog-events.h"
 #include "../prefs-utils.h"
 
 #include "io/sys.h"
 
+#include "helper/png-write.h"
+
 
 #define SP_EXPORT_MIN_SIZE 1.0
 
 #define DPI_BASE PX_PER_IN
 
-#define EXPORT_COORD_PRECISION 3
+#define EXPORT_COORD_PRECISION 3    
+
+#define MIN_ONSCREEN_DISTANCE 50
 
 static void sp_export_area_toggled   ( GtkToggleButton *tb, GtkObject *base );
 static void sp_export_export_clicked ( GtkButton *button, GtkObject *base );
@@ -334,12 +340,53 @@ sp_export_dialog_area_box (GtkWidget * dlg)
 } // end of sp_export_dialog_area_box
 
 
+gchar* create_filepath_from_id (const gchar *id, const gchar *file_entry_text) {
+
+    if (id == NULL) /* This should never happen */
+        id = "bitmap";
+
+    gchar * directory = NULL;
+
+    if (directory == NULL && file_entry_text != NULL && file_entry_text[0] != '\0') {
+        // std::cout << "Directory from dialog" << std::endl;
+        directory = g_dirname(file_entry_text);
+    }
+
+    if (directory == NULL) {
+        /* Grab document directory */
+        if (SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT)) {
+            // std::cout << "Directory from document" << std::endl;
+            directory = g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT));
+        }
+    }
+
+    if (directory == NULL) {
+        // std::cout << "Home Directory" << std::endl;
+        directory = homedir_path(NULL);
+    }
+
+    gchar * id_ext = g_strconcat(id, ".png", NULL);
+    gchar *filename = g_build_filename(directory, id_ext, NULL);
+    g_free(directory);
+    g_free(id_ext);
+    return filename;
+}
+
+static void
+batch_export_clicked (GtkWidget *widget, GtkObject *base)
+{
+    Gtk::Widget *vb_singleexport = (Gtk::Widget *)gtk_object_get_data(base, "vb_singleexport");
+    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) {
+        vb_singleexport->set_sensitive(false);
+    } else {
+        vb_singleexport->set_sensitive(true);
+    }
+}
+
 void
 sp_export_dialog (void)
 {
     if (!dlg) {
-        Gtk::VBox* vb;
-        Gtk::HBox* hb;
 
         gchar title[500];
         sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_FILE_EXPORT), title);
@@ -356,18 +403,14 @@ sp_export_dialog (void)
             h = prefs_get_int_attribute (prefs_path, "h", 0);
         }
 
-        if (x<0) x=0;
-        if (y<0) y=0;
+//        if (x<0) x=0;
+//        if (y<0) y=0;
 
-        if (x != 0 || y != 0) {
+        if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
+        if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE)))
             gtk_window_move ((GtkWindow *) dlg, x, y);
-        } else {
+        else
             gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
-        }
-
-        if (w && h)
-            gtk_window_resize ((GtkWindow *) dlg, w, h);
-
         sp_transientize (dlg);
         wd.win = dlg;
         wd.stop = 0;
@@ -395,15 +438,20 @@ sp_export_dialog (void)
 
         GtkTooltips *tt = gtk_tooltips_new();
 
-        vb = new Gtk::VBox(false, 3);
+        Gtk::VBox *vb = new Gtk::VBox(false, 3);
         vb->set_border_width(3);
         gtk_container_add (GTK_CONTAINER (dlg), GTK_WIDGET(vb->gobj()));
 
+        Gtk::VBox *vb_singleexport = new Gtk::VBox(false, 0);
+        vb_singleexport->set_border_width(0);
+        vb->pack_start(*vb_singleexport);
+        gtk_object_set_data(GTK_OBJECT(dlg), "vb_singleexport", vb_singleexport);
+
         /* Export area frame */
         {
             Gtk::VBox *area_box = sp_export_dialog_area_box(dlg);
             area_box->set_border_width(3);
-            vb->pack_start(*area_box, false, false, 0);
+            vb_singleexport->pack_start(*area_box, false, false, 0);
         }
 
         /* Bitmap size frame */
@@ -455,7 +503,7 @@ sp_export_dialog (void)
                                        0.01, 100000.0, 0.1, 1.0, NULL, GTK_WIDGET(t->gobj()), 3, 1,
                                        NULL, _("dpi"), 2, 0, NULL, dlg );
 
-            vb->pack_start(*size_box);
+            vb_singleexport->pack_start(*size_box);
         }
 
         /* File entry */
@@ -523,7 +571,7 @@ sp_export_dialog (void)
             g_signal_connect ( G_OBJECT (fe->gobj()), "changed",
                                G_CALLBACK (sp_export_filename_modified), dlg);
 
-            hb = new Gtk::HBox(FALSE, 5);
+            Gtk::HBox *hb = new Gtk::HBox(FALSE, 5);
 
             {
                 // true = has mnemonic
@@ -559,7 +607,30 @@ sp_export_dialog (void)
             // mnemonic in frame label moves focus to filename:
             flabel->set_mnemonic_widget(*fe);
 
-            vb->pack_start(*file_box);
+            vb_singleexport->pack_start(*file_box);
+        }
+
+        {
+            Gtk::HBox* batch_box = new Gtk::HBox(FALSE, 5);
+            GtkWidget *be = gtk_check_button_new_with_label(_("Batch export all selected objects"));
+            gtk_widget_set_sensitive(GTK_WIDGET(be), TRUE);
+            gtk_object_set_data(GTK_OBJECT(dlg), "batch_checkbox", be);
+            batch_box->pack_start(*Glib::wrap(be), false, false);
+            gtk_tooltips_set_tip(tt, be, _("Export each selected object into its own PNG file, using export hints if any (caution, overwrites without asking!)"), NULL);
+            batch_box->show_all();
+            g_signal_connect(G_OBJECT(be), "toggled", GTK_SIGNAL_FUNC(batch_export_clicked), dlg);
+            vb->pack_start(*batch_box);
+        }
+
+        {
+            Gtk::HBox* hide_box = new Gtk::HBox(FALSE, 5);
+            GtkWidget *he = gtk_check_button_new_with_label(_("Hide all except selected"));
+            gtk_widget_set_sensitive(GTK_WIDGET(he), TRUE);
+            gtk_object_set_data(GTK_OBJECT(dlg), "hide_checkbox", he);
+            hide_box->pack_start(*Glib::wrap(he), false, false);
+            gtk_tooltips_set_tip(tt, he, _("In the exported image, hide all objects except those that are selected"), NULL);
+            hide_box->show_all();
+            vb->pack_start(*hide_box);
         }
 
         /* Buttons */
@@ -596,6 +667,26 @@ sp_export_dialog (void)
     return;
 } // end of sp_export_dialog()
 
+static void
+sp_export_update_checkbuttons (GtkObject *base)
+{
+    gint num = g_slist_length((GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
+    GtkWidget *be = (GtkWidget *)gtk_object_get_data(base, "batch_checkbox");
+    GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox");
+    if (num >= 2) {
+        gtk_widget_set_sensitive (be, true);
+        gtk_button_set_label (GTK_BUTTON(be), g_strdup_printf (_("Batch export %d selected objects"), num));
+    } else {
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(be), FALSE);
+        gtk_widget_set_sensitive (be, FALSE);
+    }
+    if (num > 0) {
+        gtk_widget_set_sensitive (he, true);
+    } else {
+        gtk_widget_set_sensitive (he, false);
+    }
+}
+
 static inline void
 sp_export_find_default_selection(GtkWidget * dlg)
 {
@@ -631,7 +722,7 @@ sp_export_find_default_selection(GtkWidget * dlg)
                                                        selection_names[key]);
     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
 
-    return;
+    sp_export_update_checkbuttons (GTK_OBJECT(dlg));
 }
 
 
@@ -666,10 +757,10 @@ sp_export_selection_changed ( Inkscape::Application *inkscape,
         GtkToggleButton * button;
         button = (GtkToggleButton *)gtk_object_get_data(base, selection_names[current_key]);
         sp_export_area_toggled(button, base);
-    } // end of if()
+    } 
 
-    return;
-} // end of sp_export_selection_changed()
+    sp_export_update_checkbuttons (base);
+} 
 
 static void
 sp_export_selection_modified ( Inkscape::Application *inkscape, 
@@ -685,14 +776,12 @@ sp_export_selection_modified ( Inkscape::Application *inkscape,
             if ( SP_ACTIVE_DESKTOP ) {
                 SPDocument *doc;
                 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
-                NR::Rect bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
-
-                if (!(bbox.min()[NR::X] > bbox.max()[NR::X] &&
-                      bbox.min()[NR::Y] > bbox.max()[NR::Y])) {
-                    sp_export_set_area (base, bbox.min()[NR::X],
-                                              bbox.min()[NR::Y],
-                                              bbox.max()[NR::X],
-                                              bbox.max()[NR::Y]);
+                NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
+                if (bbox) {
+                    sp_export_set_area (base, bbox->min()[NR::X],
+                                              bbox->min()[NR::Y],
+                                              bbox->max()[NR::X],
+                                              bbox->max()[NR::Y]);
                 }
             }
             break;
@@ -746,7 +835,7 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
     if ( SP_ACTIVE_DESKTOP )
     {
         SPDocument *doc;
-        NR::Rect bbox;
+        NR::Maybe<NR::Rect> bbox;
         doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
 
         /* Notice how the switch is used to 'fall through' here to get
@@ -769,11 +858,9 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
                  * This returns wrong values if the document has a viewBox.
                  */
                 bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
-                
                 /* If the drawing is valid, then we'll use it and break
                    otherwise we drop through to the page settings */
-                if (!(bbox.min()[NR::X] > bbox.max()[NR::X] &&
-                      bbox.min()[NR::Y] > bbox.max()[NR::Y])) { 
+                if (bbox) {
                     // std::cout << "Using selection: DRAWING" << std::endl;
                     key = SELECTION_DRAWING;
                     break;
@@ -795,11 +882,11 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
         prefs_set_string_attribute ( "dialogs.export.exportarea", 
                                      "value", selection_names[key]);
 
-        if (key != SELECTION_CUSTOM) {
-            sp_export_set_area (base, bbox.min()[NR::X],
-                                      bbox.min()[NR::Y],
-                                      bbox.max()[NR::X],
-                                      bbox.max()[NR::Y]);
+        if ( key != SELECTION_CUSTOM && bbox ) {
+            sp_export_set_area (base, bbox->min()[NR::X],
+                                      bbox->min()[NR::Y],
+                                      bbox->max()[NR::X],
+                                      bbox->max()[NR::Y]);
         }
     
     } // end of if ( SP_ACTIVE_DESKTOP )
@@ -816,22 +903,7 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
             case SELECTION_PAGE:
             case SELECTION_DRAWING: {
                 SPDocument * doc = SP_ACTIVE_DOCUMENT;
-                Inkscape::XML::Node * repr = sp_document_repr_root(doc);
-                const gchar * dpi_string;
-
-                filename = repr->attribute("inkscape:export-filename");
-
-                dpi_string = NULL;
-                dpi_string = repr->attribute("inkscape:export-xdpi");
-                if (dpi_string != NULL) {
-                    xdpi = atof(dpi_string);
-                }
-
-                dpi_string = NULL;
-                dpi_string = repr->attribute("inkscape:export-ydpi");
-                if (dpi_string != NULL) {
-                    ydpi = atof(dpi_string);
-                }
+                sp_document_get_export_hints (doc, &filename, &xdpi, &ydpi);
 
                 if (filename == NULL) {
                     if (doc_export_name != NULL) {
@@ -844,50 +916,14 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
             }
             case SELECTION_SELECTION:
                 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
-                    const GSList * reprlst;
-                    bool filename_search = TRUE;
-                    bool xdpi_search = TRUE;
-                    bool ydpi_search = TRUE;
-
-                    reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
-                    for(; reprlst != NULL &&
-                            filename_search &&
-                            xdpi_search &&
-                            ydpi_search;
-                            reprlst = reprlst->next) {
-                        const gchar * dpi_string;
-                        Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data;
-
-                        if (filename_search) {
-                            filename = repr->attribute("inkscape:export-filename");
-                            if (filename != NULL)
-                                filename_search = FALSE;
-                        }
 
-                        if (xdpi_search) {
-                            dpi_string = NULL;
-                            dpi_string = repr->attribute("inkscape:export-xdpi");
-                            if (dpi_string != NULL) {
-                                xdpi = atof(dpi_string);
-                                xdpi_search = FALSE;
-                            }
-                        }
-
-                        if (ydpi_search) {
-                            dpi_string = NULL;
-                            dpi_string = repr->attribute("inkscape:export-ydpi");
-                            if (dpi_string != NULL) {
-                                ydpi = atof(dpi_string);
-                                ydpi_search = FALSE;
-                            }
-                        }
-                    }
+                    sp_selection_get_export_hints (sp_desktop_selection(SP_ACTIVE_DESKTOP), &filename, &xdpi, &ydpi);
 
                     /* If we still don't have a filename -- let's build
                        one that's nice */
                     if (filename == NULL) {
                         const gchar * id = NULL;
-                        reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
+                        const GSList * reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
                         for(; reprlst != NULL; reprlst = reprlst->next) {
                             Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data;
                             if (repr->attribute("id")) {
@@ -895,35 +931,8 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
                                 break;
                             }
                         }
-                        if (id == NULL) /* This should never happen */
-                            id = "bitmap";
-
-                        gchar * directory = NULL;
-                        const gchar * file_entry_text;
-
-                        file_entry_text = gtk_entry_get_text(GTK_ENTRY(file_entry));
-                        if (directory == NULL && file_entry_text != NULL && file_entry_text[0] != '\0') {
-                            // std::cout << "Directory from dialog" << std::endl;
-                            directory = g_dirname(file_entry_text);
-                        }
-
-                        if (directory == NULL) {
-                            /* Grab document directory */
-                            if (SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT)) {
-                                // std::cout << "Directory from document" << std::endl;
-                                directory = g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT));
-                            }
-                        }
-
-                        if (directory == NULL) {
-                            // std::cout << "Home Directory" << std::endl;
-                            directory = homedir_path(NULL);
-                        }
 
-                        gchar * id_ext = g_strconcat(id, ".png", NULL);
-                        filename = g_build_filename(directory, id_ext, NULL);
-                        g_free(directory);
-                        g_free(id_ext);
+                        filename = create_filepath_from_id (id, gtk_entry_get_text(GTK_ENTRY(file_entry)));
                     }
                 }
                 break;
@@ -942,7 +951,7 @@ sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
             sp_export_value_set(base, "xdpi", xdpi);
         }
 
-        /* These can't be seperate, and setting x sets y, so for
+        /* These can't be separate, and setting x sets y, so for
            now setting this is disabled.  Hopefully it won't be in
            the future */
         if (FALSE && ydpi != 0.0) {
@@ -993,12 +1002,136 @@ sp_export_progress_callback (float value, void *data)
 
 } // end of sp_export_progress_callback()
 
+GtkWidget *
+create_progress_dialog (GtkObject *base, gchar *progress_text) {
+    GtkWidget *dlg, *prg, *btn; /* progressbar-stuff */
+    
+    dlg = gtk_dialog_new ();
+    gtk_window_set_title (GTK_WINDOW (dlg), _("Export in progress"));
+    prg = gtk_progress_bar_new ();
+    sp_transientize (dlg);
+    gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
+    g_object_set_data ((GObject *) base, "progress", prg);
+
+    gtk_progress_bar_set_text ((GtkProgressBar *) prg, progress_text);
+
+    gtk_progress_bar_set_orientation ( (GtkProgressBar *) prg, 
+                                       GTK_PROGRESS_LEFT_TO_RIGHT);
+    gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dlg)->vbox, 
+                        prg, FALSE, FALSE, 4 );
+    btn = gtk_dialog_add_button ( GTK_DIALOG (dlg), 
+                                  GTK_STOCK_CANCEL, 
+                                  GTK_RESPONSE_CANCEL );
+                                  
+    g_signal_connect ( (GObject *) dlg, "delete_event", 
+                       (GCallback) sp_export_progress_delete, base);
+    g_signal_connect ( (GObject *) btn, "clicked", 
+                       (GCallback) sp_export_progress_cancel, base);
+    gtk_window_set_modal ((GtkWindow *) dlg, TRUE);
+    gtk_widget_show_all (dlg);
+
+    return dlg;
+}
+
+// FIXME: Some lib function should be available to do this ...
+static gchar *
+filename_add_extension (const gchar *filename, const gchar *extension)
+{
+  gchar *dot;
+
+  dot = strrchr (filename, '.');
+  if ( !dot )
+    return g_strconcat (filename, ".", extension, NULL);
+  {
+    if (dot[1] == '\0')
+      return g_strconcat (filename, extension, NULL);
+    else
+    {
+      if (g_strcasecmp (dot + 1, extension) == 0)
+        return g_strdup (filename);
+      else
+      {
+        return g_strconcat (filename, ".", extension, NULL);
+      }
+    }
+  }
+}
+
 /// Called when export button is clicked
 static void
 sp_export_export_clicked (GtkButton *button, GtkObject *base)
 {
     if (!SP_ACTIVE_DESKTOP) return;
 
+    SPNamedView *nv = sp_desktop_namedview(SP_ACTIVE_DESKTOP);
+
+    GtkWidget *be = (GtkWidget *)gtk_object_get_data(base, "batch_checkbox");
+    GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox");
+    bool hide = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (he));
+    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (be))) {
+        // Batch export of selected objects
+
+        gint num = g_slist_length((GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
+        gint n = 0;
+
+        if (num < 1) 
+            return;
+
+        gchar *progress_text = g_strdup_printf (_("Exporting %d files"), num);
+        GtkWidget *prog_dlg = create_progress_dialog (base, progress_text);
+        g_free (progress_text);
+
+        for (GSList *i = (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList();
+             i != NULL;
+             i = i->next) {
+            SPItem *item = (SPItem *) i->data;
+            // retrieve export filename hint
+            const gchar *fn = SP_OBJECT_REPR(item)->attribute("inkscape:export-filename");
+            if (!fn) {
+                fn = create_filepath_from_id (SP_OBJECT_ID(item), NULL);
+            }
+
+            // retrieve export dpi hints
+            const gchar *dpi_hint = SP_OBJECT_REPR(item)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
+            gdouble dpi = 0.0;
+            if (dpi_hint) {
+                dpi = atof(dpi_hint);
+            }
+            if (dpi == 0.0) {
+                dpi = DPI_BASE;
+            }
+
+            NRRect area;
+            sp_item_invoke_bbox(item, &area, sp_item_i2r_affine((SPItem *) item), TRUE);
+
+            gint width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
+            gint height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
+
+            if (width > 1 && height > 1) {
+                /* Do export */
+                if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), fn, 
+                                         area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi, 
+                                         nv->pagecolor, 
+                                         NULL, NULL, TRUE,  // overwrite without asking 
+                                         hide ? (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList() : NULL
+                        )) {
+                    gchar * error;
+                    gchar * safeFile = Inkscape::IO::sanitizeString(fn);
+                    error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
+                    sp_ui_error_dialog(error);
+                    g_free(safeFile);
+                    g_free(error);
+                }
+            }
+            n++;
+            sp_export_progress_callback((float)n/num, base);
+        }
+
+        gtk_widget_destroy (prog_dlg);
+        g_object_set_data (G_OBJECT (base), "cancel", (gpointer) 0);
+
+    } else {
+
     GtkWidget *fe = (GtkWidget *)gtk_object_get_data(base, "filename");
     gchar const *filename = gtk_entry_get_text(GTK_ENTRY(fe));
 
@@ -1021,7 +1154,7 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
         return;
     }
 
-    gchar *dirname = g_dirname(filename);
+    gchar *dirname = g_path_get_dirname(filename);
     if ( dirname == NULL
          || !Inkscape::IO::file_test(dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) )
     {
@@ -1036,43 +1169,24 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
     }
     g_free(dirname);
 
-    SPNamedView *nv = sp_desktop_namedview(SP_ACTIVE_DESKTOP);
-    GtkWidget *dlg, *prg, *btn; /* progressbar-stuff */
-    char *fn;
-    gchar *text;
+    // make sure that .png is the extension of the file:
+    gchar * filename_ext = filename_add_extension(filename, "png");
+    gtk_entry_set_text(GTK_ENTRY(fe), filename_ext);
 
-    dlg = gtk_dialog_new ();
-    gtk_window_set_title (GTK_WINDOW (dlg), _("Export in progress"));
-    prg = gtk_progress_bar_new ();
-    sp_transientize (dlg);
-    gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
-    g_object_set_data ((GObject *) base, "progress", prg);
-    fn = g_path_get_basename (filename);
-    text = g_strdup_printf ( _("Exporting %s (%d x %d)"), 
-                             fn, width, height);
+    gchar *fn = g_path_get_basename (filename_ext);
+
+    gchar *progress_text = g_strdup_printf (_("Exporting %s (%d x %d)"), fn, width, height);
     g_free (fn);
-    gtk_progress_bar_set_text ((GtkProgressBar *) prg, text);
-    g_free (text);
-    gtk_progress_bar_set_orientation ( (GtkProgressBar *) prg, 
-                                       GTK_PROGRESS_LEFT_TO_RIGHT);
-    gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dlg)->vbox, 
-                        prg, FALSE, FALSE, 4 );
-    btn = gtk_dialog_add_button ( GTK_DIALOG (dlg), 
-                                  GTK_STOCK_CANCEL, 
-                                  GTK_RESPONSE_CANCEL );
-                                  
-    g_signal_connect ( (GObject *) dlg, "delete_event", 
-                       (GCallback) sp_export_progress_delete, base);
-    g_signal_connect ( (GObject *) btn, "clicked", 
-                       (GCallback) sp_export_progress_cancel, base);
-    gtk_window_set_modal ((GtkWindow *) dlg, TRUE);
-    gtk_widget_show_all (dlg);
+    GtkWidget *prog_dlg = create_progress_dialog (base, progress_text);
+    g_free (progress_text);
     
     /* Do export */
-    if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), filename, 
-                             x0, y0, x1, y1, width, height, 
+    if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), filename_ext
+                             x0, y0, x1, y1, width, height, xdpi, ydpi, 
                              nv->pagecolor, 
-                             sp_export_progress_callback, base)) {
+                             sp_export_progress_callback, base, FALSE,
+                             hide ? (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList() : NULL
+            )) {
         gchar * error;
         gchar * safeFile = Inkscape::IO::sanitizeString(filename);
         error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
@@ -1084,10 +1198,10 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
     /* Reset the filename so that it can be changed again by changing
        selections and all that */
     g_free(original_name);
-    original_name = g_strdup(filename);
+    original_name = g_strdup(filename_ext);
     gtk_object_set_data (GTK_OBJECT (base), "filename-modified", (gpointer)FALSE);
 
-    gtk_widget_destroy (dlg);
+    gtk_widget_destroy (prog_dlg);
     g_object_set_data (G_OBJECT (base), "cancel", (gpointer) 0);
 
     /* Setup the values in the document */
@@ -1096,26 +1210,26 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
         case SELECTION_DRAWING: {
             SPDocument * doc = SP_ACTIVE_DOCUMENT;
             Inkscape::XML::Node * repr = sp_document_repr_root(doc);
-            bool modified = FALSE;
+            bool modified = false;
             const gchar * temp_string;
 
             bool saved = sp_document_get_undo_sensitive(doc);
-            sp_document_set_undo_sensitive(doc, FALSE);
+            sp_document_set_undo_sensitive(doc, false);
 
             temp_string = repr->attribute("inkscape:export-filename");
-            if (temp_string == NULL || strcmp(temp_string, filename)) {
-                repr->setAttribute("inkscape:export-filename", filename);
-                modified = TRUE;
+            if (temp_string == NULL || strcmp(temp_string, filename_ext)) {
+                repr->setAttribute("inkscape:export-filename", filename_ext);
+                modified = true;
             }
             temp_string = repr->attribute("inkscape:export-xdpi");
             if (temp_string == NULL || xdpi != atof(temp_string)) {
                 sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi);
-                modified = TRUE;
+                modified = true;
             }
             temp_string = repr->attribute("inkscape:export-ydpi");
             if (temp_string == NULL || xdpi != atof(temp_string)) {
                 sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi);
-                modified = TRUE;
+                modified = true;
             }
 
             if (modified)
@@ -1126,10 +1240,10 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
         case SELECTION_SELECTION: {
             const GSList * reprlst;
             SPDocument * doc = SP_ACTIVE_DOCUMENT;
-            bool modified = FALSE;
+            bool modified = false;
 
             bool saved = sp_document_get_undo_sensitive(doc);
-            sp_document_set_undo_sensitive(doc, FALSE);
+            sp_document_set_undo_sensitive(doc, false);
             reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
 
             for(; reprlst != NULL; reprlst = reprlst->next) {
@@ -1137,24 +1251,24 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
                 const gchar * temp_string;
 
                 if (repr->attribute("id") == NULL ||
-                        !(g_strrstr(filename, repr->attribute("id")) != NULL &&
+                        !(g_strrstr(filename_ext, repr->attribute("id")) != NULL &&
                           (!SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT) ||
                             strcmp(g_dirname(filename), g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT))) == 0))) {
                     temp_string = repr->attribute("inkscape:export-filename");
-                    if (temp_string == NULL || strcmp(temp_string, filename)) {
-                        repr->setAttribute("inkscape:export-filename", filename);
-                        modified = TRUE;
+                    if (temp_string == NULL || strcmp(temp_string, filename_ext)) {
+                        repr->setAttribute("inkscape:export-filename", filename_ext);
+                        modified = true;
                     }
                 }
                 temp_string = repr->attribute("inkscape:export-xdpi");
                 if (temp_string == NULL || xdpi != atof(temp_string)) {
                     sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi);
-                    modified = TRUE;
+                    modified = true;
                 }
                 temp_string = repr->attribute("inkscape:export-ydpi");
                 if (temp_string == NULL || xdpi != atof(temp_string)) {
                     sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi);
-                    modified = TRUE;
+                    modified = true;
                 }
             }
 
@@ -1170,8 +1284,10 @@ sp_export_export_clicked (GtkButton *button, GtkObject *base)
             break;
     }
 
+    g_free (filename_ext);
+
+    }
 
-    return;
 } // end of sp_export_export_clicked()
 
 /// Called when Browse button is clicked
@@ -1188,6 +1304,10 @@ sp_export_browse_clicked (GtkButton *button, gpointer userdata)
                                       GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
                                       NULL );
 
+#ifdef WITH_GNOME_VFS
+    gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER (fs), false);
+#endif
+
     fe = (GtkWidget *)g_object_get_data (G_OBJECT (dlg), "filename");
 
     sp_transientize (fs);
@@ -1207,11 +1327,13 @@ sp_export_browse_clicked (GtkButton *button, gpointer userdata)
         gchar *file;
 
         file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fs));
+
         gchar * utf8file = g_filename_to_utf8( file, -1, NULL, NULL, NULL );
         gtk_entry_set_text (GTK_ENTRY (fe), utf8file);
-        g_free(utf8file);
 
         g_object_set_data (G_OBJECT (dlg), "filename", fe);
+
+        g_free(utf8file);
         g_free(file);
     }
 
@@ -1283,10 +1405,10 @@ sp_export_detect_size(GtkObject * base) {
         switch (this_test[i]) {
             case SELECTION_SELECTION:
                 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
-                    NR::Rect bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds();
+                    NR::Maybe<NR::Rect> bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds();
 
                     //std::cout << "Selection " << bbox;
-                    if (sp_export_bbox_equal(bbox,current_bbox)) {
+                    if ( bbox && sp_export_bbox_equal(*bbox,current_bbox)) {
                         key = SELECTION_SELECTION;
                     }
                 }
@@ -1294,10 +1416,10 @@ sp_export_detect_size(GtkObject * base) {
             case SELECTION_DRAWING: {
                 SPDocument *doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
 
-                NR::Rect bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
+                NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
 
                 // std::cout << "Drawing " << bbox2;
-                if (sp_export_bbox_equal(bbox,current_bbox)) {
+                if ( bbox && sp_export_bbox_equal(*bbox,current_bbox) ) {
                     key = SELECTION_DRAWING;
                 }
                 break;