Code

warning cleanup
[inkscape.git] / src / ui / dialog / filedialogimpl-gtkmm.cpp
1 /**
2  * 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  *
10  * Copyright (C) 2004-2007 Bob Jamison
11  * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
12  * Copyright (C) 2004-2007 The Inkscape Organization
13  * Copyright (C) 2007 Joel Holdsworth
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #include "filedialogimpl-gtkmm.h"
23 #include "dialogs/dialog-events.h"
24 #include "interface.h"
25 #include "io/sys.h"
26 #include "path-prefix.h"
28 #ifdef WITH_GNOME_VFS
29 # include <libgnomevfs/gnome-vfs.h>
30 #endif
32 //Routines from file.cpp
33 #undef INK_DUMP_FILENAME_CONV
35 #ifdef INK_DUMP_FILENAME_CONV
36 void dump_str( const gchar* str, const gchar* prefix );
37 void dump_ustr( const Glib::ustring& ustr );
38 #endif
42 namespace Inkscape
43 {
44 namespace UI
45 {
46 namespace Dialog
47 {
53 //########################################################################
54 //### U T I L I T Y
55 //########################################################################
57 void
58 fileDialogExtensionToPattern(Glib::ustring &pattern,
59                       Glib::ustring &extension)
60 {
61     for (unsigned int i = 0; i < extension.length(); i++ )
62         {
63         Glib::ustring::value_type ch = extension[i];
64         if ( Glib::Unicode::isalpha(ch) )
65             {
66             pattern += '[';
67             pattern += Glib::Unicode::toupper(ch);
68             pattern += Glib::Unicode::tolower(ch);
69             pattern += ']';
70             }
71         else
72             {
73             pattern += ch;
74             }
75         }
76 }
79 void
80 findEntryWidgets(Gtk::Container *parent,
81                  std::vector<Gtk::Entry *> &result)
82 {
83     if (!parent)
84         return;
85     std::vector<Gtk::Widget *> children = parent->get_children();
86     for (unsigned int i=0; i<children.size() ; i++)
87         {
88         Gtk::Widget *child = children[i];
89         GtkWidget *wid = child->gobj();
90         if (GTK_IS_ENTRY(wid))
91            result.push_back((Gtk::Entry *)child);
92         else if (GTK_IS_CONTAINER(wid))
93             findEntryWidgets((Gtk::Container *)child, result);
94         }
96 }
98 void
99 findExpanderWidgets(Gtk::Container *parent,
100                     std::vector<Gtk::Expander *> &result)
102     if (!parent)
103         return;
104     std::vector<Gtk::Widget *> children = parent->get_children();
105     for (unsigned int i=0; i<children.size() ; i++)
106         {
107         Gtk::Widget *child = children[i];
108         GtkWidget *wid = child->gobj();
109         if (GTK_IS_EXPANDER(wid))
110            result.push_back((Gtk::Expander *)child);
111         else if (GTK_IS_CONTAINER(wid))
112             findExpanderWidgets((Gtk::Container *)child, result);
113         }
118 /*#########################################################################
119 ### SVG Preview Widget
120 #########################################################################*/
122 bool SVGPreview::setDocument(SPDocument *doc)
124     if (document)
125         sp_document_unref(document);
127     sp_document_ref(doc);
128     document = doc;
130     //This should remove it from the box, and free resources
131     if (viewerGtk)
132         gtk_widget_destroy(viewerGtk);
134     viewerGtk  = sp_svg_view_widget_new(doc);
135     GtkWidget *vbox = (GtkWidget *)gobj();
136     gtk_box_pack_start(GTK_BOX(vbox), viewerGtk, TRUE, TRUE, 0);
137     gtk_widget_show(viewerGtk);
139     return true;
143 bool SVGPreview::setFileName(Glib::ustring &theFileName)
145     Glib::ustring fileName = theFileName;
147     fileName = Glib::filename_to_utf8(fileName);
149     /**
150      * I don't know why passing false to keepalive is bad.  But it
151      * prevents the display of an svg with a non-ascii filename
152      */
153     SPDocument *doc = sp_document_new (fileName.c_str(), true);
154     if (!doc) {
155         g_warning("SVGView: error loading document '%s'\n", fileName.c_str());
156         return false;
157     }
159     setDocument(doc);
161     sp_document_unref(doc);
163     return true;
168 bool SVGPreview::setFromMem(char const *xmlBuffer)
170     if (!xmlBuffer)
171         return false;
173     gint len = (gint)strlen(xmlBuffer);
174     SPDocument *doc = sp_document_new_from_mem(xmlBuffer, len, 0);
175     if (!doc) {
176         g_warning("SVGView: error loading buffer '%s'\n",xmlBuffer);
177         return false;
178     }
180     setDocument(doc);
182     sp_document_unref(doc);
184     Inkscape::GC::request_early_collection();
186     return true;
191 void SVGPreview::showImage(Glib::ustring &theFileName)
193     Glib::ustring fileName = theFileName;
196     /*#####################################
197     # LET'S HAVE SOME FUN WITH SVG!
198     # Instead of just loading an image, why
199     # don't we make a lovely little svg and
200     # display it nicely?
201     #####################################*/
203     //Arbitrary size of svg doc -- rather 'portrait' shaped
204     gint previewWidth  = 400;
205     gint previewHeight = 600;
207     //Get some image info. Smart pointer does not need to be deleted
208     Glib::RefPtr<Gdk::Pixbuf> img(NULL);
209     try {
210         img = Gdk::Pixbuf::create_from_file(fileName);
211     }
212     catch (Glib::FileError e)
213     {
214         g_message("caught Glib::FileError in SVGPreview::showImage");
215         return;
216     }
217     catch (Gdk::PixbufError e)
218     {
219         g_message("Gdk::PixbufError in SVGPreview::showImage");
220         return;
221     }
223     gint imgWidth  = img->get_width();
224     gint imgHeight = img->get_height();
226     //Find the minimum scale to fit the image inside the preview area
227     double scaleFactorX = (0.9 *(double)previewWidth)  / ((double)imgWidth);
228     double scaleFactorY = (0.9 *(double)previewHeight) / ((double)imgHeight);
229     double scaleFactor = scaleFactorX;
230     if (scaleFactorX > scaleFactorY)
231         scaleFactor = scaleFactorY;
233     //Now get the resized values
234     gint scaledImgWidth  = (int) (scaleFactor * (double)imgWidth);
235     gint scaledImgHeight = (int) (scaleFactor * (double)imgHeight);
237     //center the image on the area
238     gint imgX = (previewWidth  - scaledImgWidth)  / 2;
239     gint imgY = (previewHeight - scaledImgHeight) / 2;
241     //wrap a rectangle around the image
242     gint rectX      = imgX-1;
243     gint rectY      = imgY-1;
244     gint rectWidth  = scaledImgWidth +2;
245     gint rectHeight = scaledImgHeight+2;
247     //Our template.  Modify to taste
248     gchar const *xformat =
249           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
250           "<svg\n"
251           "xmlns=\"http://www.w3.org/2000/svg\"\n"
252           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
253           "width=\"%d\" height=\"%d\">\n"  //# VALUES HERE
254           "<rect\n"
255           "  style=\"fill:#eeeeee;stroke:none\"\n"
256           "  x=\"-100\" y=\"-100\" width=\"4000\" height=\"4000\"/>\n"
257           "<image x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"\n"
258           "xlink:href=\"%s\"/>\n"
259           "<rect\n"
260           "  style=\"fill:none;"
261           "    stroke:#000000;stroke-width:1.0;"
262           "    stroke-linejoin:miter;stroke-opacity:1.0000000;"
263           "    stroke-miterlimit:4.0000000;stroke-dasharray:none\"\n"
264           "  x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
265           "<text\n"
266           "  style=\"font-size:24.000000;font-style:normal;font-weight:normal;"
267           "    fill:#000000;fill-opacity:1.0000000;stroke:none;"
268           "    font-family:Bitstream Vera Sans\"\n"
269           "  x=\"10\" y=\"26\">%d x %d</text>\n" //# VALUES HERE
270           "</svg>\n\n";
272     //if (!Glib::get_charset()) //If we are not utf8
273     fileName = Glib::filename_to_utf8(fileName);
275     //Fill in the template
276     /* FIXME: Do proper XML quoting for fileName. */
277     gchar *xmlBuffer = g_strdup_printf(xformat,
278            previewWidth, previewHeight,
279            imgX, imgY, scaledImgWidth, scaledImgHeight,
280            fileName.c_str(),
281            rectX, rectY, rectWidth, rectHeight,
282            imgWidth, imgHeight);
284     //g_message("%s\n", xmlBuffer);
286     //now show it!
287     setFromMem(xmlBuffer);
288     g_free(xmlBuffer);
293 void SVGPreview::showNoPreview()
295     //Are we already showing it?
296     if (showingNoPreview)
297         return;
299     //Arbitrary size of svg doc -- rather 'portrait' shaped
300     gint previewWidth  = 300;
301     gint previewHeight = 600;
303     //Our template.  Modify to taste
304     gchar const *xformat =
305           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
306           "<svg\n"
307           "xmlns=\"http://www.w3.org/2000/svg\"\n"
308           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
309           "width=\"%d\" height=\"%d\">\n" //# VALUES HERE
310           "<g transform=\"translate(-190,24.27184)\" style=\"opacity:0.12\">\n"
311           "<path\n"
312           "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
313           "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
314           "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
315           "id=\"whiteSpace\" />\n"
316           "<path\n"
317           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
318           "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
319           "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
320           "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
321           "id=\"droplet01\" />\n"
322           "<path\n"
323           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
324           "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
325           "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
326           "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
327           "287.18046 343.1206 286.46194 340.42914 z \"\n"
328           "id=\"droplet02\" />\n"
329           "<path\n"
330           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
331           "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
332           "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
333           "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
334           "id=\"droplet03\" />\n"
335           "<path\n"
336           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
337           "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
338           "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
339           "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
340           "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
341           "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
342           "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
343           "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
344           "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
345           "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
346           "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
347           "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
348           "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
349           "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
350           "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
351           "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
352           "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
353           "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
354           "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
355           "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
356           "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
357           "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
358           "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
359           "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
360           "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
361           "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
362           "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
363           "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
364           "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
365           "id=\"mountainDroplet\" />\n"
366           "</g> <g transform=\"translate(-20,0)\">\n"
367           "<text xml:space=\"preserve\"\n"
368           "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
369           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
370           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
371           "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
372           "x=\"190\" y=\"240\">%s</text></g>\n"  //# VALUE HERE
373           "</svg>\n\n";
375     //Fill in the template
376     gchar *xmlBuffer = g_strdup_printf(xformat,
377            previewWidth, previewHeight, _("No preview"));
379     //g_message("%s\n", xmlBuffer);
381     //now show it!
382     setFromMem(xmlBuffer);
383     g_free(xmlBuffer);
384     showingNoPreview = true;
389 /**
390  * Inform the user that the svg file is too large to be displayed.
391  * This does not check for sizes of embedded images (yet)
392  */
393 void SVGPreview::showTooLarge(long fileLength)
396     //Arbitrary size of svg doc -- rather 'portrait' shaped
397     gint previewWidth  = 300;
398     gint previewHeight = 600;
400     //Our template.  Modify to taste
401     gchar const *xformat =
402           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
403           "<svg\n"
404           "xmlns=\"http://www.w3.org/2000/svg\"\n"
405           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
406           "width=\"%d\" height=\"%d\">\n"  //# VALUES HERE
407           "<g transform=\"translate(-170,24.27184)\" style=\"opacity:0.12\">\n"
408           "<path\n"
409           "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
410           "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
411           "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
412           "id=\"whiteSpace\" />\n"
413           "<path\n"
414           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
415           "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
416           "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
417           "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
418           "id=\"droplet01\" />\n"
419           "<path\n"
420           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
421           "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
422           "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
423           "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
424           "287.18046 343.1206 286.46194 340.42914 z \"\n"
425           "id=\"droplet02\" />\n"
426           "<path\n"
427           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
428           "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
429           "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
430           "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
431           "id=\"droplet03\" />\n"
432           "<path\n"
433           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
434           "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
435           "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
436           "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
437           "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
438           "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
439           "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
440           "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
441           "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
442           "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
443           "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
444           "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
445           "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
446           "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
447           "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
448           "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
449           "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
450           "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
451           "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
452           "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
453           "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
454           "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
455           "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
456           "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
457           "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
458           "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
459           "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
460           "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
461           "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
462           "id=\"mountainDroplet\" />\n"
463           "</g>\n"
464           "<text xml:space=\"preserve\"\n"
465           "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
466           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
467           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
468           "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
469           "x=\"170\" y=\"215\">%5.1f MB</text>\n" //# VALUE HERE
470           "<text xml:space=\"preserve\"\n"
471           "style=\"font-size:24.000000;font-style:normal;font-variant:normal;font-weight:bold;"
472           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
473           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
474           "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
475           "x=\"180\" y=\"245\">%s</text>\n" //# VALUE HERE
476           "</svg>\n\n";
478     //Fill in the template
479     double floatFileLength = ((double)fileLength) / 1048576.0;
480     //printf("%ld %f\n", fileLength, floatFileLength);
481     gchar *xmlBuffer = g_strdup_printf(xformat,
482            previewWidth, previewHeight, floatFileLength,
483            _("too large for preview"));
485     //g_message("%s\n", xmlBuffer);
487     //now show it!
488     setFromMem(xmlBuffer);
489     g_free(xmlBuffer);
494 /**
495  * Return true if the string ends with the given suffix
496  */
497 static bool
498 hasSuffix(Glib::ustring &str, Glib::ustring &ext)
500     int strLen = str.length();
501     int extLen = ext.length();
502     if (extLen > strLen)
503         return false;
504     int strpos = strLen-1;
505     for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
506         {
507         Glib::ustring::value_type ch = str[strpos];
508         if (ch != ext[extpos])
509             {
510             if ( ((ch & 0xff80) != 0) ||
511                  static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
512                 {
513                 return false;
514                 }
515             }
516         }
517     return true;
521 /**
522  * Return true if the image is loadable by Gdk, else false
523  */
524 static bool
525 isValidImageFile(Glib::ustring &fileName)
527     std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
528     for (unsigned int i=0; i<formats.size(); i++)
529         {
530         Gdk::PixbufFormat format = formats[i];
531         std::vector<Glib::ustring>extensions = format.get_extensions();
532         for (unsigned int j=0; j<extensions.size(); j++)
533             {
534             Glib::ustring ext = extensions[j];
535             if (hasSuffix(fileName, ext))
536                 return true;
537             }
538         }
539     return false;
542 bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
545     if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS))
546         return false;
548     //g_message("fname:%s", fileName.c_str());
550     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
551         showNoPreview();
552         return false;
553     }
555     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR))
556         {
557         Glib::ustring fileNameUtf8 = Glib::filename_to_utf8(fileName);
558         gchar *fName = (gchar *)fileNameUtf8.c_str();
559         struct stat info;
560         if (g_stat(fName, &info))
561             {
562             g_warning("SVGPreview::set() : %s : %s",
563                            fName, strerror(errno));
564             return FALSE;
565             }
566         long fileLen = info.st_size;
567         if (fileLen > 0x150000L)
568             {
569             showingNoPreview = false;
570             showTooLarge(fileLen);
571             return FALSE;
572             }
573         }
575     Glib::ustring svg = ".svg";
576     Glib::ustring svgz = ".svgz";
578     if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
579            (hasSuffix(fileName, svg) || hasSuffix(fileName, svgz)   )
580         ) {
581         bool retval = setFileName(fileName);
582         showingNoPreview = false;
583         return retval;
584     } else if (isValidImageFile(fileName)) {
585         showImage(fileName);
586         showingNoPreview = false;
587         return true;
588     } else {
589         showNoPreview();
590         return false;
591     }
595 SVGPreview::SVGPreview()
597     if (!INKSCAPE)
598         inkscape_application_init("",false);
599     document = NULL;
600     viewerGtk = NULL;
601     set_size_request(150,150);
602     showingNoPreview = false;
605 SVGPreview::~SVGPreview()
611 /*#########################################################################
612 ### F I L E     D I A L O G    B A S E    C L A S S
613 #########################################################################*/
615 void FileDialogBaseGtk::internalSetup()
617     bool enablePreview =
618         (bool)prefs_get_int_attribute( preferenceBase.c_str(),
619              "enable_preview", 1 );
621     previewCheckbox.set_label( Glib::ustring(_("Enable preview")) );
622     previewCheckbox.set_active( enablePreview );
624     previewCheckbox.signal_toggled().connect(
625         sigc::mem_fun(*this, &FileDialogBaseGtk::_previewEnabledCB) );
627     //Catch selection-changed events, so we can adjust the text widget
628     signal_update_preview().connect(
629          sigc::mem_fun(*this, &FileDialogBaseGtk::_updatePreviewCallback) );
631     //###### Add a preview widget
632     set_preview_widget(svgPreview);
633     set_preview_widget_active( enablePreview );
634     set_use_preview_label (false);
639 void FileDialogBaseGtk::cleanup( bool showConfirmed )
641     if ( showConfirmed )
642         prefs_set_int_attribute( preferenceBase.c_str(),
643                "enable_preview", previewCheckbox.get_active() );
647 void FileDialogBaseGtk::_previewEnabledCB()
649     bool enabled = previewCheckbox.get_active();
650     set_preview_widget_active(enabled);
651     if ( enabled ) {
652         _updatePreviewCallback();
653     }
658 /**
659  * Callback for checking if the preview needs to be redrawn
660  */
661 void FileDialogBaseGtk::_updatePreviewCallback()
663     Glib::ustring fileName = get_preview_filename();
665 #ifdef WITH_GNOME_VFS
666     if ( fileName.empty() && gnome_vfs_initialized() ) {
667         fileName = get_preview_uri();
668     }
669 #endif
671     if (fileName.empty()) {
672         return;
673     }
675     svgPreview.set(fileName, dialogType);
679 /*#########################################################################
680 ### F I L E    O P E N
681 #########################################################################*/
683 /**
684  * Constructor.  Not called directly.  Use the factory.
685  */
686 FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow,
687                                        const Glib::ustring &dir,
688                                        FileDialogType fileTypes,
689                                        const Glib::ustring &title) :
690     FileDialogBaseGtk(parentWindow, title, fileTypes, "dialogs.open")
694     /* One file at a time */
695     /* And also Multiple Files */
696     set_select_multiple(true);
698 #ifdef WITH_GNOME_VFS
699     if (gnome_vfs_initialized()) {
700         set_local_only(false);
701     }
702 #endif
704     /* Initalize to Autodetect */
705     extension = NULL;
706     /* No filename to start out with */
707     myFilename = "";
709     /* Set our dialog type (open, import, etc...)*/
710     dialogType = fileTypes;
713     /* Set the pwd and/or the filename */
714     if (dir.size() > 0)
715         {
716         Glib::ustring udir(dir);
717         Glib::ustring::size_type len = udir.length();
718         // leaving a trailing backslash on the directory name leads to the infamous
719         // double-directory bug on win32
720         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
721         set_current_folder(udir.c_str());
722         }
725     set_extra_widget( previewCheckbox );
728     //###### Add the file types menu
729     createFilterMenu();
731     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
732     set_default(*add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_OK));
733         
734         //###### Allow easy access to our examples folder                
735     if(Inkscape::IO::file_test(INKSCAPE_EXAMPLESDIR,
736                 (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
737         {
738         add_shortcut_folder(INKSCAPE_EXAMPLESDIR);
739     }
742 /**
743  * Destructor
744  */
745 FileOpenDialogImplGtk::~FileOpenDialogImplGtk()
750 void FileOpenDialogImplGtk::createFilterMenu()
752     Gtk::FileFilter allInkscapeFilter;
753     allInkscapeFilter.set_name(_("All Inkscape Files"));
754     extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL;
755     add_filter(allInkscapeFilter);
757     Gtk::FileFilter allFilter;
758     allFilter.set_name(_("All Files"));
759     extensionMap[Glib::ustring(_("All Files"))]=NULL;
760     allFilter.add_pattern("*");
761     add_filter(allFilter);
763     Gtk::FileFilter allImageFilter;
764     allImageFilter.set_name(_("All Images"));
765     extensionMap[Glib::ustring(_("All Images"))]=NULL;
766     add_filter(allImageFilter);
768     //patterns added dynamically below
769     Inkscape::Extension::DB::InputList extension_list;
770     Inkscape::Extension::db.get_input_list(extension_list);
772     for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
773          current_item != extension_list.end(); current_item++)
774     {
775         Inkscape::Extension::Input * imod = *current_item;
777         // FIXME: would be nice to grey them out instead of not listing them
778         if (imod->deactivated()) continue;
780         Glib::ustring upattern("*");
781         Glib::ustring extension = imod->get_extension();
782         fileDialogExtensionToPattern(upattern, extension);
784         Gtk::FileFilter filter;
785         Glib::ustring uname(_(imod->get_filetypename()));
786         filter.set_name(uname);
787         filter.add_pattern(upattern);
788         add_filter(filter);
789         extensionMap[uname] = imod;
791         //g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str());
792         allInkscapeFilter.add_pattern(upattern);
793         if ( strncmp("image", imod->get_mimetype(), 5)==0 )
794             allImageFilter.add_pattern(upattern);
795     }
797     return;
800 /**
801  * Show this dialog modally.  Return true if user hits [OK]
802  */
803 bool
804 FileOpenDialogImplGtk::show()
806     Glib::ustring s = Glib::filename_to_utf8 (get_current_folder());
807     if (s.length() == 0)
808         s = getcwd (NULL, 0);
809     set_current_folder(Glib::filename_from_utf8(s)); //hack to force initial dir listing
810     set_modal (TRUE);                      //Window
811     sp_transientize((GtkWidget *)gobj());  //Make transient
812     gint b = run();                        //Dialog
813     svgPreview.showNoPreview();
814     hide();
816     if (b == Gtk::RESPONSE_OK)
817         {
818         //This is a hack, to avoid the warning messages that
819         //Gtk::FileChooser::get_filter() returns
820         //should be:  Gtk::FileFilter *filter = get_filter();
821         GtkFileChooser *gtkFileChooser = Gtk::FileChooser::gobj();
822         GtkFileFilter *filter = gtk_file_chooser_get_filter(gtkFileChooser);
823         if (filter)
824             {
825             //Get which extension was chosen, if any
826             extension = extensionMap[gtk_file_filter_get_name(filter)];
827             }
828         myFilename = get_filename();
829 #ifdef WITH_GNOME_VFS
830         if (myFilename.empty() && gnome_vfs_initialized())
831             myFilename = get_uri();
832 #endif
833         cleanup( true );
834         return TRUE;
835         }
836     else
837        {
838        cleanup( false );
839        return FALSE;
840        }
846 /**
847  * Get the file extension type that was selected by the user. Valid after an [OK]
848  */
849 Inkscape::Extension::Extension *
850 FileOpenDialogImplGtk::getSelectionType()
852     return extension;
856 /**
857  * Get the file name chosen by the user.   Valid after an [OK]
858  */
859 Glib::ustring
860 FileOpenDialogImplGtk::getFilename (void)
862     return g_strdup(myFilename.c_str());
866 /**
867  * To Get Multiple filenames selected at-once.
868  */
869 std::vector<Glib::ustring>FileOpenDialogImplGtk::getFilenames()
871     std::vector<Glib::ustring> result = get_filenames();
872 #ifdef WITH_GNOME_VFS
873     if (result.empty() && gnome_vfs_initialized())
874         result = get_uris();
875 #endif
876     return result;
884 //########################################################################
885 //# F I L E    S A V E
886 //########################################################################
888 /**
889  * Constructor
890  */
891 FileSaveDialogImplGtk::FileSaveDialogImplGtk( Gtk::Window &parentWindow,
892                                               const Glib::ustring &dir,
893                                               FileDialogType fileTypes,
894                                               const Glib::ustring &title,
895                                               const Glib::ustring &/*default_key*/ ) :
896     FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_SAVE, fileTypes, "dialogs.save_as")
898     /* One file at a time */
899     set_select_multiple(false);
901 #ifdef WITH_GNOME_VFS
902     if (gnome_vfs_initialized()) {
903         set_local_only(false);
904     }
905 #endif
907     /* Initalize to Autodetect */
908     extension = NULL;
909     /* No filename to start out with */
910     myFilename = "";
912     /* Set our dialog type (save, export, etc...)*/
913     dialogType = fileTypes;
915     /* Set the pwd and/or the filename */
916     if (dir.size() > 0)
917         {
918         Glib::ustring udir(dir);
919         Glib::ustring::size_type len = udir.length();
920         // leaving a trailing backslash on the directory name leads to the infamous
921         // double-directory bug on win32
922         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
923         myFilename = udir;
924         }
926     //###### Add the file types menu
927     //createFilterMenu();
929     //###### Do we want the .xxx extension automatically added?
930     fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
931     fileTypeCheckbox.set_active( (bool)prefs_get_int_attribute("dialogs.save_as",
932                                                                "append_extension", 1) );
934     createFileTypeMenu();
935     fileTypeComboBox.set_size_request(200,40);
936     fileTypeComboBox.signal_changed().connect(
937          sigc::mem_fun(*this, &FileSaveDialogImplGtk::fileTypeChangedCallback) );
940     childBox.pack_start( checksBox );
941     childBox.pack_end( fileTypeComboBox );
942     checksBox.pack_start( fileTypeCheckbox );
943     checksBox.pack_start( previewCheckbox );
945     set_extra_widget( childBox );
947     //Let's do some customization
948     fileNameEntry = NULL;
949     Gtk::Container *cont = get_toplevel();
950     std::vector<Gtk::Entry *> entries;
951     findEntryWidgets(cont, entries);
952     //g_message("Found %d entry widgets\n", entries.size());
953     if (entries.size() >=1 )
954         {
955         //Catch when user hits [return] on the text field
956         fileNameEntry = entries[0];
957         fileNameEntry->signal_activate().connect(
958              sigc::mem_fun(*this, &FileSaveDialogImplGtk::fileNameEntryChangedCallback) );
959         }
961     //Let's do more customization
962     std::vector<Gtk::Expander *> expanders;
963     findExpanderWidgets(cont, expanders);
964     //g_message("Found %d expander widgets\n", expanders.size());
965     if (expanders.size() >=1 )
966         {
967         //Always show the file list
968         Gtk::Expander *expander = expanders[0];
969         expander->set_expanded(true);
970         }
973     //if (extension == NULL)
974     //    checkbox.set_sensitive(FALSE);
976     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
977     set_default(*add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_OK));
979     show_all_children();
982 /**
983  * Destructor
984  */
985 FileSaveDialogImplGtk::~FileSaveDialogImplGtk()
989 /**
990  * Callback for fileNameEntry widget
991  */
992 void FileSaveDialogImplGtk::fileNameEntryChangedCallback()
994     if (!fileNameEntry)
995         return;
997     Glib::ustring fileName = fileNameEntry->get_text();
998     if (!Glib::get_charset()) //If we are not utf8
999         fileName = Glib::filename_to_utf8(fileName);
1001     //g_message("User hit return.  Text is '%s'\n", fileName.c_str());
1003     if (!Glib::path_is_absolute(fileName)) {
1004         //try appending to the current path
1005         // not this way: fileName = get_current_folder() + "/" + fileName;
1006         std::vector<Glib::ustring> pathSegments;
1007         pathSegments.push_back( get_current_folder() );
1008         pathSegments.push_back( fileName );
1009         fileName = Glib::build_filename(pathSegments);
1010     }
1012     //g_message("path:'%s'\n", fileName.c_str());
1014     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1015         set_current_folder(fileName);
1016     } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1017         //dialog with either (1) select a regular file or (2) cd to dir
1018         //simulate an 'OK'
1019         set_filename(fileName);
1020         response(Gtk::RESPONSE_OK);
1021     }
1026 /**
1027  * Callback for fileNameEntry widget
1028  */
1029 void FileSaveDialogImplGtk::fileTypeChangedCallback()
1031     int sel = fileTypeComboBox.get_active_row_number();
1032     if (sel<0 || sel >= (int)fileTypes.size())
1033         return;
1034     FileType type = fileTypes[sel];
1035     //g_message("selected: %s\n", type.name.c_str());
1037     extension = type.extension;
1038     Gtk::FileFilter filter;
1039     filter.add_pattern(type.pattern);
1040     set_filter(filter);
1042     updateNameAndExtension();
1047 void FileSaveDialogImplGtk::createFileTypeMenu()
1049     Inkscape::Extension::DB::OutputList extension_list;
1050     Inkscape::Extension::db.get_output_list(extension_list);
1051     knownExtensions.clear();
1053     for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1054          current_item != extension_list.end(); current_item++)
1055     {
1056         Inkscape::Extension::Output * omod = *current_item;
1058         // FIXME: would be nice to grey them out instead of not listing them
1059         if (omod->deactivated()) continue;
1061         FileType type;
1062         type.name     = (_(omod->get_filetypename()));
1063         type.pattern  = "*";
1064         Glib::ustring extension = omod->get_extension();
1065         knownExtensions.insert( extension.casefold() );
1066         fileDialogExtensionToPattern (type.pattern, extension);
1067         type.extension= omod;
1068         fileTypeComboBox.append_text(type.name);
1069         fileTypes.push_back(type);
1070     }
1072     //#Let user choose
1073     FileType guessType;
1074     guessType.name = _("Guess from extension");
1075     guessType.pattern = "*";
1076     guessType.extension = NULL;
1077     fileTypeComboBox.append_text(guessType.name);
1078     fileTypes.push_back(guessType);
1081     fileTypeComboBox.set_active(0);
1082     fileTypeChangedCallback(); //call at least once to set the filter
1089 /**
1090  * Show this dialog modally.  Return true if user hits [OK]
1091  */
1092 bool
1093 FileSaveDialogImplGtk::show()
1095     change_path(myFilename);
1096     set_modal (TRUE);                      //Window
1097     sp_transientize((GtkWidget *)gobj());  //Make transient
1098     gint b = run();                        //Dialog
1099     svgPreview.showNoPreview();
1100     set_preview_widget_active(false);
1101     hide();
1103     if (b == Gtk::RESPONSE_OK)
1104         {
1105         updateNameAndExtension();
1107         // Store changes of the "Append filename automatically" checkbox back to preferences.
1108         prefs_set_int_attribute("dialogs.save_as", "append_extension", fileTypeCheckbox.get_active());
1110         // Store the last used save-as filetype to preferences.
1111         prefs_set_string_attribute("dialogs.save_as", "default",
1112                                    ( extension != NULL ? extension->get_id() : "" ));
1114         cleanup( true );
1116         return TRUE;
1117         }
1118     else
1119         {
1120         cleanup( false );
1122         return FALSE;
1123         }
1127 /**
1128  * Get the file extension type that was selected by the user. Valid after an [OK]
1129  */
1130 Inkscape::Extension::Extension *
1131 FileSaveDialogImplGtk::getSelectionType()
1133     return extension;
1136 void FileSaveDialogImplGtk::setSelectionType( Inkscape::Extension::Extension * key )
1138     // If no pointer to extension is passed in, look up based on filename extension.
1139     if ( !key ) {
1140         // Not quite UTF-8 here.
1141         gchar *filenameLower = g_ascii_strdown(myFilename.c_str(), -1);
1142         for ( int i = 0; !key && (i < (int)fileTypes.size()); i++ ) {
1143             Inkscape::Extension::Output *ext = dynamic_cast<Inkscape::Extension::Output*>(fileTypes[i].extension);
1144             if ( ext && ext->get_extension() ) {
1145                 gchar *extensionLower = g_ascii_strdown( ext->get_extension(), -1 );
1146                 if ( g_str_has_suffix(filenameLower, extensionLower) ) {
1147                     key = fileTypes[i].extension;
1148                 }
1149                 g_free(extensionLower);
1150             }
1151         }
1152         g_free(filenameLower);
1153     }
1155     // Ensure the proper entry in the combo box is selected.
1156     if ( key ) {
1157         extension = key;
1158         gchar const * extensionID = extension->get_id();
1159         if ( extensionID ) {
1160             for ( int i = 0; i < (int)fileTypes.size(); i++ ) {
1161                 Inkscape::Extension::Extension *ext = fileTypes[i].extension;
1162                 if ( ext ) {
1163                     gchar const * id = ext->get_id();
1164                     if ( id && ( strcmp(extensionID, id) == 0) ) {
1165                         int oldSel = fileTypeComboBox.get_active_row_number();
1166                         if ( i != oldSel ) {
1167                             fileTypeComboBox.set_active(i);
1168                         }
1169                         break;
1170                     }
1171                 }
1172             }
1173         }
1174     }
1178 /**
1179  * Get the file name chosen by the user.   Valid after an [OK]
1180  */
1181 Glib::ustring
1182 FileSaveDialogImplGtk::getFilename()
1184     return myFilename;
1188 void
1189 FileSaveDialogImplGtk::change_title(const Glib::ustring& title)
1191     this->set_title(title);
1194 /**
1195   * Change the default save path location.
1196   */
1197 void
1198 FileSaveDialogImplGtk::change_path(const Glib::ustring& path)
1200     myFilename = path;
1201     if (Glib::file_test(myFilename, Glib::FILE_TEST_IS_DIR)) {
1202         //fprintf(stderr,"set_current_folder(%s)\n",myFilename.c_str());
1203         set_current_folder(myFilename);
1204     } else {
1205         //fprintf(stderr,"set_filename(%s)\n",myFilename.c_str());
1206         if ( Glib::file_test( myFilename, Glib::FILE_TEST_EXISTS ) ) {
1207             set_filename(myFilename);
1208         } else {
1209             std::string dirName = Glib::path_get_dirname( myFilename  );
1210             if ( dirName != get_current_folder() ) {
1211                 set_current_folder(dirName);
1212             }
1213         }
1214         Glib::ustring basename = Glib::path_get_basename(myFilename);
1215         //fprintf(stderr,"set_current_name(%s)\n",basename.c_str());
1216         try {
1217             set_current_name( Glib::filename_to_utf8(basename) );
1218         } catch ( Glib::ConvertError& e ) {
1219             g_warning( "Error converting save filename to UTF-8." );
1220             // try a fallback.
1221             set_current_name( basename );
1222         }
1223     }
1226 void FileSaveDialogImplGtk::updateNameAndExtension()
1228     // Pick up any changes the user has typed in.
1229     Glib::ustring tmp = get_filename();
1230 #ifdef WITH_GNOME_VFS
1231     if ( tmp.empty() && gnome_vfs_initialized() ) {
1232         tmp = get_uri();
1233     }
1234 #endif
1235     if ( !tmp.empty() ) {
1236         myFilename = tmp;
1237     }
1239     Inkscape::Extension::Output* newOut = extension ? dynamic_cast<Inkscape::Extension::Output*>(extension) : 0;
1240     if ( fileTypeCheckbox.get_active() && newOut ) {
1241         try {
1242             bool appendExtension = true;
1243             Glib::ustring utf8Name = Glib::filename_to_utf8( myFilename );
1244             Glib::ustring::size_type pos = utf8Name.rfind('.');
1245             if ( pos != Glib::ustring::npos ) {
1246                 Glib::ustring trail = utf8Name.substr( pos );
1247                 Glib::ustring foldedTrail = trail.casefold();
1248                 if ( (trail == ".")
1249                      | (foldedTrail != Glib::ustring( newOut->get_extension() ).casefold()
1250                         && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) {
1251                     utf8Name = utf8Name.erase( pos );
1252                 } else {
1253                     appendExtension = false;
1254                 }
1255             }
1257             if (appendExtension) {
1258                 utf8Name = utf8Name + newOut->get_extension();
1259                 myFilename = Glib::filename_from_utf8( utf8Name );
1260                 change_path(myFilename);
1261             }
1262         } catch ( Glib::ConvertError& e ) {
1263             // ignore
1264         }
1265     }
1269 //########################################################################
1270 //# F I L E     E X P O R T
1271 //########################################################################
1273 /**
1274  * Callback for fileNameEntry widget
1275  */
1276 void FileExportDialogImpl::fileNameEntryChangedCallback()
1278     if (!fileNameEntry)
1279         return;
1281     Glib::ustring fileName = fileNameEntry->get_text();
1282     if (!Glib::get_charset()) //If we are not utf8
1283         fileName = Glib::filename_to_utf8(fileName);
1285     //g_message("User hit return.  Text is '%s'\n", fileName.c_str());
1287     if (!Glib::path_is_absolute(fileName)) {
1288         //try appending to the current path
1289         // not this way: fileName = get_current_folder() + "/" + fileName;
1290         std::vector<Glib::ustring> pathSegments;
1291         pathSegments.push_back( get_current_folder() );
1292         pathSegments.push_back( fileName );
1293         fileName = Glib::build_filename(pathSegments);
1294     }
1296     //g_message("path:'%s'\n", fileName.c_str());
1298     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1299         set_current_folder(fileName);
1300     } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1301         //dialog with either (1) select a regular file or (2) cd to dir
1302         //simulate an 'OK'
1303         set_filename(fileName);
1304         response(Gtk::RESPONSE_OK);
1305     }
1310 /**
1311  * Callback for fileNameEntry widget
1312  */
1313 void FileExportDialogImpl::fileTypeChangedCallback()
1315     int sel = fileTypeComboBox.get_active_row_number();
1316     if (sel<0 || sel >= (int)fileTypes.size())
1317         return;
1318     FileType type = fileTypes[sel];
1319     //g_message("selected: %s\n", type.name.c_str());
1320     Gtk::FileFilter filter;
1321     filter.add_pattern(type.pattern);
1322     set_filter(filter);
1327 void FileExportDialogImpl::createFileTypeMenu()
1329     Inkscape::Extension::DB::OutputList extension_list;
1330     Inkscape::Extension::db.get_output_list(extension_list);
1332     for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1333          current_item != extension_list.end(); current_item++)
1334     {
1335         Inkscape::Extension::Output * omod = *current_item;
1337         // FIXME: would be nice to grey them out instead of not listing them
1338         if (omod->deactivated()) continue;
1340         FileType type;
1341         type.name     = (_(omod->get_filetypename()));
1342         type.pattern  = "*";
1343         Glib::ustring extension = omod->get_extension();
1344         fileDialogExtensionToPattern (type.pattern, extension);
1345         type.extension= omod;
1346         fileTypeComboBox.append_text(type.name);
1347         fileTypes.push_back(type);
1348     }
1350     //#Let user choose
1351     FileType guessType;
1352     guessType.name = _("Guess from extension");
1353     guessType.pattern = "*";
1354     guessType.extension = NULL;
1355     fileTypeComboBox.append_text(guessType.name);
1356     fileTypes.push_back(guessType);
1359     fileTypeComboBox.set_active(0);
1360     fileTypeChangedCallback(); //call at least once to set the filter
1364 /**
1365  * Constructor
1366  */
1367 FileExportDialogImpl::FileExportDialogImpl( Gtk::Window& parentWindow,
1368                                             const Glib::ustring &dir,
1369                                             FileDialogType fileTypes,
1370                                             const Glib::ustring &title,
1371                                             const Glib::ustring &/*default_key*/ ) :
1372             FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_SAVE, fileTypes, "dialogs.export"),
1373             sourceX0Spinner("X0",         _("Left edge of source")),
1374             sourceY0Spinner("Y0",         _("Top edge of source")),
1375             sourceX1Spinner("X1",         _("Right edge of source")),
1376             sourceY1Spinner("Y1",         _("Bottom edge of source")),
1377             sourceWidthSpinner("Width",   _("Source width")),
1378             sourceHeightSpinner("Height", _("Source height")),
1379             destWidthSpinner("Width",     _("Destination width")),
1380             destHeightSpinner("Height",   _("Destination height")),
1381             destDPISpinner("DPI",         _("Resolution (dots per inch)"))
1383     append_extension = (bool)prefs_get_int_attribute("dialogs.save_as", "append_extension", 1);
1385     /* One file at a time */
1386     set_select_multiple(false);
1388 #ifdef WITH_GNOME_VFS
1389     if (gnome_vfs_initialized()) {
1390         set_local_only(false);
1391     }
1392 #endif
1394     /* Initalize to Autodetect */
1395     extension = NULL;
1396     /* No filename to start out with */
1397     myFilename = "";
1399     /* Set our dialog type (save, export, etc...)*/
1400     dialogType = fileTypes;
1402     /* Set the pwd and/or the filename */
1403     if (dir.size()>0)
1404         {
1405         Glib::ustring udir(dir);
1406         Glib::ustring::size_type len = udir.length();
1407         // leaving a trailing backslash on the directory name leads to the infamous
1408         // double-directory bug on win32
1409         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
1410         set_current_folder(udir.c_str());
1411         }
1413     //#########################################
1414     //## EXTRA WIDGET -- SOURCE SIDE
1415     //#########################################
1417     //##### Export options buttons/spinners, etc
1418     documentButton.set_label(_("Document"));
1419     scopeBox.pack_start(documentButton);
1420     scopeGroup = documentButton.get_group();
1422     pageButton.set_label(_("Page"));
1423     pageButton.set_group(scopeGroup);
1424     scopeBox.pack_start(pageButton);
1426     selectionButton.set_label(_("Selection"));
1427     selectionButton.set_group(scopeGroup);
1428     scopeBox.pack_start(selectionButton);
1430     customButton.set_label(_("Custom"));
1431     customButton.set_group(scopeGroup);
1432     scopeBox.pack_start(customButton);
1434     sourceBox.pack_start(scopeBox);
1438     //dimension buttons
1439     sourceTable.resize(3,3);
1440     sourceTable.attach(sourceX0Spinner,     0,1,0,1);
1441     sourceTable.attach(sourceY0Spinner,     1,2,0,1);
1442     sourceUnitsSpinner.setUnitType(UNIT_TYPE_LINEAR);
1443     sourceTable.attach(sourceUnitsSpinner,  2,3,0,1);
1444     sourceTable.attach(sourceX1Spinner,     0,1,1,2);
1445     sourceTable.attach(sourceY1Spinner,     1,2,1,2);
1446     sourceTable.attach(sourceWidthSpinner,  0,1,2,3);
1447     sourceTable.attach(sourceHeightSpinner, 1,2,2,3);
1449     sourceBox.pack_start(sourceTable);
1450     sourceFrame.set_label(_("Source"));
1451     sourceFrame.add(sourceBox);
1452     exportOptionsBox.pack_start(sourceFrame);
1455     //#########################################
1456     //## EXTRA WIDGET -- SOURCE SIDE
1457     //#########################################
1460     destTable.resize(3,3);
1461     destTable.attach(destWidthSpinner,    0,1,0,1);
1462     destTable.attach(destHeightSpinner,   1,2,0,1);
1463     destUnitsSpinner.setUnitType(UNIT_TYPE_LINEAR);
1464     destTable.attach(destUnitsSpinner,    2,3,0,1);
1465     destTable.attach(destDPISpinner,      0,1,1,2);
1467     destBox.pack_start(destTable);
1470     cairoButton.set_label(_("Cairo"));
1471     otherOptionBox.pack_start(cairoButton);
1473     antiAliasButton.set_label(_("Antialias"));
1474     otherOptionBox.pack_start(antiAliasButton);
1476     backgroundButton.set_label(_("Background"));
1477     otherOptionBox.pack_start(backgroundButton);
1479     destBox.pack_start(otherOptionBox);
1485     //###### File options
1486     //###### Do we want the .xxx extension automatically added?
1487     fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
1488     fileTypeCheckbox.set_active(append_extension);
1489     destBox.pack_start(fileTypeCheckbox);
1491     //###### File type menu
1492     createFileTypeMenu();
1493     fileTypeComboBox.set_size_request(200,40);
1494     fileTypeComboBox.signal_changed().connect(
1495          sigc::mem_fun(*this, &FileExportDialogImpl::fileTypeChangedCallback) );
1497     destBox.pack_start(fileTypeComboBox);
1499     destFrame.set_label(_("Destination"));
1500     destFrame.add(destBox);
1501     exportOptionsBox.pack_start(destFrame);
1503     //##### Put the two boxes and their parent onto the dialog
1504     exportOptionsBox.pack_start(sourceFrame);
1505     exportOptionsBox.pack_start(destFrame);
1507     set_extra_widget(exportOptionsBox);
1512     //Let's do some customization
1513     fileNameEntry = NULL;
1514     Gtk::Container *cont = get_toplevel();
1515     std::vector<Gtk::Entry *> entries;
1516     findEntryWidgets(cont, entries);
1517     //g_message("Found %d entry widgets\n", entries.size());
1518     if (entries.size() >=1 )
1519         {
1520         //Catch when user hits [return] on the text field
1521         fileNameEntry = entries[0];
1522         fileNameEntry->signal_activate().connect(
1523              sigc::mem_fun(*this, &FileExportDialogImpl::fileNameEntryChangedCallback) );
1524         }
1526     //Let's do more customization
1527     std::vector<Gtk::Expander *> expanders;
1528     findExpanderWidgets(cont, expanders);
1529     //g_message("Found %d expander widgets\n", expanders.size());
1530     if (expanders.size() >=1 )
1531         {
1532         //Always show the file list
1533         Gtk::Expander *expander = expanders[0];
1534         expander->set_expanded(true);
1535         }
1538     //if (extension == NULL)
1539     //    checkbox.set_sensitive(FALSE);
1541     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1542     set_default(*add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_OK));
1544     show_all_children();
1547 /**
1548  * Destructor
1549  */
1550 FileExportDialogImpl::~FileExportDialogImpl()
1556 /**
1557  * Show this dialog modally.  Return true if user hits [OK]
1558  */
1559 bool
1560 FileExportDialogImpl::show()
1562     Glib::ustring s = Glib::filename_to_utf8 (get_current_folder());
1563     if (s.length() == 0)
1564         s = getcwd (NULL, 0);
1565     set_current_folder(Glib::filename_from_utf8(s)); //hack to force initial dir listing
1566     set_modal (TRUE);                      //Window
1567     sp_transientize((GtkWidget *)gobj());  //Make transient
1568     gint b = run();                        //Dialog
1569     svgPreview.showNoPreview();
1570     hide();
1572     if (b == Gtk::RESPONSE_OK)
1573         {
1574         int sel = fileTypeComboBox.get_active_row_number ();
1575         if (sel>=0 && sel< (int)fileTypes.size())
1576             {
1577             FileType &type = fileTypes[sel];
1578             extension = type.extension;
1579             }
1580         myFilename = get_filename();
1581 #ifdef WITH_GNOME_VFS
1582         if ( myFilename.empty() && gnome_vfs_initialized() ) {
1583             myFilename = get_uri();
1584         }
1585 #endif
1587         /*
1589         // FIXME: Why do we have more code
1591         append_extension = checkbox.get_active();
1592         prefs_set_int_attribute("dialogs.save_as", "append_extension", append_extension);
1593         prefs_set_string_attribute("dialogs.save_as", "default",
1594                   ( extension != NULL ? extension->get_id() : "" ));
1595         */
1596         return TRUE;
1597         }
1598     else
1599         {
1600         return FALSE;
1601         }
1605 /**
1606  * Get the file extension type that was selected by the user. Valid after an [OK]
1607  */
1608 Inkscape::Extension::Extension *
1609 FileExportDialogImpl::getSelectionType()
1611     return extension;
1615 /**
1616  * Get the file name chosen by the user.   Valid after an [OK]
1617  */
1618 Glib::ustring
1619 FileExportDialogImpl::getFilename()
1621     return myFilename;
1625 } //namespace Dialog
1626 } //namespace UI
1627 } //namespace Inkscape
1629 /*
1630   Local Variables:
1631   mode:c++
1632   c-file-style:"stroustrup"
1633   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1634   indent-tabs-mode:nil
1635   fill-column:99
1636   End:
1637 */
1638 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :