08c0d411615c801106332b5a31816862a84cb491
1 /**
2 * Implementation of the file dialog interfaces defined in filedialog.h
3 *
4 * Authors:
5 * Bob Jamison
6 * Other dudes from The Inkscape Organization
7 *
8 * Copyright (C) 2004-2007 Bob Jamison
9 * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
10 * Copyright (C) 2004-2007 The Inkscape Organization
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
20 //General includes
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <errno.h>
24 #include <set>
26 //Gtk includes
27 #include <gtkmm.h>
28 #include <glibmm/i18n.h>
29 #include <glib/gstdio.h>
30 //Temporary ugly hack
31 //Remove this after the get_filter() calls in
32 //show() on both classes are fixed
33 #include <gtk/gtkfilechooser.h>
34 //Another hack
35 #include <gtk/gtkentry.h>
36 #include <gtk/gtkexpander.h>
37 #ifdef WITH_GNOME_VFS
38 # include <libgnomevfs/gnome-vfs-init.h> // gnome_vfs_initialized
39 #endif
43 //Inkscape includes
44 #include "prefs-utils.h"
45 #include <dialogs/dialog-events.h>
46 #include <extension/input.h>
47 #include <extension/output.h>
48 #include <extension/db.h>
49 #include "inkscape.h"
50 #include "svg-view-widget.h"
51 #include "filedialog.h"
52 #include "gc-core.h"
54 //For export dialog
55 #include "ui/widget/scalar-unit.h"
58 //Routines from file.cpp
59 #undef INK_DUMP_FILENAME_CONV
61 #ifdef INK_DUMP_FILENAME_CONV
62 void dump_str( const gchar* str, const gchar* prefix );
63 void dump_ustr( const Glib::ustring& ustr );
64 #endif
68 namespace Inkscape
69 {
70 namespace UI
71 {
72 namespace Dialog
73 {
79 //########################################################################
80 //### U T I L I T Y
81 //########################################################################
83 /**
84 \brief A quick function to turn a standard extension into a searchable
85 pattern for the file dialogs
86 \param pattern The patter that the extension should be written to
87 \param in_file_extension The C string that represents the extension
89 This function just goes through the string, and takes all characters
90 and puts a [<upper><lower>] so that both are searched and shown in
91 the file dialog. This function edits the pattern string to make
92 this happen.
93 */
94 static void
95 fileDialogExtensionToPattern(Glib::ustring &pattern,
96 Glib::ustring &extension)
97 {
98 for (unsigned int i = 0; i < extension.length(); i++ )
99 {
100 Glib::ustring::value_type ch = extension[i];
101 if ( Glib::Unicode::isalpha(ch) )
102 {
103 pattern += '[';
104 pattern += Glib::Unicode::toupper(ch);
105 pattern += Glib::Unicode::tolower(ch);
106 pattern += ']';
107 }
108 else
109 {
110 pattern += ch;
111 }
112 }
113 }
116 /**
117 * Hack: Find all entry widgets in a container
118 */
119 static void
120 findEntryWidgets(Gtk::Container *parent,
121 std::vector<Gtk::Entry *> &result)
122 {
123 if (!parent)
124 return;
125 std::vector<Gtk::Widget *> children = parent->get_children();
126 for (unsigned int i=0; i<children.size() ; i++)
127 {
128 Gtk::Widget *child = children[i];
129 GtkWidget *wid = child->gobj();
130 if (GTK_IS_ENTRY(wid))
131 result.push_back((Gtk::Entry *)child);
132 else if (GTK_IS_CONTAINER(wid))
133 findEntryWidgets((Gtk::Container *)child, result);
134 }
136 }
141 /**
142 * Hack: Find all expander widgets in a container
143 */
144 static void
145 findExpanderWidgets(Gtk::Container *parent,
146 std::vector<Gtk::Expander *> &result)
147 {
148 if (!parent)
149 return;
150 std::vector<Gtk::Widget *> children = parent->get_children();
151 for (unsigned int i=0; i<children.size() ; i++)
152 {
153 Gtk::Widget *child = children[i];
154 GtkWidget *wid = child->gobj();
155 if (GTK_IS_EXPANDER(wid))
156 result.push_back((Gtk::Expander *)child);
157 else if (GTK_IS_CONTAINER(wid))
158 findExpanderWidgets((Gtk::Container *)child, result);
159 }
161 }
164 /*#########################################################################
165 ### SVG Preview Widget
166 #########################################################################*/
168 /**
169 * Simple class for displaying an SVG file in the "preview widget."
170 * Currently, this is just a wrapper of the sp_svg_view Gtk widget.
171 * Hopefully we will eventually replace with a pure Gtkmm widget.
172 */
173 class SVGPreview : public Gtk::VBox
174 {
175 public:
177 SVGPreview();
179 ~SVGPreview();
181 bool setDocument(SPDocument *doc);
183 bool setFileName(Glib::ustring &fileName);
185 bool setFromMem(char const *xmlBuffer);
187 bool set(Glib::ustring &fileName, int dialogType);
189 bool setURI(URI &uri);
191 /**
192 * Show image embedded in SVG
193 */
194 void showImage(Glib::ustring &fileName);
196 /**
197 * Show the "No preview" image
198 */
199 void showNoPreview();
201 /**
202 * Show the "Too large" image
203 */
204 void showTooLarge(long fileLength);
206 private:
207 /**
208 * The svg document we are currently showing
209 */
210 SPDocument *document;
212 /**
213 * The sp_svg_view widget
214 */
215 GtkWidget *viewerGtk;
217 /**
218 * are we currently showing the "no preview" image?
219 */
220 bool showingNoPreview;
222 };
225 bool SVGPreview::setDocument(SPDocument *doc)
226 {
227 if (document)
228 sp_document_unref(document);
230 sp_document_ref(doc);
231 document = doc;
233 //This should remove it from the box, and free resources
234 if (viewerGtk)
235 gtk_widget_destroy(viewerGtk);
237 viewerGtk = sp_svg_view_widget_new(doc);
238 GtkWidget *vbox = (GtkWidget *)gobj();
239 gtk_box_pack_start(GTK_BOX(vbox), viewerGtk, TRUE, TRUE, 0);
240 gtk_widget_show(viewerGtk);
242 return true;
243 }
246 bool SVGPreview::setFileName(Glib::ustring &theFileName)
247 {
248 Glib::ustring fileName = theFileName;
250 fileName = Glib::filename_to_utf8(fileName);
252 /**
253 * I don't know why passing false to keepalive is bad. But it
254 * prevents the display of an svg with a non-ascii filename
255 */
256 SPDocument *doc = sp_document_new (fileName.c_str(), true);
257 if (!doc) {
258 g_warning("SVGView: error loading document '%s'\n", fileName.c_str());
259 return false;
260 }
262 setDocument(doc);
264 sp_document_unref(doc);
266 return true;
267 }
271 bool SVGPreview::setFromMem(char const *xmlBuffer)
272 {
273 if (!xmlBuffer)
274 return false;
276 gint len = (gint)strlen(xmlBuffer);
277 SPDocument *doc = sp_document_new_from_mem(xmlBuffer, len, 0);
278 if (!doc) {
279 g_warning("SVGView: error loading buffer '%s'\n",xmlBuffer);
280 return false;
281 }
283 setDocument(doc);
285 sp_document_unref(doc);
287 Inkscape::GC::request_early_collection();
289 return true;
290 }
294 void SVGPreview::showImage(Glib::ustring &theFileName)
295 {
296 Glib::ustring fileName = theFileName;
299 /*#####################################
300 # LET'S HAVE SOME FUN WITH SVG!
301 # Instead of just loading an image, why
302 # don't we make a lovely little svg and
303 # display it nicely?
304 #####################################*/
306 //Arbitrary size of svg doc -- rather 'portrait' shaped
307 gint previewWidth = 400;
308 gint previewHeight = 600;
310 //Get some image info. Smart pointer does not need to be deleted
311 Glib::RefPtr<Gdk::Pixbuf> img = Gdk::Pixbuf::create_from_file(fileName);
312 gint imgWidth = img->get_width();
313 gint imgHeight = img->get_height();
315 //Find the minimum scale to fit the image inside the preview area
316 double scaleFactorX = (0.9 *(double)previewWidth) / ((double)imgWidth);
317 double scaleFactorY = (0.9 *(double)previewHeight) / ((double)imgHeight);
318 double scaleFactor = scaleFactorX;
319 if (scaleFactorX > scaleFactorY)
320 scaleFactor = scaleFactorY;
322 //Now get the resized values
323 gint scaledImgWidth = (int) (scaleFactor * (double)imgWidth);
324 gint scaledImgHeight = (int) (scaleFactor * (double)imgHeight);
326 //center the image on the area
327 gint imgX = (previewWidth - scaledImgWidth) / 2;
328 gint imgY = (previewHeight - scaledImgHeight) / 2;
330 //wrap a rectangle around the image
331 gint rectX = imgX-1;
332 gint rectY = imgY-1;
333 gint rectWidth = scaledImgWidth +2;
334 gint rectHeight = scaledImgHeight+2;
336 //Our template. Modify to taste
337 gchar const *xformat =
338 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
339 "<svg\n"
340 "xmlns=\"http://www.w3.org/2000/svg\"\n"
341 "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
342 "width=\"%d\" height=\"%d\">\n" //# VALUES HERE
343 "<rect\n"
344 " style=\"fill:#eeeeee;stroke:none\"\n"
345 " x=\"-100\" y=\"-100\" width=\"4000\" height=\"4000\"/>\n"
346 "<image x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"\n"
347 "xlink:href=\"%s\"/>\n"
348 "<rect\n"
349 " style=\"fill:none;"
350 " stroke:#000000;stroke-width:1.0;"
351 " stroke-linejoin:miter;stroke-opacity:1.0000000;"
352 " stroke-miterlimit:4.0000000;stroke-dasharray:none\"\n"
353 " x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
354 "<text\n"
355 " style=\"font-size:24.000000;font-style:normal;font-weight:normal;"
356 " fill:#000000;fill-opacity:1.0000000;stroke:none;"
357 " font-family:Bitstream Vera Sans\"\n"
358 " x=\"10\" y=\"26\">%d x %d</text>\n" //# VALUES HERE
359 "</svg>\n\n";
361 //if (!Glib::get_charset()) //If we are not utf8
362 fileName = Glib::filename_to_utf8(fileName);
364 //Fill in the template
365 /* FIXME: Do proper XML quoting for fileName. */
366 gchar *xmlBuffer = g_strdup_printf(xformat,
367 previewWidth, previewHeight,
368 imgX, imgY, scaledImgWidth, scaledImgHeight,
369 fileName.c_str(),
370 rectX, rectY, rectWidth, rectHeight,
371 imgWidth, imgHeight);
373 //g_message("%s\n", xmlBuffer);
375 //now show it!
376 setFromMem(xmlBuffer);
377 g_free(xmlBuffer);
378 }
382 void SVGPreview::showNoPreview()
383 {
384 //Are we already showing it?
385 if (showingNoPreview)
386 return;
388 //Arbitrary size of svg doc -- rather 'portrait' shaped
389 gint previewWidth = 300;
390 gint previewHeight = 600;
392 //Our template. Modify to taste
393 gchar const *xformat =
394 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
395 "<svg\n"
396 "xmlns=\"http://www.w3.org/2000/svg\"\n"
397 "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
398 "width=\"%d\" height=\"%d\">\n" //# VALUES HERE
399 "<g transform=\"translate(-190,24.27184)\" style=\"opacity:0.12\">\n"
400 "<path\n"
401 "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
402 "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
403 "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
404 "id=\"whiteSpace\" />\n"
405 "<path\n"
406 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
407 "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
408 "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
409 "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
410 "id=\"droplet01\" />\n"
411 "<path\n"
412 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
413 "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
414 "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
415 "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
416 "287.18046 343.1206 286.46194 340.42914 z \"\n"
417 "id=\"droplet02\" />\n"
418 "<path\n"
419 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
420 "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
421 "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
422 "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
423 "id=\"droplet03\" />\n"
424 "<path\n"
425 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
426 "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
427 "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
428 "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
429 "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
430 "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
431 "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
432 "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
433 "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
434 "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
435 "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
436 "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
437 "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
438 "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
439 "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
440 "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
441 "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
442 "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
443 "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
444 "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
445 "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
446 "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
447 "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
448 "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
449 "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
450 "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
451 "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
452 "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
453 "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
454 "id=\"mountainDroplet\" />\n"
455 "</g> <g transform=\"translate(-20,0)\">\n"
456 "<text xml:space=\"preserve\"\n"
457 "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
458 "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
459 "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
460 "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
461 "x=\"190\" y=\"240\">%s</text></g>\n" //# VALUE HERE
462 "</svg>\n\n";
464 //Fill in the template
465 gchar *xmlBuffer = g_strdup_printf(xformat,
466 previewWidth, previewHeight, _("No preview"));
468 //g_message("%s\n", xmlBuffer);
470 //now show it!
471 setFromMem(xmlBuffer);
472 g_free(xmlBuffer);
473 showingNoPreview = true;
475 }
478 /**
479 * Inform the user that the svg file is too large to be displayed.
480 * This does not check for sizes of embedded images (yet)
481 */
482 void SVGPreview::showTooLarge(long fileLength)
483 {
485 //Arbitrary size of svg doc -- rather 'portrait' shaped
486 gint previewWidth = 300;
487 gint previewHeight = 600;
489 //Our template. Modify to taste
490 gchar const *xformat =
491 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
492 "<svg\n"
493 "xmlns=\"http://www.w3.org/2000/svg\"\n"
494 "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
495 "width=\"%d\" height=\"%d\">\n" //# VALUES HERE
496 "<g transform=\"translate(-170,24.27184)\" style=\"opacity:0.12\">\n"
497 "<path\n"
498 "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
499 "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
500 "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
501 "id=\"whiteSpace\" />\n"
502 "<path\n"
503 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
504 "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
505 "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
506 "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
507 "id=\"droplet01\" />\n"
508 "<path\n"
509 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
510 "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
511 "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
512 "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
513 "287.18046 343.1206 286.46194 340.42914 z \"\n"
514 "id=\"droplet02\" />\n"
515 "<path\n"
516 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
517 "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
518 "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
519 "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
520 "id=\"droplet03\" />\n"
521 "<path\n"
522 "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
523 "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
524 "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
525 "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
526 "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
527 "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
528 "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
529 "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
530 "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
531 "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
532 "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
533 "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
534 "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
535 "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
536 "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
537 "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
538 "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
539 "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
540 "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
541 "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
542 "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
543 "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
544 "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
545 "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
546 "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
547 "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
548 "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
549 "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
550 "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
551 "id=\"mountainDroplet\" />\n"
552 "</g>\n"
553 "<text xml:space=\"preserve\"\n"
554 "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
555 "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
556 "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
557 "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
558 "x=\"170\" y=\"215\">%5.1f MB</text>\n" //# VALUE HERE
559 "<text xml:space=\"preserve\"\n"
560 "style=\"font-size:24.000000;font-style:normal;font-variant:normal;font-weight:bold;"
561 "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
562 "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
563 "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
564 "x=\"180\" y=\"245\">%s</text>\n" //# VALUE HERE
565 "</svg>\n\n";
567 //Fill in the template
568 double floatFileLength = ((double)fileLength) / 1048576.0;
569 //printf("%ld %f\n", fileLength, floatFileLength);
570 gchar *xmlBuffer = g_strdup_printf(xformat,
571 previewWidth, previewHeight, floatFileLength,
572 _("too large for preview"));
574 //g_message("%s\n", xmlBuffer);
576 //now show it!
577 setFromMem(xmlBuffer);
578 g_free(xmlBuffer);
580 }
583 /**
584 * Return true if the string ends with the given suffix
585 */
586 static bool
587 hasSuffix(Glib::ustring &str, Glib::ustring &ext)
588 {
589 int strLen = str.length();
590 int extLen = ext.length();
591 if (extLen > strLen)
592 return false;
593 int strpos = strLen-1;
594 for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
595 {
596 Glib::ustring::value_type ch = str[strpos];
597 if (ch != ext[extpos])
598 {
599 if ( ((ch & 0xff80) != 0) ||
600 static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
601 {
602 return false;
603 }
604 }
605 }
606 return true;
607 }
610 /**
611 * Return true if the image is loadable by Gdk, else false
612 */
613 static bool
614 isValidImageFile(Glib::ustring &fileName)
615 {
616 std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
617 for (unsigned int i=0; i<formats.size(); i++)
618 {
619 Gdk::PixbufFormat format = formats[i];
620 std::vector<Glib::ustring>extensions = format.get_extensions();
621 for (unsigned int j=0; j<extensions.size(); j++)
622 {
623 Glib::ustring ext = extensions[j];
624 if (hasSuffix(fileName, ext))
625 return true;
626 }
627 }
628 return false;
629 }
631 bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
632 {
634 if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS))
635 return false;
637 //g_message("fname:%s", fileName.c_str());
639 if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
640 showNoPreview();
641 return false;
642 }
644 if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR))
645 {
646 Glib::ustring fileNameUtf8 = Glib::filename_to_utf8(fileName);
647 gchar *fName = (gchar *)fileNameUtf8.c_str();
648 struct stat info;
649 if (g_stat(fName, &info))
650 {
651 g_warning("SVGPreview::set() : %s : %s",
652 fName, strerror(errno));
653 return FALSE;
654 }
655 long fileLen = info.st_size;
656 if (fileLen > 0x150000L)
657 {
658 showingNoPreview = false;
659 showTooLarge(fileLen);
660 return FALSE;
661 }
662 }
664 Glib::ustring svg = ".svg";
665 Glib::ustring svgz = ".svgz";
667 if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
668 (hasSuffix(fileName, svg) || hasSuffix(fileName, svgz) )
669 ) {
670 bool retval = setFileName(fileName);
671 showingNoPreview = false;
672 return retval;
673 } else if (isValidImageFile(fileName)) {
674 showImage(fileName);
675 showingNoPreview = false;
676 return true;
677 } else {
678 showNoPreview();
679 return false;
680 }
681 }
684 SVGPreview::SVGPreview()
685 {
686 if (!INKSCAPE)
687 inkscape_application_init("",false);
688 document = NULL;
689 viewerGtk = NULL;
690 set_size_request(150,150);
691 showingNoPreview = false;
692 }
694 SVGPreview::~SVGPreview()
695 {
697 }
703 /*#########################################################################
704 ### F I L E D I A L O G B A S E C L A S S
705 #########################################################################*/
707 /**
708 * This class is the base implementation for the others. This
709 * reduces redundancies and bugs.
710 */
711 class FileDialogBase : public Gtk::FileChooserDialog
712 {
713 public:
715 /**
716 *
717 */
718 FileDialogBase(const Glib::ustring &title, FileDialogType type, gchar const* preferenceBase) :
719 Gtk::FileChooserDialog(title),
720 preferenceBase(preferenceBase ? preferenceBase : "unknown"),
721 dialogType(type)
722 {
723 internalSetup();
724 }
726 /**
727 *
728 */
729 FileDialogBase(const Glib::ustring &title,
730 Gtk::FileChooserAction dialogType, FileDialogType type, gchar const* preferenceBase) :
731 Gtk::FileChooserDialog(title, dialogType),
732 preferenceBase(preferenceBase ? preferenceBase : "unknown"),
733 dialogType(type)
734 {
735 internalSetup();
736 }
738 /**
739 *
740 */
741 virtual ~FileDialogBase()
742 {}
744 protected:
745 void cleanup( bool showConfirmed );
747 Glib::ustring preferenceBase;
748 /**
749 * What type of 'open' are we? (open, import, place, etc)
750 */
751 FileDialogType dialogType;
753 /**
754 * Our svg preview widget
755 */
756 SVGPreview svgPreview;
758 //# Child widgets
759 Gtk::CheckButton previewCheckbox;
761 private:
762 void internalSetup();
764 /**
765 * Callback for user changing preview checkbox
766 */
767 void _previewEnabledCB();
769 /**
770 * Callback for seeing if the preview needs to be drawn
771 */
772 void _updatePreviewCallback();
773 };
776 void FileDialogBase::internalSetup()
777 {
778 bool enablePreview =
779 (bool)prefs_get_int_attribute( preferenceBase.c_str(),
780 "enable_preview", 1 );
782 previewCheckbox.set_label( Glib::ustring(_("Enable Preview")) );
783 previewCheckbox.set_active( enablePreview );
785 previewCheckbox.signal_toggled().connect(
786 sigc::mem_fun(*this, &FileDialogBase::_previewEnabledCB) );
788 //Catch selection-changed events, so we can adjust the text widget
789 signal_update_preview().connect(
790 sigc::mem_fun(*this, &FileDialogBase::_updatePreviewCallback) );
792 //###### Add a preview widget
793 set_preview_widget(svgPreview);
794 set_preview_widget_active( enablePreview );
795 set_use_preview_label (false);
797 }
800 void FileDialogBase::cleanup( bool showConfirmed )
801 {
802 if ( showConfirmed )
803 prefs_set_int_attribute( preferenceBase.c_str(),
804 "enable_preview", previewCheckbox.get_active() );
805 }
808 void FileDialogBase::_previewEnabledCB()
809 {
810 bool enabled = previewCheckbox.get_active();
811 set_preview_widget_active(enabled);
812 if ( enabled ) {
813 _updatePreviewCallback();
814 }
815 }
819 /**
820 * Callback for checking if the preview needs to be redrawn
821 */
822 void FileDialogBase::_updatePreviewCallback()
823 {
824 Glib::ustring fileName = get_preview_filename();
826 #ifdef WITH_GNOME_VFS
827 if ( fileName.empty() && gnome_vfs_initialized() ) {
828 fileName = get_preview_uri();
829 }
830 #endif
832 if (fileName.empty()) {
833 return;
834 }
836 svgPreview.set(fileName, dialogType);
837 }
840 /*#########################################################################
841 ### F I L E O P E N
842 #########################################################################*/
844 /**
845 * Our implementation class for the FileOpenDialog interface..
846 */
847 class FileOpenDialogImpl : public FileOpenDialog, public FileDialogBase
848 {
849 public:
851 FileOpenDialogImpl(const Glib::ustring &dir,
852 FileDialogType fileTypes,
853 const Glib::ustring &title);
855 virtual ~FileOpenDialogImpl();
857 bool show();
859 Inkscape::Extension::Extension *getSelectionType();
861 Glib::ustring getFilename();
863 std::vector<Glib::ustring> getFilenames ();
865 private:
867 /**
868 * Create a filter menu for this type of dialog
869 */
870 void createFilterMenu();
872 /**
873 * Filter name->extension lookup
874 */
875 std::map<Glib::ustring, Inkscape::Extension::Extension *> extensionMap;
877 /**
878 * The extension to use to write this file
879 */
880 Inkscape::Extension::Extension *extension;
882 /**
883 * Filename that was given
884 */
885 Glib::ustring myFilename;
887 };
895 void FileOpenDialogImpl::createFilterMenu()
896 {
897 Gtk::FileFilter allInkscapeFilter;
898 allInkscapeFilter.set_name(_("All Inkscape Files"));
899 extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL;
900 add_filter(allInkscapeFilter);
902 Gtk::FileFilter allFilter;
903 allFilter.set_name(_("All Files"));
904 extensionMap[Glib::ustring(_("All Files"))]=NULL;
905 allFilter.add_pattern("*");
906 add_filter(allFilter);
908 Gtk::FileFilter allImageFilter;
909 allImageFilter.set_name(_("All Images"));
910 extensionMap[Glib::ustring(_("All Images"))]=NULL;
911 add_filter(allImageFilter);
913 //patterns added dynamically below
914 Inkscape::Extension::DB::InputList extension_list;
915 Inkscape::Extension::db.get_input_list(extension_list);
917 for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
918 current_item != extension_list.end(); current_item++)
919 {
920 Inkscape::Extension::Input * imod = *current_item;
922 // FIXME: would be nice to grey them out instead of not listing them
923 if (imod->deactivated()) continue;
925 Glib::ustring upattern("*");
926 Glib::ustring extension = imod->get_extension();
927 fileDialogExtensionToPattern(upattern, extension);
929 Gtk::FileFilter filter;
930 Glib::ustring uname(_(imod->get_filetypename()));
931 filter.set_name(uname);
932 filter.add_pattern(upattern);
933 add_filter(filter);
934 extensionMap[uname] = imod;
936 //g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str());
937 allInkscapeFilter.add_pattern(upattern);
938 if ( strncmp("image", imod->get_mimetype(), 5)==0 )
939 allImageFilter.add_pattern(upattern);
940 }
942 return;
943 }
947 /**
948 * Constructor. Not called directly. Use the factory.
949 */
950 FileOpenDialogImpl::FileOpenDialogImpl(const Glib::ustring &dir,
951 FileDialogType fileTypes,
952 const Glib::ustring &title) :
953 FileDialogBase(title, fileTypes, "dialogs.open")
954 {
957 /* One file at a time */
958 /* And also Multiple Files */
959 set_select_multiple(true);
961 #ifdef WITH_GNOME_VFS
962 if (gnome_vfs_initialized()) {
963 set_local_only(false);
964 }
965 #endif
967 /* Initalize to Autodetect */
968 extension = NULL;
969 /* No filename to start out with */
970 myFilename = "";
972 /* Set our dialog type (open, import, etc...)*/
973 dialogType = fileTypes;
976 /* Set the pwd and/or the filename */
977 if (dir.size() > 0)
978 {
979 Glib::ustring udir(dir);
980 Glib::ustring::size_type len = udir.length();
981 // leaving a trailing backslash on the directory name leads to the infamous
982 // double-directory bug on win32
983 if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
984 set_current_folder(udir.c_str());
985 }
988 set_extra_widget( previewCheckbox );
991 //###### Add the file types menu
992 createFilterMenu();
995 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
996 set_default(*add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK));
997 }
1003 /**
1004 * Public factory. Called by file.cpp, among others.
1005 */
1006 FileOpenDialog *FileOpenDialog::create(const Glib::ustring &path,
1007 FileDialogType fileTypes,
1008 const Glib::ustring &title)
1009 {
1010 FileOpenDialog *dialog = new FileOpenDialogImpl(path, fileTypes, title);
1011 return dialog;
1012 }
1017 /**
1018 * Destructor
1019 */
1020 FileOpenDialogImpl::~FileOpenDialogImpl()
1021 {
1023 }
1026 /**
1027 * Show this dialog modally. Return true if user hits [OK]
1028 */
1029 bool
1030 FileOpenDialogImpl::show()
1031 {
1032 Glib::ustring s = Glib::filename_to_utf8 (get_current_folder());
1033 if (s.length() == 0)
1034 s = getcwd (NULL, 0);
1035 set_current_folder(Glib::filename_from_utf8(s)); //hack to force initial dir listing
1036 set_modal (TRUE); //Window
1037 sp_transientize((GtkWidget *)gobj()); //Make transient
1038 gint b = run(); //Dialog
1039 svgPreview.showNoPreview();
1040 hide();
1042 if (b == Gtk::RESPONSE_OK)
1043 {
1044 //This is a hack, to avoid the warning messages that
1045 //Gtk::FileChooser::get_filter() returns
1046 //should be: Gtk::FileFilter *filter = get_filter();
1047 GtkFileChooser *gtkFileChooser = Gtk::FileChooser::gobj();
1048 GtkFileFilter *filter = gtk_file_chooser_get_filter(gtkFileChooser);
1049 if (filter)
1050 {
1051 //Get which extension was chosen, if any
1052 extension = extensionMap[gtk_file_filter_get_name(filter)];
1053 }
1054 myFilename = get_filename();
1055 #ifdef WITH_GNOME_VFS
1056 if (myFilename.empty() && gnome_vfs_initialized())
1057 myFilename = get_uri();
1058 #endif
1059 cleanup( true );
1060 return TRUE;
1061 }
1062 else
1063 {
1064 cleanup( false );
1065 return FALSE;
1066 }
1067 }
1072 /**
1073 * Get the file extension type that was selected by the user. Valid after an [OK]
1074 */
1075 Inkscape::Extension::Extension *
1076 FileOpenDialogImpl::getSelectionType()
1077 {
1078 return extension;
1079 }
1082 /**
1083 * Get the file name chosen by the user. Valid after an [OK]
1084 */
1085 Glib::ustring
1086 FileOpenDialogImpl::getFilename (void)
1087 {
1088 return g_strdup(myFilename.c_str());
1089 }
1092 /**
1093 * To Get Multiple filenames selected at-once.
1094 */
1095 std::vector<Glib::ustring>FileOpenDialogImpl::getFilenames()
1096 {
1097 std::vector<Glib::ustring> result = get_filenames();
1098 #ifdef WITH_GNOME_VFS
1099 if (result.empty() && gnome_vfs_initialized())
1100 result = get_uris();
1101 #endif
1102 return result;
1103 }
1110 //########################################################################
1111 //# F I L E S A V E
1112 //########################################################################
1114 class FileType
1115 {
1116 public:
1117 FileType() {}
1118 ~FileType() {}
1119 Glib::ustring name;
1120 Glib::ustring pattern;
1121 Inkscape::Extension::Extension *extension;
1122 };
1124 /**
1125 * Our implementation of the FileSaveDialog interface.
1126 */
1127 class FileSaveDialogImpl : public FileSaveDialog, public FileDialogBase
1128 {
1130 public:
1131 FileSaveDialogImpl(const Glib::ustring &dir,
1132 FileDialogType fileTypes,
1133 const Glib::ustring &title,
1134 const Glib::ustring &default_key);
1136 virtual ~FileSaveDialogImpl();
1138 bool show();
1140 Inkscape::Extension::Extension *getSelectionType();
1141 virtual void setSelectionType( Inkscape::Extension::Extension * key );
1143 Glib::ustring getFilename();
1145 void change_title(const Glib::ustring& title);
1146 void change_path(const Glib::ustring& path);
1147 void updateNameAndExtension();
1149 private:
1151 /**
1152 * Fix to allow the user to type the file name
1153 */
1154 Gtk::Entry *fileNameEntry;
1157 /**
1158 * Allow the specification of the output file type
1159 */
1160 Gtk::ComboBoxText fileTypeComboBox;
1163 /**
1164 * Data mirror of the combo box
1165 */
1166 std::vector<FileType> fileTypes;
1168 //# Child widgets
1169 Gtk::HBox childBox;
1170 Gtk::VBox checksBox;
1172 Gtk::CheckButton fileTypeCheckbox;
1174 /**
1175 * Callback for user input into fileNameEntry
1176 */
1177 void fileTypeChangedCallback();
1179 /**
1180 * Create a filter menu for this type of dialog
1181 */
1182 void createFileTypeMenu();
1185 /**
1186 * The extension to use to write this file
1187 */
1188 Inkscape::Extension::Extension *extension;
1190 /**
1191 * Callback for user input into fileNameEntry
1192 */
1193 void fileNameEntryChangedCallback();
1195 /**
1196 * Filename that was given
1197 */
1198 Glib::ustring myFilename;
1200 /**
1201 * List of known file extensions.
1202 */
1203 std::set<Glib::ustring> knownExtensions;
1204 };
1209 /**
1210 * Callback for fileNameEntry widget
1211 */
1212 void FileSaveDialogImpl::fileNameEntryChangedCallback()
1213 {
1214 if (!fileNameEntry)
1215 return;
1217 Glib::ustring fileName = fileNameEntry->get_text();
1218 if (!Glib::get_charset()) //If we are not utf8
1219 fileName = Glib::filename_to_utf8(fileName);
1221 //g_message("User hit return. Text is '%s'\n", fileName.c_str());
1223 if (!Glib::path_is_absolute(fileName)) {
1224 //try appending to the current path
1225 // not this way: fileName = get_current_folder() + "/" + fileName;
1226 std::vector<Glib::ustring> pathSegments;
1227 pathSegments.push_back( get_current_folder() );
1228 pathSegments.push_back( fileName );
1229 fileName = Glib::build_filename(pathSegments);
1230 }
1232 //g_message("path:'%s'\n", fileName.c_str());
1234 if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1235 set_current_folder(fileName);
1236 } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1237 //dialog with either (1) select a regular file or (2) cd to dir
1238 //simulate an 'OK'
1239 set_filename(fileName);
1240 response(Gtk::RESPONSE_OK);
1241 }
1242 }
1246 /**
1247 * Callback for fileNameEntry widget
1248 */
1249 void FileSaveDialogImpl::fileTypeChangedCallback()
1250 {
1251 int sel = fileTypeComboBox.get_active_row_number();
1252 if (sel<0 || sel >= (int)fileTypes.size())
1253 return;
1254 FileType type = fileTypes[sel];
1255 //g_message("selected: %s\n", type.name.c_str());
1257 extension = type.extension;
1258 Gtk::FileFilter filter;
1259 filter.add_pattern(type.pattern);
1260 set_filter(filter);
1262 updateNameAndExtension();
1263 }
1267 void FileSaveDialogImpl::createFileTypeMenu()
1268 {
1269 Inkscape::Extension::DB::OutputList extension_list;
1270 Inkscape::Extension::db.get_output_list(extension_list);
1271 knownExtensions.clear();
1273 for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1274 current_item != extension_list.end(); current_item++)
1275 {
1276 Inkscape::Extension::Output * omod = *current_item;
1278 // FIXME: would be nice to grey them out instead of not listing them
1279 if (omod->deactivated()) continue;
1281 FileType type;
1282 type.name = (_(omod->get_filetypename()));
1283 type.pattern = "*";
1284 Glib::ustring extension = omod->get_extension();
1285 knownExtensions.insert( extension.casefold() );
1286 fileDialogExtensionToPattern (type.pattern, extension);
1287 type.extension= omod;
1288 fileTypeComboBox.append_text(type.name);
1289 fileTypes.push_back(type);
1290 }
1292 //#Let user choose
1293 FileType guessType;
1294 guessType.name = _("Guess from extension");
1295 guessType.pattern = "*";
1296 guessType.extension = NULL;
1297 fileTypeComboBox.append_text(guessType.name);
1298 fileTypes.push_back(guessType);
1301 fileTypeComboBox.set_active(0);
1302 fileTypeChangedCallback(); //call at least once to set the filter
1303 }
1307 /**
1308 * Constructor
1309 */
1310 FileSaveDialogImpl::FileSaveDialogImpl(const Glib::ustring &dir,
1311 FileDialogType fileTypes,
1312 const Glib::ustring &title,
1313 const Glib::ustring &default_key) :
1314 FileDialogBase(title, Gtk::FILE_CHOOSER_ACTION_SAVE, fileTypes, "dialogs.save_as")
1315 {
1316 /* One file at a time */
1317 set_select_multiple(false);
1319 #ifdef WITH_GNOME_VFS
1320 if (gnome_vfs_initialized()) {
1321 set_local_only(false);
1322 }
1323 #endif
1325 /* Initalize to Autodetect */
1326 extension = NULL;
1327 /* No filename to start out with */
1328 myFilename = "";
1330 /* Set our dialog type (save, export, etc...)*/
1331 dialogType = fileTypes;
1333 /* Set the pwd and/or the filename */
1334 if (dir.size() > 0)
1335 {
1336 Glib::ustring udir(dir);
1337 Glib::ustring::size_type len = udir.length();
1338 // leaving a trailing backslash on the directory name leads to the infamous
1339 // double-directory bug on win32
1340 if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
1341 myFilename = udir;
1342 }
1344 //###### Add the file types menu
1345 //createFilterMenu();
1347 //###### Do we want the .xxx extension automatically added?
1348 fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
1349 fileTypeCheckbox.set_active( (bool)prefs_get_int_attribute("dialogs.save_as",
1350 "append_extension", 1) );
1352 createFileTypeMenu();
1353 fileTypeComboBox.set_size_request(200,40);
1354 fileTypeComboBox.signal_changed().connect(
1355 sigc::mem_fun(*this, &FileSaveDialogImpl::fileTypeChangedCallback) );
1358 childBox.pack_start( checksBox );
1359 childBox.pack_end( fileTypeComboBox );
1360 checksBox.pack_start( fileTypeCheckbox );
1361 checksBox.pack_start( previewCheckbox );
1363 set_extra_widget( childBox );
1365 //Let's do some customization
1366 fileNameEntry = NULL;
1367 Gtk::Container *cont = get_toplevel();
1368 std::vector<Gtk::Entry *> entries;
1369 findEntryWidgets(cont, entries);
1370 //g_message("Found %d entry widgets\n", entries.size());
1371 if (entries.size() >=1 )
1372 {
1373 //Catch when user hits [return] on the text field
1374 fileNameEntry = entries[0];
1375 fileNameEntry->signal_activate().connect(
1376 sigc::mem_fun(*this, &FileSaveDialogImpl::fileNameEntryChangedCallback) );
1377 }
1379 //Let's do more customization
1380 std::vector<Gtk::Expander *> expanders;
1381 findExpanderWidgets(cont, expanders);
1382 //g_message("Found %d expander widgets\n", expanders.size());
1383 if (expanders.size() >=1 )
1384 {
1385 //Always show the file list
1386 Gtk::Expander *expander = expanders[0];
1387 expander->set_expanded(true);
1388 }
1391 //if (extension == NULL)
1392 // checkbox.set_sensitive(FALSE);
1394 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1395 set_default(*add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK));
1397 show_all_children();
1398 }
1402 /**
1403 * Public factory method. Used in file.cpp
1404 */
1405 FileSaveDialog *FileSaveDialog::create(const Glib::ustring &path,
1406 FileDialogType fileTypes,
1407 const Glib::ustring &title,
1408 const Glib::ustring &default_key)
1409 {
1410 FileSaveDialog *dialog = new FileSaveDialogImpl(path, fileTypes, title, default_key);
1411 return dialog;
1412 }
1418 /**
1419 * Destructor
1420 */
1421 FileSaveDialogImpl::~FileSaveDialogImpl()
1422 {
1423 }
1427 /**
1428 * Show this dialog modally. Return true if user hits [OK]
1429 */
1430 bool
1431 FileSaveDialogImpl::show()
1432 {
1433 change_path(myFilename);
1434 set_modal (TRUE); //Window
1435 sp_transientize((GtkWidget *)gobj()); //Make transient
1436 gint b = run(); //Dialog
1437 svgPreview.showNoPreview();
1438 hide();
1440 if (b == Gtk::RESPONSE_OK)
1441 {
1442 updateNameAndExtension();
1444 // Store changes of the "Append filename automatically" checkbox back to preferences.
1445 prefs_set_int_attribute("dialogs.save_as", "append_extension", fileTypeCheckbox.get_active());
1447 // Store the last used save-as filetype to preferences.
1448 prefs_set_string_attribute("dialogs.save_as", "default",
1449 ( extension != NULL ? extension->get_id() : "" ));
1451 cleanup( true );
1453 return TRUE;
1454 }
1455 else
1456 {
1457 cleanup( false );
1459 return FALSE;
1460 }
1461 }
1464 /**
1465 * Get the file extension type that was selected by the user. Valid after an [OK]
1466 */
1467 Inkscape::Extension::Extension *
1468 FileSaveDialogImpl::getSelectionType()
1469 {
1470 return extension;
1471 }
1473 void FileSaveDialogImpl::setSelectionType( Inkscape::Extension::Extension * key )
1474 {
1475 // If no pointer to extension is passed in, look up based on filename extension.
1476 if ( !key ) {
1477 // Not quite UTF-8 here.
1478 gchar *filenameLower = g_ascii_strdown(myFilename.c_str(), -1);
1479 for ( int i = 0; !key && (i < (int)fileTypes.size()); i++ ) {
1480 Inkscape::Extension::Output *ext = dynamic_cast<Inkscape::Extension::Output*>(fileTypes[i].extension);
1481 if ( ext && ext->get_extension() ) {
1482 gchar *extensionLower = g_ascii_strdown( ext->get_extension(), -1 );
1483 if ( g_str_has_suffix(filenameLower, extensionLower) ) {
1484 key = fileTypes[i].extension;
1485 }
1486 g_free(extensionLower);
1487 }
1488 }
1489 g_free(filenameLower);
1490 }
1492 // Ensure the proper entry in the combo box is selected.
1493 if ( key ) {
1494 extension = key;
1495 gchar const * extensionID = extension->get_id();
1496 if ( extensionID ) {
1497 for ( int i = 0; i < (int)fileTypes.size(); i++ ) {
1498 Inkscape::Extension::Extension *ext = fileTypes[i].extension;
1499 if ( ext ) {
1500 gchar const * id = ext->get_id();
1501 if ( id && ( strcmp(extensionID, id) == 0) ) {
1502 int oldSel = fileTypeComboBox.get_active_row_number();
1503 if ( i != oldSel ) {
1504 fileTypeComboBox.set_active(i);
1505 }
1506 break;
1507 }
1508 }
1509 }
1510 }
1511 }
1512 }
1515 /**
1516 * Get the file name chosen by the user. Valid after an [OK]
1517 */
1518 Glib::ustring
1519 FileSaveDialogImpl::getFilename()
1520 {
1521 return myFilename;
1522 }
1525 void
1526 FileSaveDialogImpl::change_title(const Glib::ustring& title)
1527 {
1528 this->set_title(title);
1529 }
1531 /**
1532 * Change the default save path location.
1533 */
1534 void
1535 FileSaveDialogImpl::change_path(const Glib::ustring& path)
1536 {
1537 myFilename = path;
1538 if (Glib::file_test(myFilename, Glib::FILE_TEST_IS_DIR)) {
1539 //fprintf(stderr,"set_current_folder(%s)\n",myFilename.c_str());
1540 set_current_folder(myFilename);
1541 } else {
1542 //fprintf(stderr,"set_filename(%s)\n",myFilename.c_str());
1543 if ( Glib::file_test( myFilename, Glib::FILE_TEST_EXISTS ) ) {
1544 set_filename(myFilename);
1545 } else {
1546 std::string dirName = Glib::path_get_dirname( myFilename );
1547 if ( dirName != get_current_folder() ) {
1548 set_current_folder(dirName);
1549 }
1550 }
1551 Glib::ustring basename = Glib::path_get_basename(myFilename);
1552 //fprintf(stderr,"set_current_name(%s)\n",basename.c_str());
1553 try {
1554 set_current_name( Glib::filename_to_utf8(basename) );
1555 } catch ( Glib::ConvertError& e ) {
1556 g_warning( "Error converting save filename to UTF-8." );
1557 // try a fallback.
1558 set_current_name( basename );
1559 }
1560 }
1561 }
1563 void FileSaveDialogImpl::updateNameAndExtension()
1564 {
1565 // Pick up any changes the user has typed in.
1566 Glib::ustring tmp = get_filename();
1567 #ifdef WITH_GNOME_VFS
1568 if ( tmp.empty() && gnome_vfs_initialized() ) {
1569 tmp = get_uri();
1570 }
1571 #endif
1572 if ( !tmp.empty() ) {
1573 myFilename = tmp;
1574 }
1576 Inkscape::Extension::Output* newOut = extension ? dynamic_cast<Inkscape::Extension::Output*>(extension) : 0;
1577 if ( fileTypeCheckbox.get_active() && newOut ) {
1578 try {
1579 bool appendExtension = true;
1580 Glib::ustring utf8Name = Glib::filename_to_utf8( myFilename );
1581 Glib::ustring::size_type pos = utf8Name.rfind('.');
1582 if ( pos != Glib::ustring::npos ) {
1583 Glib::ustring trail = utf8Name.substr( pos );
1584 Glib::ustring foldedTrail = trail.casefold();
1585 if ( (trail == ".")
1586 | (foldedTrail != Glib::ustring( newOut->get_extension() ).casefold()
1587 && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) {
1588 utf8Name = utf8Name.erase( pos );
1589 } else {
1590 appendExtension = false;
1591 }
1592 }
1594 if (appendExtension) {
1595 utf8Name = utf8Name + newOut->get_extension();
1596 myFilename = Glib::filename_from_utf8( utf8Name );
1597 change_path(myFilename);
1598 }
1599 } catch ( Glib::ConvertError& e ) {
1600 // ignore
1601 }
1602 }
1603 }
1607 //########################################################################
1608 //# F I L E E X P O R T
1609 //########################################################################
1612 /**
1613 * Our implementation of the FileExportDialog interface.
1614 */
1615 class FileExportDialogImpl : public FileExportDialog, public FileDialogBase
1616 {
1618 public:
1619 FileExportDialogImpl(const Glib::ustring &dir,
1620 FileDialogType fileTypes,
1621 const Glib::ustring &title,
1622 const Glib::ustring &default_key);
1624 virtual ~FileExportDialogImpl();
1626 bool show();
1628 Inkscape::Extension::Extension *getSelectionType();
1630 Glib::ustring getFilename();
1633 /**
1634 * Return the scope of the export. One of the enumerated types
1635 * in ScopeType
1636 */
1637 ScopeType getScope()
1638 {
1639 if (pageButton.get_active())
1640 return SCOPE_PAGE;
1641 else if (selectionButton.get_active())
1642 return SCOPE_SELECTION;
1643 else if (customButton.get_active())
1644 return SCOPE_CUSTOM;
1645 else
1646 return SCOPE_DOCUMENT;
1648 }
1650 /**
1651 * Return left side of the exported region
1652 */
1653 double getSourceX()
1654 { return sourceX0Spinner.getValue(); }
1656 /**
1657 * Return the top of the exported region
1658 */
1659 double getSourceY()
1660 { return sourceY1Spinner.getValue(); }
1662 /**
1663 * Return the width of the exported region
1664 */
1665 double getSourceWidth()
1666 { return sourceWidthSpinner.getValue(); }
1668 /**
1669 * Return the height of the exported region
1670 */
1671 double getSourceHeight()
1672 { return sourceHeightSpinner.getValue(); }
1674 /**
1675 * Return the units of the coordinates of exported region
1676 */
1677 Glib::ustring getSourceUnits()
1678 { return sourceUnitsSpinner.getUnitAbbr(); }
1680 /**
1681 * Return the width of the destination document
1682 */
1683 double getDestinationWidth()
1684 { return destWidthSpinner.getValue(); }
1686 /**
1687 * Return the height of the destination document
1688 */
1689 double getDestinationHeight()
1690 { return destHeightSpinner.getValue(); }
1692 /**
1693 * Return the height of the exported region
1694 */
1695 Glib::ustring getDestinationUnits()
1696 { return destUnitsSpinner.getUnitAbbr(); }
1698 /**
1699 * Return the destination DPI image resulution, if bitmap
1700 */
1701 double getDestinationDPI()
1702 { return destDPISpinner.getValue(); }
1704 /**
1705 * Return whether we should use Cairo for rendering
1706 */
1707 bool getUseCairo()
1708 { return cairoButton.get_active(); }
1710 /**
1711 * Return whether we should use antialiasing
1712 */
1713 bool getUseAntialias()
1714 { return antiAliasButton.get_active(); }
1716 /**
1717 * Return the background color for exporting
1718 */
1719 unsigned long getBackground()
1720 { return backgroundButton.get_color().get_pixel(); }
1722 private:
1724 /**
1725 * Fix to allow the user to type the file name
1726 */
1727 Gtk::Entry *fileNameEntry;
1729 //##########################################
1730 //# EXTRA WIDGET -- SOURCE SIDE
1731 //##########################################
1733 Gtk::Frame sourceFrame;
1734 Gtk::VBox sourceBox;
1736 Gtk::HBox scopeBox;
1737 Gtk::RadioButtonGroup scopeGroup;
1738 Gtk::RadioButton documentButton;
1739 Gtk::RadioButton pageButton;
1740 Gtk::RadioButton selectionButton;
1741 Gtk::RadioButton customButton;
1743 Gtk::Table sourceTable;
1744 Inkscape::UI::Widget::Scalar sourceX0Spinner;
1745 Inkscape::UI::Widget::Scalar sourceY0Spinner;
1746 Inkscape::UI::Widget::Scalar sourceX1Spinner;
1747 Inkscape::UI::Widget::Scalar sourceY1Spinner;
1748 Inkscape::UI::Widget::Scalar sourceWidthSpinner;
1749 Inkscape::UI::Widget::Scalar sourceHeightSpinner;
1750 Inkscape::UI::Widget::UnitMenu sourceUnitsSpinner;
1753 //##########################################
1754 //# EXTRA WIDGET -- DESTINATION SIDE
1755 //##########################################
1757 Gtk::Frame destFrame;
1758 Gtk::VBox destBox;
1760 Gtk::Table destTable;
1761 Inkscape::UI::Widget::Scalar destWidthSpinner;
1762 Inkscape::UI::Widget::Scalar destHeightSpinner;
1763 Inkscape::UI::Widget::Scalar destDPISpinner;
1764 Inkscape::UI::Widget::UnitMenu destUnitsSpinner;
1766 Gtk::HBox otherOptionBox;
1767 Gtk::CheckButton cairoButton;
1768 Gtk::CheckButton antiAliasButton;
1769 Gtk::ColorButton backgroundButton;
1772 /**
1773 * 'Extra' widget that holds two boxes above
1774 */
1775 Gtk::HBox exportOptionsBox;
1778 //# Child widgets
1779 Gtk::CheckButton fileTypeCheckbox;
1781 /**
1782 * Allow the specification of the output file type
1783 */
1784 Gtk::ComboBoxText fileTypeComboBox;
1787 /**
1788 * Data mirror of the combo box
1789 */
1790 std::vector<FileType> fileTypes;
1794 /**
1795 * Callback for user input into fileNameEntry
1796 */
1797 void fileTypeChangedCallback();
1799 /**
1800 * Create a filter menu for this type of dialog
1801 */
1802 void createFileTypeMenu();
1805 bool append_extension;
1807 /**
1808 * The extension to use to write this file
1809 */
1810 Inkscape::Extension::Extension *extension;
1812 /**
1813 * Callback for user input into fileNameEntry
1814 */
1815 void fileNameEntryChangedCallback();
1817 /**
1818 * Filename that was given
1819 */
1820 Glib::ustring myFilename;
1821 };
1828 /**
1829 * Callback for fileNameEntry widget
1830 */
1831 void FileExportDialogImpl::fileNameEntryChangedCallback()
1832 {
1833 if (!fileNameEntry)
1834 return;
1836 Glib::ustring fileName = fileNameEntry->get_text();
1837 if (!Glib::get_charset()) //If we are not utf8
1838 fileName = Glib::filename_to_utf8(fileName);
1840 //g_message("User hit return. Text is '%s'\n", fileName.c_str());
1842 if (!Glib::path_is_absolute(fileName)) {
1843 //try appending to the current path
1844 // not this way: fileName = get_current_folder() + "/" + fileName;
1845 std::vector<Glib::ustring> pathSegments;
1846 pathSegments.push_back( get_current_folder() );
1847 pathSegments.push_back( fileName );
1848 fileName = Glib::build_filename(pathSegments);
1849 }
1851 //g_message("path:'%s'\n", fileName.c_str());
1853 if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1854 set_current_folder(fileName);
1855 } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1856 //dialog with either (1) select a regular file or (2) cd to dir
1857 //simulate an 'OK'
1858 set_filename(fileName);
1859 response(Gtk::RESPONSE_OK);
1860 }
1861 }
1865 /**
1866 * Callback for fileNameEntry widget
1867 */
1868 void FileExportDialogImpl::fileTypeChangedCallback()
1869 {
1870 int sel = fileTypeComboBox.get_active_row_number();
1871 if (sel<0 || sel >= (int)fileTypes.size())
1872 return;
1873 FileType type = fileTypes[sel];
1874 //g_message("selected: %s\n", type.name.c_str());
1875 Gtk::FileFilter filter;
1876 filter.add_pattern(type.pattern);
1877 set_filter(filter);
1878 }
1882 void FileExportDialogImpl::createFileTypeMenu()
1883 {
1884 Inkscape::Extension::DB::OutputList extension_list;
1885 Inkscape::Extension::db.get_output_list(extension_list);
1887 for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1888 current_item != extension_list.end(); current_item++)
1889 {
1890 Inkscape::Extension::Output * omod = *current_item;
1892 // FIXME: would be nice to grey them out instead of not listing them
1893 if (omod->deactivated()) continue;
1895 FileType type;
1896 type.name = (_(omod->get_filetypename()));
1897 type.pattern = "*";
1898 Glib::ustring extension = omod->get_extension();
1899 fileDialogExtensionToPattern (type.pattern, extension);
1900 type.extension= omod;
1901 fileTypeComboBox.append_text(type.name);
1902 fileTypes.push_back(type);
1903 }
1905 //#Let user choose
1906 FileType guessType;
1907 guessType.name = _("Guess from extension");
1908 guessType.pattern = "*";
1909 guessType.extension = NULL;
1910 fileTypeComboBox.append_text(guessType.name);
1911 fileTypes.push_back(guessType);
1914 fileTypeComboBox.set_active(0);
1915 fileTypeChangedCallback(); //call at least once to set the filter
1916 }
1919 /**
1920 * Constructor
1921 */
1922 FileExportDialogImpl::FileExportDialogImpl(const Glib::ustring &dir,
1923 FileDialogType fileTypes,
1924 const Glib::ustring &title,
1925 const Glib::ustring &default_key) :
1926 FileDialogBase(title, Gtk::FILE_CHOOSER_ACTION_SAVE, fileTypes, "dialogs.export"),
1927 sourceX0Spinner("X0", _("Left edge of source")),
1928 sourceY0Spinner("Y0", _("Top edge of source")),
1929 sourceX1Spinner("X1", _("Right edge of source")),
1930 sourceY1Spinner("Y1", _("Bottom edge of source")),
1931 sourceWidthSpinner("Width", _("Source width")),
1932 sourceHeightSpinner("Height", _("Source height")),
1933 destWidthSpinner("Width", _("Destination width")),
1934 destHeightSpinner("Height", _("Destination height")),
1935 destDPISpinner("DPI", _("Resolution (dots per inch)"))
1936 {
1937 append_extension = (bool)prefs_get_int_attribute("dialogs.save_as", "append_extension", 1);
1939 /* One file at a time */
1940 set_select_multiple(false);
1942 #ifdef WITH_GNOME_VFS
1943 if (gnome_vfs_initialized()) {
1944 set_local_only(false);
1945 }
1946 #endif
1948 /* Initalize to Autodetect */
1949 extension = NULL;
1950 /* No filename to start out with */
1951 myFilename = "";
1953 /* Set our dialog type (save, export, etc...)*/
1954 dialogType = fileTypes;
1956 /* Set the pwd and/or the filename */
1957 if (dir.size()>0)
1958 {
1959 Glib::ustring udir(dir);
1960 Glib::ustring::size_type len = udir.length();
1961 // leaving a trailing backslash on the directory name leads to the infamous
1962 // double-directory bug on win32
1963 if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
1964 set_current_folder(udir.c_str());
1965 }
1967 //#########################################
1968 //## EXTRA WIDGET -- SOURCE SIDE
1969 //#########################################
1971 //##### Export options buttons/spinners, etc
1972 documentButton.set_label(_("Document"));
1973 scopeBox.pack_start(documentButton);
1974 scopeGroup = documentButton.get_group();
1976 pageButton.set_label(_("Page"));
1977 pageButton.set_group(scopeGroup);
1978 scopeBox.pack_start(pageButton);
1980 selectionButton.set_label(_("Selection"));
1981 selectionButton.set_group(scopeGroup);
1982 scopeBox.pack_start(selectionButton);
1984 customButton.set_label(_("Custom"));
1985 customButton.set_group(scopeGroup);
1986 scopeBox.pack_start(customButton);
1988 sourceBox.pack_start(scopeBox);
1992 //dimension buttons
1993 sourceTable.resize(3,3);
1994 sourceTable.attach(sourceX0Spinner, 0,1,0,1);
1995 sourceTable.attach(sourceY0Spinner, 1,2,0,1);
1996 sourceUnitsSpinner.setUnitType(UNIT_TYPE_LINEAR);
1997 sourceTable.attach(sourceUnitsSpinner, 2,3,0,1);
1998 sourceTable.attach(sourceX1Spinner, 0,1,1,2);
1999 sourceTable.attach(sourceY1Spinner, 1,2,1,2);
2000 sourceTable.attach(sourceWidthSpinner, 0,1,2,3);
2001 sourceTable.attach(sourceHeightSpinner, 1,2,2,3);
2003 sourceBox.pack_start(sourceTable);
2004 sourceFrame.set_label(_("Source"));
2005 sourceFrame.add(sourceBox);
2006 exportOptionsBox.pack_start(sourceFrame);
2009 //#########################################
2010 //## EXTRA WIDGET -- SOURCE SIDE
2011 //#########################################
2014 destTable.resize(3,3);
2015 destTable.attach(destWidthSpinner, 0,1,0,1);
2016 destTable.attach(destHeightSpinner, 1,2,0,1);
2017 destUnitsSpinner.setUnitType(UNIT_TYPE_LINEAR);
2018 destTable.attach(destUnitsSpinner, 2,3,0,1);
2019 destTable.attach(destDPISpinner, 0,1,1,2);
2021 destBox.pack_start(destTable);
2024 cairoButton.set_label(_("Cairo"));
2025 otherOptionBox.pack_start(cairoButton);
2027 antiAliasButton.set_label(_("Antialias"));
2028 otherOptionBox.pack_start(antiAliasButton);
2030 backgroundButton.set_label(_("Background"));
2031 otherOptionBox.pack_start(backgroundButton);
2033 destBox.pack_start(otherOptionBox);
2039 //###### File options
2040 //###### Do we want the .xxx extension automatically added?
2041 fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
2042 fileTypeCheckbox.set_active(append_extension);
2043 destBox.pack_start(fileTypeCheckbox);
2045 //###### File type menu
2046 createFileTypeMenu();
2047 fileTypeComboBox.set_size_request(200,40);
2048 fileTypeComboBox.signal_changed().connect(
2049 sigc::mem_fun(*this, &FileExportDialogImpl::fileTypeChangedCallback) );
2051 destBox.pack_start(fileTypeComboBox);
2053 destFrame.set_label(_("Destination"));
2054 destFrame.add(destBox);
2055 exportOptionsBox.pack_start(destFrame);
2057 //##### Put the two boxes and their parent onto the dialog
2058 exportOptionsBox.pack_start(sourceFrame);
2059 exportOptionsBox.pack_start(destFrame);
2061 set_extra_widget(exportOptionsBox);
2066 //Let's do some customization
2067 fileNameEntry = NULL;
2068 Gtk::Container *cont = get_toplevel();
2069 std::vector<Gtk::Entry *> entries;
2070 findEntryWidgets(cont, entries);
2071 //g_message("Found %d entry widgets\n", entries.size());
2072 if (entries.size() >=1 )
2073 {
2074 //Catch when user hits [return] on the text field
2075 fileNameEntry = entries[0];
2076 fileNameEntry->signal_activate().connect(
2077 sigc::mem_fun(*this, &FileExportDialogImpl::fileNameEntryChangedCallback) );
2078 }
2080 //Let's do more customization
2081 std::vector<Gtk::Expander *> expanders;
2082 findExpanderWidgets(cont, expanders);
2083 //g_message("Found %d expander widgets\n", expanders.size());
2084 if (expanders.size() >=1 )
2085 {
2086 //Always show the file list
2087 Gtk::Expander *expander = expanders[0];
2088 expander->set_expanded(true);
2089 }
2092 //if (extension == NULL)
2093 // checkbox.set_sensitive(FALSE);
2095 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2096 set_default(*add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK));
2098 show_all_children();
2099 }
2103 /**
2104 * Public factory method. Used in file.cpp
2105 */
2106 FileExportDialog *FileExportDialog::create(const Glib::ustring &path,
2107 FileDialogType fileTypes,
2108 const Glib::ustring &title,
2109 const Glib::ustring &default_key)
2110 {
2111 FileExportDialog *dialog = new FileExportDialogImpl(path, fileTypes, title, default_key);
2112 return dialog;
2113 }
2119 /**
2120 * Destructor
2121 */
2122 FileExportDialogImpl::~FileExportDialogImpl()
2123 {
2124 }
2128 /**
2129 * Show this dialog modally. Return true if user hits [OK]
2130 */
2131 bool
2132 FileExportDialogImpl::show()
2133 {
2134 Glib::ustring s = Glib::filename_to_utf8 (get_current_folder());
2135 if (s.length() == 0)
2136 s = getcwd (NULL, 0);
2137 set_current_folder(Glib::filename_from_utf8(s)); //hack to force initial dir listing
2138 set_modal (TRUE); //Window
2139 sp_transientize((GtkWidget *)gobj()); //Make transient
2140 gint b = run(); //Dialog
2141 svgPreview.showNoPreview();
2142 hide();
2144 if (b == Gtk::RESPONSE_OK)
2145 {
2146 int sel = fileTypeComboBox.get_active_row_number ();
2147 if (sel>=0 && sel< (int)fileTypes.size())
2148 {
2149 FileType &type = fileTypes[sel];
2150 extension = type.extension;
2151 }
2152 myFilename = get_filename();
2153 #ifdef WITH_GNOME_VFS
2154 if ( myFilename.empty() && gnome_vfs_initialized() ) {
2155 myFilename = get_uri();
2156 }
2157 #endif
2159 /*
2161 // FIXME: Why do we have more code
2163 append_extension = checkbox.get_active();
2164 prefs_set_int_attribute("dialogs.save_as", "append_extension", append_extension);
2165 prefs_set_string_attribute("dialogs.save_as", "default",
2166 ( extension != NULL ? extension->get_id() : "" ));
2167 */
2168 return TRUE;
2169 }
2170 else
2171 {
2172 return FALSE;
2173 }
2174 }
2177 /**
2178 * Get the file extension type that was selected by the user. Valid after an [OK]
2179 */
2180 Inkscape::Extension::Extension *
2181 FileExportDialogImpl::getSelectionType()
2182 {
2183 return extension;
2184 }
2187 /**
2188 * Get the file name chosen by the user. Valid after an [OK]
2189 */
2190 Glib::ustring
2191 FileExportDialogImpl::getFilename()
2192 {
2193 return myFilename;
2194 }
2199 } //namespace Dialog
2200 } //namespace UI
2201 } //namespace Inkscape
2204 /*
2205 Local Variables:
2206 mode:c++
2207 c-file-style:"stroustrup"
2208 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
2209 indent-tabs-mode:nil
2210 fill-column:99
2211 End:
2212 */
2213 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :