Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / ui / dialog / filedialogimpl-gtkmm.cpp
1 /** @file
2  * @brief Implementation of the file dialog interfaces defined in filedialogimpl.h
3  */
4 /* Authors:
5  *   Bob Jamison
6  *   Joel Holdsworth
7  *   Bruno Dilly
8  *   Other dudes from The Inkscape Organization
9  *   Abhishek Sharma
10  *
11  * Copyright (C) 2004-2007 Bob Jamison
12  * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
13  * Copyright (C) 2007-2008 Joel Holdsworth
14  * Copyright (C) 2004-2007 The Inkscape Organization
15  *
16  * Released under GNU GPL, read the file 'COPYING' for more information
17  */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include "filedialogimpl-gtkmm.h"
24 #include "dialogs/dialog-events.h"
25 #include "interface.h"
26 #include "io/sys.h"
27 #include "path-prefix.h"
28 #include "preferences.h"
30 #ifdef WITH_GNOME_VFS
31 # include <libgnomevfs/gnome-vfs.h>
32 #endif
34 //Routines from file.cpp
35 #undef INK_DUMP_FILENAME_CONV
37 #ifdef INK_DUMP_FILENAME_CONV
38 void dump_str( const gchar* str, const gchar* prefix );
39 void dump_ustr( const Glib::ustring& ustr );
40 #endif
44 namespace Inkscape
45 {
46 namespace UI
47 {
48 namespace Dialog
49 {
55 //########################################################################
56 //### U T I L I T Y
57 //########################################################################
59 void
60 fileDialogExtensionToPattern(Glib::ustring &pattern,
61                       Glib::ustring &extension)
62 {
63     for (unsigned int i = 0; i < extension.length(); i++ )
64         {
65         Glib::ustring::value_type ch = extension[i];
66         if ( Glib::Unicode::isalpha(ch) )
67             {
68             pattern += '[';
69             pattern += Glib::Unicode::toupper(ch);
70             pattern += Glib::Unicode::tolower(ch);
71             pattern += ']';
72             }
73         else
74             {
75             pattern += ch;
76             }
77         }
78 }
81 void
82 findEntryWidgets(Gtk::Container *parent,
83                  std::vector<Gtk::Entry *> &result)
84 {
85     if (!parent)
86         return;
87     std::vector<Gtk::Widget *> children = parent->get_children();
88     for (unsigned int i=0; i<children.size() ; i++)
89         {
90         Gtk::Widget *child = children[i];
91         GtkWidget *wid = child->gobj();
92         if (GTK_IS_ENTRY(wid))
93            result.push_back((Gtk::Entry *)child);
94         else if (GTK_IS_CONTAINER(wid))
95             findEntryWidgets((Gtk::Container *)child, result);
96         }
98 }
100 void
101 findExpanderWidgets(Gtk::Container *parent,
102                     std::vector<Gtk::Expander *> &result)
104     if (!parent)
105         return;
106     std::vector<Gtk::Widget *> children = parent->get_children();
107     for (unsigned int i=0; i<children.size() ; i++)
108         {
109         Gtk::Widget *child = children[i];
110         GtkWidget *wid = child->gobj();
111         if (GTK_IS_EXPANDER(wid))
112            result.push_back((Gtk::Expander *)child);
113         else if (GTK_IS_CONTAINER(wid))
114             findExpanderWidgets((Gtk::Container *)child, result);
115         }
120 /*#########################################################################
121 ### SVG Preview Widget
122 #########################################################################*/
124 bool SVGPreview::setDocument(SPDocument *doc)
126     if (document)
127         document->doUnref();
129     doc->doRef();
130     document = doc;
132     //This should remove it from the box, and free resources
133     if (viewerGtk)
134         gtk_widget_destroy(viewerGtk);
136     viewerGtk  = sp_svg_view_widget_new(doc);
137     GtkWidget *vbox = (GtkWidget *)gobj();
138     gtk_box_pack_start(GTK_BOX(vbox), viewerGtk, TRUE, TRUE, 0);
139     gtk_widget_show(viewerGtk);
141     return true;
145 bool SVGPreview::setFileName(Glib::ustring &theFileName)
147     Glib::ustring fileName = theFileName;
149     fileName = Glib::filename_to_utf8(fileName);
151     /**
152      * I don't know why passing false to keepalive is bad.  But it
153      * prevents the display of an svg with a non-ascii filename
154      */
155     SPDocument *doc = SPDocument::createNewDoc (fileName.c_str(), true);
156     if (!doc) {
157         g_warning("SVGView: error loading document '%s'\n", fileName.c_str());
158         return false;
159     }
161     setDocument(doc);
163     doc->doUnref();
165     return true;
170 bool SVGPreview::setFromMem(char const *xmlBuffer)
172     if (!xmlBuffer)
173         return false;
175     gint len = (gint)strlen(xmlBuffer);
176     SPDocument *doc = SPDocument::createNewDocFromMem(xmlBuffer, len, 0);
177     if (!doc) {
178         g_warning("SVGView: error loading buffer '%s'\n",xmlBuffer);
179         return false;
180     }
182     setDocument(doc);
184     doc->doUnref();
186     Inkscape::GC::request_early_collection();
188     return true;
193 void SVGPreview::showImage(Glib::ustring &theFileName)
195     Glib::ustring fileName = theFileName;
198     /*#####################################
199     # LET'S HAVE SOME FUN WITH SVG!
200     # Instead of just loading an image, why
201     # don't we make a lovely little svg and
202     # display it nicely?
203     #####################################*/
205     //Arbitrary size of svg doc -- rather 'portrait' shaped
206     gint previewWidth  = 400;
207     gint previewHeight = 600;
209     //Get some image info. Smart pointer does not need to be deleted
210     Glib::RefPtr<Gdk::Pixbuf> img(NULL);
211     try {
212         img = Gdk::Pixbuf::create_from_file(fileName);
213     }
214     catch (const Glib::FileError & e)
215     {
216         g_message("caught Glib::FileError in SVGPreview::showImage");
217         return;
218     }
219     catch (const Gdk::PixbufError & e)
220     {
221         g_message("Gdk::PixbufError in SVGPreview::showImage");
222         return;
223     }
224     catch (...)
225     {
226         g_message("Caught ... in SVGPreview::showImage");
227         return;
228     }
230     gint imgWidth  = img->get_width();
231     gint imgHeight = img->get_height();
233     //Find the minimum scale to fit the image inside the preview area
234     double scaleFactorX = (0.9 *(double)previewWidth)  / ((double)imgWidth);
235     double scaleFactorY = (0.9 *(double)previewHeight) / ((double)imgHeight);
236     double scaleFactor = scaleFactorX;
237     if (scaleFactorX > scaleFactorY)
238         scaleFactor = scaleFactorY;
240     //Now get the resized values
241     gint scaledImgWidth  = (int) (scaleFactor * (double)imgWidth);
242     gint scaledImgHeight = (int) (scaleFactor * (double)imgHeight);
244     //center the image on the area
245     gint imgX = (previewWidth  - scaledImgWidth)  / 2;
246     gint imgY = (previewHeight - scaledImgHeight) / 2;
248     //wrap a rectangle around the image
249     gint rectX      = imgX-1;
250     gint rectY      = imgY-1;
251     gint rectWidth  = scaledImgWidth +2;
252     gint rectHeight = scaledImgHeight+2;
254     //Our template.  Modify to taste
255     gchar const *xformat =
256           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
257           "<svg\n"
258           "xmlns=\"http://www.w3.org/2000/svg\"\n"
259           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
260           "width=\"%d\" height=\"%d\">\n"  //# VALUES HERE
261           "<rect\n"
262           "  style=\"fill:#eeeeee;stroke:none\"\n"
263           "  x=\"-100\" y=\"-100\" width=\"4000\" height=\"4000\"/>\n"
264           "<image x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"\n"
265           "xlink:href=\"%s\"/>\n"
266           "<rect\n"
267           "  style=\"fill:none;"
268           "    stroke:#000000;stroke-width:1.0;"
269           "    stroke-linejoin:miter;stroke-opacity:1.0000000;"
270           "    stroke-miterlimit:4.0000000;stroke-dasharray:none\"\n"
271           "  x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
272           "<text\n"
273           "  style=\"font-size:24.000000;font-style:normal;font-weight:normal;"
274           "    fill:#000000;fill-opacity:1.0000000;stroke:none;"
275           "    font-family:Sans\"\n"
276           "  x=\"10\" y=\"26\">%d x %d</text>\n" //# VALUES HERE
277           "</svg>\n\n";
279     //if (!Glib::get_charset()) //If we are not utf8
280     fileName = Glib::filename_to_utf8(fileName);
282     //Fill in the template
283     /* FIXME: Do proper XML quoting for fileName. */
284     gchar *xmlBuffer = g_strdup_printf(xformat,
285            previewWidth, previewHeight,
286            imgX, imgY, scaledImgWidth, scaledImgHeight,
287            fileName.c_str(),
288            rectX, rectY, rectWidth, rectHeight,
289            imgWidth, imgHeight);
291     //g_message("%s\n", xmlBuffer);
293     //now show it!
294     setFromMem(xmlBuffer);
295     g_free(xmlBuffer);
300 void SVGPreview::showNoPreview()
302     //Are we already showing it?
303     if (showingNoPreview)
304         return;
306     //Arbitrary size of svg doc -- rather 'portrait' shaped
307     gint previewWidth  = 300;
308     gint previewHeight = 600;
310     //Our template.  Modify to taste
311     gchar const *xformat =
312           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
313           "<svg\n"
314           "xmlns=\"http://www.w3.org/2000/svg\"\n"
315           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
316           "width=\"%d\" height=\"%d\">\n" //# VALUES HERE
317           "<g transform=\"translate(-190,24.27184)\" style=\"opacity:0.12\">\n"
318           "<path\n"
319           "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
320           "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
321           "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
322           "id=\"whiteSpace\" />\n"
323           "<path\n"
324           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
325           "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
326           "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
327           "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
328           "id=\"droplet01\" />\n"
329           "<path\n"
330           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
331           "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
332           "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
333           "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
334           "287.18046 343.1206 286.46194 340.42914 z \"\n"
335           "id=\"droplet02\" />\n"
336           "<path\n"
337           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
338           "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
339           "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
340           "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
341           "id=\"droplet03\" />\n"
342           "<path\n"
343           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
344           "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
345           "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
346           "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
347           "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
348           "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
349           "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
350           "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
351           "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
352           "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
353           "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
354           "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
355           "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
356           "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
357           "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
358           "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
359           "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
360           "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
361           "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
362           "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
363           "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
364           "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
365           "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
366           "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
367           "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
368           "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
369           "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
370           "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
371           "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
372           "id=\"mountainDroplet\" />\n"
373           "</g> <g transform=\"translate(-20,0)\">\n"
374           "<text xml:space=\"preserve\"\n"
375           "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
376           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
377           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
378           "font-family:Sans;text-anchor:middle;writing-mode:lr\"\n"
379           "x=\"190\" y=\"240\">%s</text></g>\n"  //# VALUE HERE
380           "</svg>\n\n";
382     //Fill in the template
383     gchar *xmlBuffer = g_strdup_printf(xformat,
384            previewWidth, previewHeight, _("No preview"));
386     //g_message("%s\n", xmlBuffer);
388     //now show it!
389     setFromMem(xmlBuffer);
390     g_free(xmlBuffer);
391     showingNoPreview = true;
396 /**
397  * Inform the user that the svg file is too large to be displayed.
398  * This does not check for sizes of embedded images (yet)
399  */
400 void SVGPreview::showTooLarge(long fileLength)
403     //Arbitrary size of svg doc -- rather 'portrait' shaped
404     gint previewWidth  = 300;
405     gint previewHeight = 600;
407     //Our template.  Modify to taste
408     gchar const *xformat =
409           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
410           "<svg\n"
411           "xmlns=\"http://www.w3.org/2000/svg\"\n"
412           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
413           "width=\"%d\" height=\"%d\">\n"  //# VALUES HERE
414           "<g transform=\"translate(-170,24.27184)\" style=\"opacity:0.12\">\n"
415           "<path\n"
416           "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
417           "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
418           "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
419           "id=\"whiteSpace\" />\n"
420           "<path\n"
421           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
422           "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
423           "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
424           "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
425           "id=\"droplet01\" />\n"
426           "<path\n"
427           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
428           "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
429           "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
430           "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
431           "287.18046 343.1206 286.46194 340.42914 z \"\n"
432           "id=\"droplet02\" />\n"
433           "<path\n"
434           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
435           "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
436           "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
437           "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
438           "id=\"droplet03\" />\n"
439           "<path\n"
440           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
441           "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
442           "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
443           "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
444           "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
445           "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
446           "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
447           "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
448           "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
449           "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
450           "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
451           "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
452           "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
453           "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
454           "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
455           "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
456           "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
457           "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
458           "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
459           "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
460           "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
461           "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
462           "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
463           "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
464           "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
465           "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
466           "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
467           "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
468           "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
469           "id=\"mountainDroplet\" />\n"
470           "</g>\n"
471           "<text xml:space=\"preserve\"\n"
472           "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
473           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
474           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
475           "font-family:Sans;text-anchor:middle;writing-mode:lr\"\n"
476           "x=\"170\" y=\"215\">%5.1f MB</text>\n" //# VALUE HERE
477           "<text xml:space=\"preserve\"\n"
478           "style=\"font-size:24.000000;font-style:normal;font-variant:normal;font-weight:bold;"
479           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
480           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
481           "font-family:Sans;text-anchor:middle;writing-mode:lr\"\n"
482           "x=\"180\" y=\"245\">%s</text>\n" //# VALUE HERE
483           "</svg>\n\n";
485     //Fill in the template
486     double floatFileLength = ((double)fileLength) / 1048576.0;
487     //printf("%ld %f\n", fileLength, floatFileLength);
488     gchar *xmlBuffer = g_strdup_printf(xformat,
489            previewWidth, previewHeight, floatFileLength,
490            _("too large for preview"));
492     //g_message("%s\n", xmlBuffer);
494     //now show it!
495     setFromMem(xmlBuffer);
496     g_free(xmlBuffer);
500 bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
503     if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS))
504         return false;
506     //g_message("fname:%s", fileName.c_str());
508     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
509         showNoPreview();
510         return false;
511     }
513     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR))
514         {
515         Glib::ustring fileNameUtf8 = Glib::filename_to_utf8(fileName);
516         gchar *fName = (gchar *)fileNameUtf8.c_str();
517         struct stat info;
518         if (g_stat(fName, &info))
519             {
520             g_warning("SVGPreview::set() : %s : %s",
521                            fName, strerror(errno));
522             return FALSE;
523             }
524         long fileLen = info.st_size;
525         if (fileLen > 0xA00000L)
526             {
527             showingNoPreview = false;
528             showTooLarge(fileLen);
529             return FALSE;
530             }
531         }
533     Glib::ustring svg = ".svg";
534     Glib::ustring svgz = ".svgz";
536     if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
537            (hasSuffix(fileName, svg) || hasSuffix(fileName, svgz)   )
538         ) {
539         bool retval = setFileName(fileName);
540         showingNoPreview = false;
541         return retval;
542     } else if (isValidImageFile(fileName)) {
543         showImage(fileName);
544         showingNoPreview = false;
545         return true;
546     } else {
547         showNoPreview();
548         return false;
549     }
553 SVGPreview::SVGPreview()
555     if (!INKSCAPE)
556         inkscape_application_init("",false);
557     document = NULL;
558     viewerGtk = NULL;
559     set_size_request(150,150);
560     showingNoPreview = false;
563 SVGPreview::~SVGPreview()
569 /*#########################################################################
570 ### F I L E     D I A L O G    B A S E    C L A S S
571 #########################################################################*/
573 void FileDialogBaseGtk::internalSetup()
575     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
576     bool enablePreview = prefs->getBool( preferenceBase + "/enable_preview", true);
578     previewCheckbox.set_label( Glib::ustring(_("Enable preview")) );
579     previewCheckbox.set_active( enablePreview );
581     previewCheckbox.signal_toggled().connect(
582         sigc::mem_fun(*this, &FileDialogBaseGtk::_previewEnabledCB) );
584     //Catch selection-changed events, so we can adjust the text widget
585     signal_update_preview().connect(
586          sigc::mem_fun(*this, &FileDialogBaseGtk::_updatePreviewCallback) );
588     //###### Add a preview widget
589     set_preview_widget(svgPreview);
590     set_preview_widget_active( enablePreview );
591     set_use_preview_label (false);
596 void FileDialogBaseGtk::cleanup( bool showConfirmed )
598     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
599     if ( showConfirmed )
600         prefs->setBool( preferenceBase + "/enable_preview", previewCheckbox.get_active() );
604 void FileDialogBaseGtk::_previewEnabledCB()
606     bool enabled = previewCheckbox.get_active();
607     set_preview_widget_active(enabled);
608     if ( enabled ) {
609         _updatePreviewCallback();
610     }
615 /**
616  * Callback for checking if the preview needs to be redrawn
617  */
618 void FileDialogBaseGtk::_updatePreviewCallback()
620     Glib::ustring fileName = get_preview_filename();
622 #ifdef WITH_GNOME_VFS
623     if ( fileName.empty() && gnome_vfs_initialized() ) {
624         fileName = get_preview_uri();
625     }
626 #endif
628     if (fileName.empty()) {
629         return;
630     }
632     svgPreview.set(fileName, _dialogType);
636 /*#########################################################################
637 ### F I L E    O P E N
638 #########################################################################*/
640 /**
641  * Constructor.  Not called directly.  Use the factory.
642  */
643 FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow,
644                                        const Glib::ustring &dir,
645                                        FileDialogType fileTypes,
646                                        const Glib::ustring &title) :
647     FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_OPEN, fileTypes, "/dialogs/open")
651     /* One file at a time */
652     /* And also Multiple Files */
653     set_select_multiple(true);
655 #ifdef WITH_GNOME_VFS
656     if (gnome_vfs_initialized()) {
657         set_local_only(false);
658     }
659 #endif
661     /* Initalize to Autodetect */
662     extension = NULL;
663     /* No filename to start out with */
664     myFilename = "";
666     /* Set our dialog type (open, import, etc...)*/
667     _dialogType = fileTypes;
670     /* Set the pwd and/or the filename */
671     if (dir.size() > 0)
672         {
673         Glib::ustring udir(dir);
674         Glib::ustring::size_type len = udir.length();
675         // leaving a trailing backslash on the directory name leads to the infamous
676         // double-directory bug on win32
677         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
678         set_current_folder(udir.c_str());
679         }
682     set_extra_widget( previewCheckbox );
685     //###### Add the file types menu
686     createFilterMenu();
688     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
689     set_default(*add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_OK));
691     //###### Allow easy access to our examples folder
692     if ( Inkscape::IO::file_test(INKSCAPE_EXAMPLESDIR, G_FILE_TEST_EXISTS)
693          && Inkscape::IO::file_test(INKSCAPE_EXAMPLESDIR, G_FILE_TEST_IS_DIR)
694          && g_path_is_absolute(INKSCAPE_EXAMPLESDIR)
695         )
696     {
697         add_shortcut_folder(INKSCAPE_EXAMPLESDIR);
698     }
701 /**
702  * Destructor
703  */
704 FileOpenDialogImplGtk::~FileOpenDialogImplGtk()
709 void FileOpenDialogImplGtk::createFilterMenu()
711     Gtk::FileFilter allInkscapeFilter;
712     allInkscapeFilter.set_name(_("All Inkscape Files"));
713     extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL;
714     add_filter(allInkscapeFilter);
716     Gtk::FileFilter allFilter;
717     allFilter.set_name(_("All Files"));
718     extensionMap[Glib::ustring(_("All Files"))]=NULL;
719     allFilter.add_pattern("*");
720     add_filter(allFilter);
722     Gtk::FileFilter allImageFilter;
723     allImageFilter.set_name(_("All Images"));
724     extensionMap[Glib::ustring(_("All Images"))]=NULL;
725     add_filter(allImageFilter);
727     Gtk::FileFilter allVectorFilter;
728     allVectorFilter.set_name(_("All Vectors"));
729     extensionMap[Glib::ustring(_("All Vectors"))]=NULL;
730     add_filter(allVectorFilter);
732     Gtk::FileFilter allBitmapFilter;
733     allBitmapFilter.set_name(_("All Bitmaps"));
734     extensionMap[Glib::ustring(_("All Bitmaps"))]=NULL;
735     add_filter(allBitmapFilter);
737     //patterns added dynamically below
738     Inkscape::Extension::DB::InputList extension_list;
739     Inkscape::Extension::db.get_input_list(extension_list);
741     for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
742          current_item != extension_list.end(); current_item++)
743     {
744         Inkscape::Extension::Input * imod = *current_item;
746         // FIXME: would be nice to grey them out instead of not listing them
747         if (imod->deactivated()) continue;
749         Glib::ustring upattern("*");
750         Glib::ustring extension = imod->get_extension();
751         fileDialogExtensionToPattern(upattern, extension);
753         Gtk::FileFilter filter;
754         Glib::ustring uname(_(imod->get_filetypename()));
755         filter.set_name(uname);
756         filter.add_pattern(upattern);
757         add_filter(filter);
758         extensionMap[uname] = imod;
760         //g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str());
761         allInkscapeFilter.add_pattern(upattern);
762         if ( strncmp("image", imod->get_mimetype(), 5)==0 )
763             allImageFilter.add_pattern(upattern);
765         // uncomment this to find out all mime types supported by Inkscape import/open
766         // g_print ("%s\n", imod->get_mimetype());
768         // I don't know of any other way to define "bitmap" formats other than by listing them
769         if ( 
770             strncmp("image/png", imod->get_mimetype(), 9)==0 ||
771             strncmp("image/jpeg", imod->get_mimetype(), 10)==0 ||
772             strncmp("image/gif", imod->get_mimetype(), 9)==0 ||
773             strncmp("image/x-icon", imod->get_mimetype(), 12)==0 ||
774             strncmp("image/x-navi-animation", imod->get_mimetype(), 22)==0 ||
775             strncmp("image/x-cmu-raster", imod->get_mimetype(), 18)==0 ||
776             strncmp("image/x-xpixmap", imod->get_mimetype(), 15)==0 ||
777             strncmp("image/bmp", imod->get_mimetype(), 9)==0 ||
778             strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18)==0 ||
779             strncmp("image/tiff", imod->get_mimetype(), 10)==0 ||
780             strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 ||
781             strncmp("image/x-tga", imod->get_mimetype(), 11)==0 ||
782             strncmp("image/x-pcx", imod->get_mimetype(), 11)==0 
783            )
784             allBitmapFilter.add_pattern(upattern);
785         else 
786             allVectorFilter.add_pattern(upattern);
787     }
789     return;
792 /**
793  * Show this dialog modally.  Return true if user hits [OK]
794  */
795 bool
796 FileOpenDialogImplGtk::show()
798     set_modal (TRUE);                      //Window
799     sp_transientize((GtkWidget *)gobj());  //Make transient
800     gint b = run();                        //Dialog
801     svgPreview.showNoPreview();
802     hide();
804     if (b == Gtk::RESPONSE_OK)
805         {
806         //This is a hack, to avoid the warning messages that
807         //Gtk::FileChooser::get_filter() returns
808         //should be:  Gtk::FileFilter *filter = get_filter();
809         GtkFileChooser *gtkFileChooser = Gtk::FileChooser::gobj();
810         GtkFileFilter *filter = gtk_file_chooser_get_filter(gtkFileChooser);
811         if (filter)
812             {
813             //Get which extension was chosen, if any
814             extension = extensionMap[gtk_file_filter_get_name(filter)];
815             }
816         myFilename = get_filename();
817 #ifdef WITH_GNOME_VFS
818         if (myFilename.empty() && gnome_vfs_initialized())
819             myFilename = get_uri();
820 #endif
821         cleanup( true );
822         return TRUE;
823         }
824     else
825        {
826        cleanup( false );
827        return FALSE;
828        }
834 /**
835  * Get the file extension type that was selected by the user. Valid after an [OK]
836  */
837 Inkscape::Extension::Extension *
838 FileOpenDialogImplGtk::getSelectionType()
840     return extension;
844 /**
845  * Get the file name chosen by the user.   Valid after an [OK]
846  */
847 Glib::ustring
848 FileOpenDialogImplGtk::getFilename (void)
850     return myFilename;
854 /**
855  * To Get Multiple filenames selected at-once.
856  */
857 std::vector<Glib::ustring>FileOpenDialogImplGtk::getFilenames()
859     std::vector<Glib::ustring> result = get_filenames();
860 #ifdef WITH_GNOME_VFS
861     if (result.empty() && gnome_vfs_initialized())
862         result = get_uris();
863 #endif
864     return result;
867 Glib::ustring FileOpenDialogImplGtk::getCurrentDirectory()
869     return get_current_folder();
875 //########################################################################
876 //# F I L E    S A V E
877 //########################################################################
879 /**
880  * Constructor
881  */
882 FileSaveDialogImplGtk::FileSaveDialogImplGtk( Gtk::Window &parentWindow,
883                                               const Glib::ustring &dir,
884                                               FileDialogType fileTypes,
885                                               const Glib::ustring &title,
886                                               const Glib::ustring &/*default_key*/,
887                                               const gchar* docTitle,
888                                               const Inkscape::Extension::FileSaveMethod save_method) :
889     FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_SAVE, fileTypes,
890                       (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) ? "/dialogs/save_copy" : "/dialogs/save_as"),
891     save_method(save_method)
893     FileSaveDialog::myDocTitle = docTitle;
895     /* One file at a time */
896     set_select_multiple(false);
898 #ifdef WITH_GNOME_VFS
899     if (gnome_vfs_initialized()) {
900         set_local_only(false);
901     }
902 #endif
904     /* Initalize to Autodetect */
905     extension = NULL;
906     /* No filename to start out with */
907     myFilename = "";
909     /* Set our dialog type (save, export, etc...)*/
910     _dialogType = fileTypes;
912     /* Set the pwd and/or the filename */
913     if (dir.size() > 0)
914         {
915         Glib::ustring udir(dir);
916         Glib::ustring::size_type len = udir.length();
917         // leaving a trailing backslash on the directory name leads to the infamous
918         // double-directory bug on win32
919         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
920         myFilename = udir;
921         }
923     //###### Add the file types menu
924     //createFilterMenu();
926     //###### Do we want the .xxx extension automatically added?
927     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
928     fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
929     if (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) {
930         fileTypeCheckbox.set_active(prefs->getBool("/dialogs/save_copy/append_extension", true));
931     } else {
932         fileTypeCheckbox.set_active(prefs->getBool("/dialogs/save_as/append_extension", true));
933     }
935     createFileTypeMenu();
936     fileTypeComboBox.set_size_request(200,40);
937     fileTypeComboBox.signal_changed().connect(
938          sigc::mem_fun(*this, &FileSaveDialogImplGtk::fileTypeChangedCallback) );
941     childBox.pack_start( checksBox );
942     childBox.pack_end( fileTypeComboBox );
943     checksBox.pack_start( fileTypeCheckbox );
944     checksBox.pack_start( previewCheckbox );
946     set_extra_widget( childBox );
948     //Let's do some customization
949     fileNameEntry = NULL;
950     Gtk::Container *cont = get_toplevel();
951     std::vector<Gtk::Entry *> entries;
952     findEntryWidgets(cont, entries);
953     //g_message("Found %d entry widgets\n", entries.size());
954     if (entries.size() >=1 )
955         {
956         //Catch when user hits [return] on the text field
957         fileNameEntry = entries[0];
958         fileNameEntry->signal_activate().connect(
959              sigc::mem_fun(*this, &FileSaveDialogImplGtk::fileNameEntryChangedCallback) );
960         }
962     //Let's do more customization
963     std::vector<Gtk::Expander *> expanders;
964     findExpanderWidgets(cont, expanders);
965     //g_message("Found %d expander widgets\n", expanders.size());
966     if (expanders.size() >=1 )
967         {
968         //Always show the file list
969         Gtk::Expander *expander = expanders[0];
970         expander->set_expanded(true);
971         }
973     // allow easy access to the user's own templates folder
974     gchar *templates = profile_path ("templates");
975     if ( Inkscape::IO::file_test(templates, G_FILE_TEST_EXISTS)
976          && Inkscape::IO::file_test(templates, G_FILE_TEST_IS_DIR)
977          && g_path_is_absolute(templates)
978         )
979     {
980         add_shortcut_folder(templates);
981     }
982     g_free (templates);
985     //if (extension == NULL)
986     //    checkbox.set_sensitive(FALSE);
988     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
989     set_default(*add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_OK));
991     show_all_children();
994 /**
995  * Destructor
996  */
997 FileSaveDialogImplGtk::~FileSaveDialogImplGtk()
1001 /**
1002  * Callback for fileNameEntry widget
1003  */
1004 void FileSaveDialogImplGtk::fileNameEntryChangedCallback()
1006     if (!fileNameEntry)
1007         return;
1009     Glib::ustring fileName = fileNameEntry->get_text();
1010     if (!Glib::get_charset()) //If we are not utf8
1011         fileName = Glib::filename_to_utf8(fileName);
1013     //g_message("User hit return.  Text is '%s'\n", fileName.c_str());
1015     if (!Glib::path_is_absolute(fileName)) {
1016         //try appending to the current path
1017         // not this way: fileName = get_current_folder() + "/" + fileName;
1018         std::vector<Glib::ustring> pathSegments;
1019         pathSegments.push_back( get_current_folder() );
1020         pathSegments.push_back( fileName );
1021         fileName = Glib::build_filename(pathSegments);
1022     }
1024     //g_message("path:'%s'\n", fileName.c_str());
1026     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1027         set_current_folder(fileName);
1028     } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1029         //dialog with either (1) select a regular file or (2) cd to dir
1030         //simulate an 'OK'
1031         set_filename(fileName);
1032         response(Gtk::RESPONSE_OK);
1033     }
1038 /**
1039  * Callback for fileNameEntry widget
1040  */
1041 void FileSaveDialogImplGtk::fileTypeChangedCallback()
1043     int sel = fileTypeComboBox.get_active_row_number();
1044     if (sel<0 || sel >= (int)fileTypes.size())
1045         return;
1046     FileType type = fileTypes[sel];
1047     //g_message("selected: %s\n", type.name.c_str());
1049     extension = type.extension;
1050     Gtk::FileFilter filter;
1051     filter.add_pattern(type.pattern);
1052     set_filter(filter);
1054     updateNameAndExtension();
1059 void FileSaveDialogImplGtk::createFileTypeMenu()
1061     Inkscape::Extension::DB::OutputList extension_list;
1062     Inkscape::Extension::db.get_output_list(extension_list);
1063     knownExtensions.clear();
1065     for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1066          current_item != extension_list.end(); current_item++)
1067     {
1068         Inkscape::Extension::Output * omod = *current_item;
1070         // FIXME: would be nice to grey them out instead of not listing them
1071         if (omod->deactivated()) continue;
1073         FileType type;
1074         type.name     = (_(omod->get_filetypename()));
1075         type.pattern  = "*";
1076         Glib::ustring extension = omod->get_extension();
1077         knownExtensions.insert( extension.casefold() );
1078         fileDialogExtensionToPattern (type.pattern, extension);
1079         type.extension= omod;
1080         fileTypeComboBox.append_text(type.name);
1081         fileTypes.push_back(type);
1082     }
1084     //#Let user choose
1085     FileType guessType;
1086     guessType.name = _("Guess from extension");
1087     guessType.pattern = "*";
1088     guessType.extension = NULL;
1089     fileTypeComboBox.append_text(guessType.name);
1090     fileTypes.push_back(guessType);
1093     fileTypeComboBox.set_active(0);
1094     fileTypeChangedCallback(); //call at least once to set the filter
1101 /**
1102  * Show this dialog modally.  Return true if user hits [OK]
1103  */
1104 bool
1105 FileSaveDialogImplGtk::show()
1107     change_path(myFilename);
1108     set_modal (TRUE);                      //Window
1109     sp_transientize((GtkWidget *)gobj());  //Make transient
1110     gint b = run();                        //Dialog
1111     svgPreview.showNoPreview();
1112     set_preview_widget_active(false);
1113     hide();
1115     if (b == Gtk::RESPONSE_OK) {
1116         updateNameAndExtension();
1117         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1118         
1119         // Store changes of the "Append filename automatically" checkbox back to preferences.
1120         if (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) {
1121             prefs->setBool("/dialogs/save_copy/append_extension", fileTypeCheckbox.get_active());
1122         } else {
1123             prefs->setBool("/dialogs/save_as/append_extension", fileTypeCheckbox.get_active());
1124         }
1126         Inkscape::Extension::store_file_extension_in_prefs ((extension != NULL ? extension->get_id() : "" ), save_method);
1128         cleanup( true );
1130         return TRUE;
1131     } else {
1132         cleanup( false );
1133         return FALSE;
1134     }
1138 /**
1139  * Get the file extension type that was selected by the user. Valid after an [OK]
1140  */
1141 Inkscape::Extension::Extension *
1142 FileSaveDialogImplGtk::getSelectionType()
1144     return extension;
1147 void FileSaveDialogImplGtk::setSelectionType( Inkscape::Extension::Extension * key )
1149     // If no pointer to extension is passed in, look up based on filename extension.
1150     if ( !key ) {
1151         // Not quite UTF-8 here.
1152         gchar *filenameLower = g_ascii_strdown(myFilename.c_str(), -1);
1153         for ( int i = 0; !key && (i < (int)fileTypes.size()); i++ ) {
1154             Inkscape::Extension::Output *ext = dynamic_cast<Inkscape::Extension::Output*>(fileTypes[i].extension);
1155             if ( ext && ext->get_extension() ) {
1156                 gchar *extensionLower = g_ascii_strdown( ext->get_extension(), -1 );
1157                 if ( g_str_has_suffix(filenameLower, extensionLower) ) {
1158                     key = fileTypes[i].extension;
1159                 }
1160                 g_free(extensionLower);
1161             }
1162         }
1163         g_free(filenameLower);
1164     }
1166     // Ensure the proper entry in the combo box is selected.
1167     if ( key ) {
1168         extension = key;
1169         gchar const * extensionID = extension->get_id();
1170         if ( extensionID ) {
1171             for ( int i = 0; i < (int)fileTypes.size(); i++ ) {
1172                 Inkscape::Extension::Extension *ext = fileTypes[i].extension;
1173                 if ( ext ) {
1174                     gchar const * id = ext->get_id();
1175                     if ( id && ( strcmp(extensionID, id) == 0) ) {
1176                         int oldSel = fileTypeComboBox.get_active_row_number();
1177                         if ( i != oldSel ) {
1178                             fileTypeComboBox.set_active(i);
1179                         }
1180                         break;
1181                     }
1182                 }
1183             }
1184         }
1185     }
1188 Glib::ustring FileSaveDialogImplGtk::getCurrentDirectory()
1190     return get_current_folder();
1194 /*void
1195 FileSaveDialogImplGtk::change_title(const Glib::ustring& title)
1197     set_title(title);
1198 }*/
1200 /**
1201   * Change the default save path location.
1202   */
1203 void
1204 FileSaveDialogImplGtk::change_path(const Glib::ustring& path)
1206     myFilename = path;
1208     if (Glib::file_test(myFilename, Glib::FILE_TEST_IS_DIR)) {
1209         //fprintf(stderr,"set_current_folder(%s)\n",myFilename.c_str());
1210         set_current_folder(myFilename);
1211     } else {
1212         //fprintf(stderr,"set_filename(%s)\n",myFilename.c_str());
1213         if ( Glib::file_test( myFilename, Glib::FILE_TEST_EXISTS ) ) {
1214             set_filename(myFilename);
1215         } else {
1216             std::string dirName = Glib::path_get_dirname( myFilename  );
1217             if ( dirName != get_current_folder() ) {
1218                 set_current_folder(dirName);
1219             }
1220         }
1221         Glib::ustring basename = Glib::path_get_basename(myFilename);
1222         //fprintf(stderr,"set_current_name(%s)\n",basename.c_str());
1223         try {
1224             set_current_name( Glib::filename_to_utf8(basename) );
1225         } catch ( Glib::ConvertError& e ) {
1226             g_warning( "Error converting save filename to UTF-8." );
1227             // try a fallback.
1228             set_current_name( basename );
1229         }
1230     }
1233 void FileSaveDialogImplGtk::updateNameAndExtension()
1235     // Pick up any changes the user has typed in.
1236     Glib::ustring tmp = get_filename();
1237 #ifdef WITH_GNOME_VFS
1238     if ( tmp.empty() && gnome_vfs_initialized() ) {
1239         tmp = get_uri();
1240     }
1241 #endif
1242     if ( !tmp.empty() ) {
1243         myFilename = tmp;
1244     }
1246     Inkscape::Extension::Output* newOut = extension ? dynamic_cast<Inkscape::Extension::Output*>(extension) : 0;
1247     if ( fileTypeCheckbox.get_active() && newOut ) {
1248         // Append the file extension if it's not already present and display it in the file name entry field
1249         appendExtension(myFilename, newOut);
1250         change_path(myFilename);
1251     }
1255 #ifdef NEW_EXPORT_DIALOG
1257 //########################################################################
1258 //# F I L E     E X P O R T
1259 //########################################################################
1261 /**
1262  * Callback for fileNameEntry widget
1263  */
1264 void FileExportDialogImpl::fileNameEntryChangedCallback()
1266     if (!fileNameEntry)
1267         return;
1269     Glib::ustring fileName = fileNameEntry->get_text();
1270     if (!Glib::get_charset()) //If we are not utf8
1271         fileName = Glib::filename_to_utf8(fileName);
1273     //g_message("User hit return.  Text is '%s'\n", fileName.c_str());
1275     if (!Glib::path_is_absolute(fileName)) {
1276         //try appending to the current path
1277         // not this way: fileName = get_current_folder() + "/" + fileName;
1278         std::vector<Glib::ustring> pathSegments;
1279         pathSegments.push_back( get_current_folder() );
1280         pathSegments.push_back( fileName );
1281         fileName = Glib::build_filename(pathSegments);
1282     }
1284     //g_message("path:'%s'\n", fileName.c_str());
1286     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1287         set_current_folder(fileName);
1288     } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1289         //dialog with either (1) select a regular file or (2) cd to dir
1290         //simulate an 'OK'
1291         set_filename(fileName);
1292         response(Gtk::RESPONSE_OK);
1293     }
1298 /**
1299  * Callback for fileNameEntry widget
1300  */
1301 void FileExportDialogImpl::fileTypeChangedCallback()
1303     int sel = fileTypeComboBox.get_active_row_number();
1304     if (sel<0 || sel >= (int)fileTypes.size())
1305         return;
1306     FileType type = fileTypes[sel];
1307     //g_message("selected: %s\n", type.name.c_str());
1308     Gtk::FileFilter filter;
1309     filter.add_pattern(type.pattern);
1310     set_filter(filter);
1315 void FileExportDialogImpl::createFileTypeMenu()
1317     Inkscape::Extension::DB::OutputList extension_list;
1318     Inkscape::Extension::db.get_output_list(extension_list);
1320     for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1321          current_item != extension_list.end(); current_item++)
1322     {
1323         Inkscape::Extension::Output * omod = *current_item;
1325         // FIXME: would be nice to grey them out instead of not listing them
1326         if (omod->deactivated()) continue;
1328         FileType type;
1329         type.name     = (_(omod->get_filetypename()));
1330         type.pattern  = "*";
1331         Glib::ustring extension = omod->get_extension();
1332         fileDialogExtensionToPattern (type.pattern, extension);
1333         type.extension= omod;
1334         fileTypeComboBox.append_text(type.name);
1335         fileTypes.push_back(type);
1336     }
1338     //#Let user choose
1339     FileType guessType;
1340     guessType.name = _("Guess from extension");
1341     guessType.pattern = "*";
1342     guessType.extension = NULL;
1343     fileTypeComboBox.append_text(guessType.name);
1344     fileTypes.push_back(guessType);
1347     fileTypeComboBox.set_active(0);
1348     fileTypeChangedCallback(); //call at least once to set the filter
1352 /**
1353  * Constructor
1354  */
1355 FileExportDialogImpl::FileExportDialogImpl( Gtk::Window& parentWindow,
1356                                             const Glib::ustring &dir,
1357                                             FileDialogType fileTypes,
1358                                             const Glib::ustring &title,
1359                                             const Glib::ustring &/*default_key*/ ) :
1360             FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_SAVE, fileTypes, "/dialogs/export"),
1361             sourceX0Spinner("X0",         _("Left edge of source")),
1362             sourceY0Spinner("Y0",         _("Top edge of source")),
1363             sourceX1Spinner("X1",         _("Right edge of source")),
1364             sourceY1Spinner("Y1",         _("Bottom edge of source")),
1365             sourceWidthSpinner("Width",   _("Source width")),
1366             sourceHeightSpinner("Height", _("Source height")),
1367             destWidthSpinner("Width",     _("Destination width")),
1368             destHeightSpinner("Height",   _("Destination height")),
1369             destDPISpinner("DPI",         _("Resolution (dots per inch)"))
1371     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1372     append_extension = prefs->getBool("/dialogs/save_export/append_extension", true);
1374     /* One file at a time */
1375     set_select_multiple(false);
1377 #ifdef WITH_GNOME_VFS
1378     if (gnome_vfs_initialized()) {
1379         set_local_only(false);
1380     }
1381 #endif
1383     /* Initalize to Autodetect */
1384     extension = NULL;
1385     /* No filename to start out with */
1386     myFilename = "";
1388     /* Set our dialog type (save, export, etc...)*/
1389     _dialogType = fileTypes;
1391     /* Set the pwd and/or the filename */
1392     if (dir.size()>0)
1393         {
1394         Glib::ustring udir(dir);
1395         Glib::ustring::size_type len = udir.length();
1396         // leaving a trailing backslash on the directory name leads to the infamous
1397         // double-directory bug on win32
1398         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
1399         set_current_folder(udir.c_str());
1400         }
1402     //#########################################
1403     //## EXTRA WIDGET -- SOURCE SIDE
1404     //#########################################
1406     //##### Export options buttons/spinners, etc
1407     documentButton.set_label(_("Document"));
1408     scopeBox.pack_start(documentButton);
1409     scopeGroup = documentButton.get_group();
1411     pageButton.set_label(_("Page"));
1412     pageButton.set_group(scopeGroup);
1413     scopeBox.pack_start(pageButton);
1415     selectionButton.set_label(_("Selection"));
1416     selectionButton.set_group(scopeGroup);
1417     scopeBox.pack_start(selectionButton);
1419     customButton.set_label(_("Custom"));
1420     customButton.set_group(scopeGroup);
1421     scopeBox.pack_start(customButton);
1423     sourceBox.pack_start(scopeBox);
1427     //dimension buttons
1428     sourceTable.resize(3,3);
1429     sourceTable.attach(sourceX0Spinner,     0,1,0,1);
1430     sourceTable.attach(sourceY0Spinner,     1,2,0,1);
1431     sourceUnitsSpinner.setUnitType(UNIT_TYPE_LINEAR);
1432     sourceTable.attach(sourceUnitsSpinner,  2,3,0,1);
1433     sourceTable.attach(sourceX1Spinner,     0,1,1,2);
1434     sourceTable.attach(sourceY1Spinner,     1,2,1,2);
1435     sourceTable.attach(sourceWidthSpinner,  0,1,2,3);
1436     sourceTable.attach(sourceHeightSpinner, 1,2,2,3);
1438     sourceBox.pack_start(sourceTable);
1439     sourceFrame.set_label(_("Source"));
1440     sourceFrame.add(sourceBox);
1441     exportOptionsBox.pack_start(sourceFrame);
1444     //#########################################
1445     //## EXTRA WIDGET -- SOURCE SIDE
1446     //#########################################
1449     destTable.resize(3,3);
1450     destTable.attach(destWidthSpinner,    0,1,0,1);
1451     destTable.attach(destHeightSpinner,   1,2,0,1);
1452     destUnitsSpinner.setUnitType(UNIT_TYPE_LINEAR);
1453     destTable.attach(destUnitsSpinner,    2,3,0,1);
1454     destTable.attach(destDPISpinner,      0,1,1,2);
1456     destBox.pack_start(destTable);
1459     cairoButton.set_label(_("Cairo"));
1460     otherOptionBox.pack_start(cairoButton);
1462     antiAliasButton.set_label(_("Antialias"));
1463     otherOptionBox.pack_start(antiAliasButton);
1465     backgroundButton.set_label(_("Background"));
1466     otherOptionBox.pack_start(backgroundButton);
1468     destBox.pack_start(otherOptionBox);
1474     //###### File options
1475     //###### Do we want the .xxx extension automatically added?
1476     fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
1477     fileTypeCheckbox.set_active(append_extension);
1478     destBox.pack_start(fileTypeCheckbox);
1480     //###### File type menu
1481     createFileTypeMenu();
1482     fileTypeComboBox.set_size_request(200,40);
1483     fileTypeComboBox.signal_changed().connect(
1484          sigc::mem_fun(*this, &FileExportDialogImpl::fileTypeChangedCallback) );
1486     destBox.pack_start(fileTypeComboBox);
1488     destFrame.set_label(_("Destination"));
1489     destFrame.add(destBox);
1490     exportOptionsBox.pack_start(destFrame);
1492     //##### Put the two boxes and their parent onto the dialog
1493     exportOptionsBox.pack_start(sourceFrame);
1494     exportOptionsBox.pack_start(destFrame);
1496     set_extra_widget(exportOptionsBox);
1501     //Let's do some customization
1502     fileNameEntry = NULL;
1503     Gtk::Container *cont = get_toplevel();
1504     std::vector<Gtk::Entry *> entries;
1505     findEntryWidgets(cont, entries);
1506     //g_message("Found %d entry widgets\n", entries.size());
1507     if (entries.size() >=1 )
1508         {
1509         //Catch when user hits [return] on the text field
1510         fileNameEntry = entries[0];
1511         fileNameEntry->signal_activate().connect(
1512              sigc::mem_fun(*this, &FileExportDialogImpl::fileNameEntryChangedCallback) );
1513         }
1515     //Let's do more customization
1516     std::vector<Gtk::Expander *> expanders;
1517     findExpanderWidgets(cont, expanders);
1518     //g_message("Found %d expander widgets\n", expanders.size());
1519     if (expanders.size() >=1 )
1520         {
1521         //Always show the file list
1522         Gtk::Expander *expander = expanders[0];
1523         expander->set_expanded(true);
1524         }
1527     //if (extension == NULL)
1528     //    checkbox.set_sensitive(FALSE);
1530     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1531     set_default(*add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_OK));
1533     show_all_children();
1536 /**
1537  * Destructor
1538  */
1539 FileExportDialogImpl::~FileExportDialogImpl()
1545 /**
1546  * Show this dialog modally.  Return true if user hits [OK]
1547  */
1548 bool
1549 FileExportDialogImpl::show()
1551     Glib::ustring s = Glib::filename_to_utf8 (get_current_folder());
1552     if (s.length() == 0)
1553         s = getcwd (NULL, 0);
1554     set_current_folder(Glib::filename_from_utf8(s)); //hack to force initial dir listing
1555     set_modal (TRUE);                      //Window
1556     sp_transientize((GtkWidget *)gobj());  //Make transient
1557     gint b = run();                        //Dialog
1558     svgPreview.showNoPreview();
1559     hide();
1561     if (b == Gtk::RESPONSE_OK)
1562         {
1563         int sel = fileTypeComboBox.get_active_row_number ();
1564         if (sel>=0 && sel< (int)fileTypes.size())
1565             {
1566             FileType &type = fileTypes[sel];
1567             extension = type.extension;
1568             }
1569         myFilename = get_filename();
1570 #ifdef WITH_GNOME_VFS
1571         if ( myFilename.empty() && gnome_vfs_initialized() ) {
1572             myFilename = get_uri();
1573         }
1574 #endif
1576         /*
1578         // FIXME: Why do we have more code
1580         append_extension = checkbox.get_active();
1581         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1582         prefs->setBool("/dialogs/save_export/append_extension", append_extension);
1583         prefs->setBool("/dialogs/save_export/default", ( extension != NULL ? extension->get_id() : "" ));
1584         */
1585         return TRUE;
1586         }
1587     else
1588         {
1589         return FALSE;
1590         }
1594 /**
1595  * Get the file extension type that was selected by the user. Valid after an [OK]
1596  */
1597 Inkscape::Extension::Extension *
1598 FileExportDialogImpl::getSelectionType()
1600     return extension;
1604 /**
1605  * Get the file name chosen by the user.   Valid after an [OK]
1606  */
1607 Glib::ustring
1608 FileExportDialogImpl::getFilename()
1610     return myFilename;
1613 #endif // NEW_EXPORT_DIALOG
1616 } //namespace Dialog
1617 } //namespace UI
1618 } //namespace Inkscape
1620 /*
1621   Local Variables:
1622   mode:c++
1623   c-file-style:"stroustrup"
1624   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1625   indent-tabs-mode:nil
1626   fill-column:99
1627   End:
1628 */
1629 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :