Code

call GC::request_early_collection() after switching preview images
[inkscape.git] / src / dialogs / filedialog.cpp
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 The Inkscape Organization
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif
19 //Temporary ugly hack
20 //Remove these after the get_filter() calls in
21 //show() on both classes are fixed
22 #include <gtk/gtkfilechooser.h>
24 //Another hack
25 #include <gtk/gtkentry.h>
26 #include <gtk/gtkexpander.h>
28 #include <sys/stat.h>
29 #include <glibmm/i18n.h>
30 #include <gtkmm/box.h>
31 #include <gtkmm/filechooserdialog.h>
32 #include <gtkmm/menubar.h>
33 #include <gtkmm/menu.h>
34 #include <gtkmm/entry.h>
35 #include <gtkmm/expander.h>
36 #include <gtkmm/comboboxtext.h>
37 #include <gtkmm/stock.h>
38 #include <gdkmm/pixbuf.h>
40 #include "prefs-utils.h"
41 #include <dialogs/dialog-events.h>
42 #include <extension/input.h>
43 #include <extension/output.h>
44 #include <extension/db.h>
45 #include "inkscape.h"
46 #include "svg-view-widget.h"
47 #include "filedialog.h"
48 #include "gc-core.h"
50 #undef INK_DUMP_FILENAME_CONV
52 #ifdef INK_DUMP_FILENAME_CONV
53 void dump_str( const gchar* str, const gchar* prefix );
54 void dump_ustr( const Glib::ustring& ustr );
55 #endif
57 namespace Inkscape {
58 namespace UI {
59 namespace Dialogs {
61 void FileDialogExtensionToPattern (Glib::ustring &pattern, gchar * in_file_extension);
63 /*#########################################################################
64 ### SVG Preview Widget
65 #########################################################################*/
66 /**
67  * Simple class for displaying an SVG file in the "preview widget."
68  * Currently, this is just a wrapper of the sp_svg_view Gtk widget.
69  * Hopefully we will eventually replace with a pure Gtkmm widget.
70  */
71 class SVGPreview : public Gtk::VBox
72 {
73 public:
74     SVGPreview();
75     ~SVGPreview();
77     bool setDocument(SPDocument *doc);
79     bool setFileName(Glib::ustring &fileName);
81     bool setFromMem(char const *xmlBuffer);
83     bool set(Glib::ustring &fileName, int dialogType);
85     bool setURI(URI &uri);
87     /**
88      * Show image embedded in SVG
89      */
90     void showImage(Glib::ustring &fileName);
92     /**
93      * Show the "No preview" image
94      */
95     void showNoPreview();
97     /**
98      * Show the "Too large" image
99      */
100     void showTooLarge(long fileLength);
102 private:
103     /**
104      * The svg document we are currently showing
105      */
106     SPDocument *document;
108     /**
109      * The sp_svg_view widget
110      */
111     GtkWidget *viewerGtk;
113     /**
114      * are we currently showing the "no preview" image?
115      */
116     bool showingNoPreview;
118 };
121 bool SVGPreview::setDocument(SPDocument *doc)
123     if (document)
124         sp_document_unref(document);
126     sp_document_ref(doc);
127     document = doc;
129     //This should remove it from the box, and free resources
130     if (viewerGtk) {
131         gtk_widget_destroy(viewerGtk);
132     }
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;
142 bool SVGPreview::setFileName(Glib::ustring &theFileName)
144     Glib::ustring fileName = theFileName;
146     fileName = Glib::filename_to_utf8(fileName);
148     SPDocument *doc = sp_document_new (fileName.c_str(), 0);
149     if (!doc) {
150         g_warning("SVGView: error loading document '%s'\n", fileName.c_str());
151         return false;
152     }
154     setDocument(doc);
156     sp_document_unref(doc);
158     return true;
163 bool SVGPreview::setFromMem(char const *xmlBuffer)
165     if (!xmlBuffer)
166         return false;
168     gint len = (gint)strlen(xmlBuffer);
169     SPDocument *doc = sp_document_new_from_mem(xmlBuffer, len, 0);
170     if (!doc) {
171         g_warning("SVGView: error loading buffer '%s'\n",xmlBuffer);
172         return false;
173     }
175     setDocument(doc);
177     sp_document_unref(doc);
179     Inkscape::GC::request_early_collection();
181     return true;
186 void SVGPreview::showImage(Glib::ustring &theFileName)
188     Glib::ustring fileName = theFileName;
191     /*#####################################
192     # LET'S HAVE SOME FUN WITH SVG!
193     # Instead of just loading an image, why
194     # don't we make a lovely little svg and
195     # display it nicely?
196     #####################################*/
198     //Arbitrary size of svg doc -- rather 'portrait' shaped
199     gint previewWidth  = 400;
200     gint previewHeight = 600;
202     //Get some image info. Smart pointer does not need to be deleted
203     Glib::RefPtr<Gdk::Pixbuf> img = Gdk::Pixbuf::create_from_file(fileName);
204     gint imgWidth  = img->get_width();
205     gint imgHeight = img->get_height();
207     //Find the minimum scale to fit the image inside the preview area
208     double scaleFactorX = (0.9 *(double)previewWidth)  / ((double)imgWidth);
209     double scaleFactorY = (0.9 *(double)previewHeight) / ((double)imgHeight);
210     double scaleFactor = scaleFactorX;
211     if (scaleFactorX > scaleFactorY)
212         scaleFactor = scaleFactorY;
214     //Now get the resized values
215     gint scaledImgWidth  = (int) (scaleFactor * (double)imgWidth);
216     gint scaledImgHeight = (int) (scaleFactor * (double)imgHeight);
218     //center the image on the area
219     gint imgX = (previewWidth  - scaledImgWidth)  / 2;
220     gint imgY = (previewHeight - scaledImgHeight) / 2;
222     //wrap a rectangle around the image
223     gint rectX      = imgX-1;
224     gint rectY      = imgY-1;
225     gint rectWidth  = scaledImgWidth +2;
226     gint rectHeight = scaledImgHeight+2;
228     //Our template.  Modify to taste
229     gchar const *xformat =
230           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
231           "<svg\n"
232           "xmlns=\"http://www.w3.org/2000/svg\"\n"
233           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
234           "width=\"%d\" height=\"%d\">\n"
235           "<rect\n"
236           "  style=\"fill:#eeeeee;stroke:none\"\n"
237           "  x=\"-100\" y=\"-100\" width=\"4000\" height=\"4000\"/>\n"
238           "<image x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"\n"
239           "xlink:href=\"%s\"/>\n"
240           "<rect\n"
241           "  style=\"fill:none;"
242           "    stroke:#000000;stroke-width:1.0;"
243           "    stroke-linejoin:miter;stroke-opacity:1.0000000;"
244           "    stroke-miterlimit:4.0000000;stroke-dasharray:none\"\n"
245           "  x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
246           "<text\n"
247           "  style=\"font-size:24.000000;font-style:normal;font-weight:normal;"
248           "    fill:#000000;fill-opacity:1.0000000;stroke:none;"
249           "    font-family:Bitstream Vera Sans\"\n"
250           "  x=\"10\" y=\"26\">%d x %d</text>\n"
251           "</svg>\n\n";
253     //if (!Glib::get_charset()) //If we are not utf8
254     fileName = Glib::filename_to_utf8(fileName);
256     //Fill in the template
257     /* FIXME: Do proper XML quoting for fileName. */
258     gchar *xmlBuffer = g_strdup_printf(xformat,
259            previewWidth, previewHeight,
260            imgX, imgY, scaledImgWidth, scaledImgHeight,
261            fileName.c_str(),
262            rectX, rectY, rectWidth, rectHeight,
263            imgWidth, imgHeight);
265     //g_message("%s\n", xmlBuffer);
267     //now show it!
268     setFromMem(xmlBuffer);
269     g_free(xmlBuffer);
274 void SVGPreview::showNoPreview()
276     //Are we already showing it?
277     if (showingNoPreview)
278         return;
280     //Arbitrary size of svg doc -- rather 'portrait' shaped
281     gint previewWidth  = 300;
282     gint previewHeight = 600;
284     //Our template.  Modify to taste
285     gchar const *xformat =
286           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
287           "<svg\n"
288           "xmlns=\"http://www.w3.org/2000/svg\"\n"
289           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
290           "width=\"%d\" height=\"%d\">\n"
291           "<g transform=\"translate(-190,24.27184)\" style=\"opacity:0.12\">\n"
292           "<path\n"
293           "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
294           "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
295           "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
296           "id=\"whiteSpace\" />\n"
297           "<path\n"
298           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
299           "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
300           "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
301           "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
302           "id=\"droplet01\" />\n"
303           "<path\n"
304           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
305           "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
306           "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
307           "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
308           "287.18046 343.1206 286.46194 340.42914 z \"\n"
309           "id=\"droplet02\" />\n"
310           "<path\n"
311           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
312           "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
313           "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
314           "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
315           "id=\"droplet03\" />\n"
316           "<path\n"
317           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
318           "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
319           "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
320           "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
321           "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
322           "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
323           "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
324           "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
325           "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
326           "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
327           "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
328           "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
329           "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
330           "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
331           "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
332           "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
333           "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
334           "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
335           "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
336           "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
337           "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
338           "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
339           "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
340           "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
341           "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
342           "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
343           "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
344           "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
345           "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
346           "id=\"mountainDroplet\" />\n"
347           "</g> <g transform=\"translate(-20,0)\">\n"
348           "<text xml:space=\"preserve\"\n"
349           "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
350           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
351           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
352           "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
353           "x=\"190\" y=\"240\">%s</text></g>\n"
354           "</svg>\n\n";
356     //Fill in the template
357     gchar *xmlBuffer = g_strdup_printf(xformat,
358            previewWidth, previewHeight, _("No preview"));
360     //g_message("%s\n", xmlBuffer);
362     //now show it!
363     setFromMem(xmlBuffer);
364     g_free(xmlBuffer);
365     showingNoPreview = true;
369 void SVGPreview::showTooLarge(long fileLength)
372     //Arbitrary size of svg doc -- rather 'portrait' shaped
373     gint previewWidth  = 300;
374     gint previewHeight = 600;
376     //Our template.  Modify to taste
377     gchar const *xformat =
378           "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
379           "<svg\n"
380           "xmlns=\"http://www.w3.org/2000/svg\"\n"
381           "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
382           "width=\"%d\" height=\"%d\">\n"
383           "<g transform=\"translate(-170,24.27184)\" style=\"opacity:0.12\">\n"
384           "<path\n"
385           "style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
386           "d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
387           "29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
388           "id=\"whiteSpace\" />\n"
389           "<path\n"
390           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
391           "d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
392           "C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
393           "356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
394           "id=\"droplet01\" />\n"
395           "<path\n"
396           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
397           "d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
398           "C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
399           "267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
400           "287.18046 343.1206 286.46194 340.42914 z \"\n"
401           "id=\"droplet02\" />\n"
402           "<path\n"
403           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
404           "d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
405           "C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
406           "308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
407           "id=\"droplet03\" />\n"
408           "<path\n"
409           "style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
410           "d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
411           "L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
412           "L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
413           "C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
414           "C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
415           "199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
416           "326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
417           "378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
418           "405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
419           "363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
420           "302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
421           "276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
422           "219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
423           "219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
424           "34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
425           "41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
426           "104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
427           "451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
428           "109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
429           "455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
430           "115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
431           "118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
432           "131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
433           "138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
434           "77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
435           "41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
436           "275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
437           "274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
438           "id=\"mountainDroplet\" />\n"
439           "</g>\n"
440           "<text xml:space=\"preserve\"\n"
441           "style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
442           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
443           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
444           "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
445           "x=\"170\" y=\"215\">%5.1f MB</text>\n"
446           "<text xml:space=\"preserve\"\n"
447           "style=\"font-size:24.000000;font-style:normal;font-variant:normal;font-weight:bold;"
448           "font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
449           "stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
450           "font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
451           "x=\"180\" y=\"245\">%s</text>\n"
452           "</svg>\n\n";
454     //Fill in the template
455     double floatFileLength = ((double)fileLength) / 1048576.0;
456     //printf("%ld %f\n", fileLength, floatFileLength);
457     gchar *xmlBuffer = g_strdup_printf(xformat,
458            previewWidth, previewHeight, floatFileLength,
459            _("too large for preview"));
461     //g_message("%s\n", xmlBuffer);
463     //now show it!
464     setFromMem(xmlBuffer);
465     g_free(xmlBuffer);
469 static bool
470 hasSuffix(Glib::ustring &str, Glib::ustring &ext)
472     int strLen = str.length();
473     int extLen = ext.length();
474     if (extLen > strLen)
475     {
476         return false;
477     }
478     int strpos = strLen-1;
479     for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
480     {
481         Glib::ustring::value_type ch = str[strpos];
482         if (ch != ext[extpos])
483         {
484             if ( ((ch & 0xff80) != 0) ||
485                  static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
486             {
487                 return false;
488             }
489         }
490     }
491     return true;
495 /**
496  * Return true if the image is loadable by Gdk, else false
497  */
498 static bool
499 isValidImageFile(Glib::ustring &fileName)
501     std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
502     for (unsigned int i=0; i<formats.size(); i++)
503         {
504         Gdk::PixbufFormat format = formats[i];
505         std::vector<Glib::ustring>extensions = format.get_extensions();
506         for (unsigned int j=0; j<extensions.size(); j++)
507             {
508             Glib::ustring ext = extensions[j];
509             if (hasSuffix(fileName, ext))
510                 {
511                 return true;
512                 }
513             }
514         }
515     return false;
518 bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
521     if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS))
522         return false;
524     gchar *fName = (gchar *)fileName.c_str();
525     //g_message("fname:%s\n", fName);
528     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR))
529         {
530         struct stat info;
531         if (stat(fName, &info))
532             {
533             return FALSE;
534             }
535         long fileLen = info.st_size;
536         if (fileLen > 0x150000L)
537             {
538             showingNoPreview = false;
539             showTooLarge(fileLen);
540             return FALSE;
541             }
542         }
544     Glib::ustring svg = ".svg";
545     Glib::ustring svgz = ".svgz";
547     if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
548            (hasSuffix(fileName, svg) || hasSuffix(fileName, svgz)   )
549          )
550         {
551         bool retval = setFileName(fileName);
552         showingNoPreview = false;
553         return retval;
554         }
555     else if (isValidImageFile(fileName))
556         {
557         showImage(fileName);
558         showingNoPreview = false;
559         return true;
560         }
561     else
562         {
563         showNoPreview();
564         return false;
565         }
569 SVGPreview::SVGPreview()
571     if (!INKSCAPE)
572         inkscape_application_init("",false);
573     document = NULL;
574     viewerGtk = NULL;
575     set_size_request(150,150);
576     showingNoPreview = false;
579 SVGPreview::~SVGPreview()
588 /*#########################################################################
589 ### F I L E    O P E N
590 #########################################################################*/
592 /**
593  * Our implementation class for the FileOpenDialog interface..
594  */
595 class FileOpenDialogImpl : public FileOpenDialog, public Gtk::FileChooserDialog
597 public:
598     FileOpenDialogImpl(char const *dir,
599                        FileDialogType fileTypes,
600                        char const *title);
602     virtual ~FileOpenDialogImpl();
604     bool show();
606     Inkscape::Extension::Extension *getSelectionType();
608     gchar *getFilename();
610     Glib::SListHandle<Glib::ustring> getFilenames ();
611 protected:
615 private:
618     /**
619      * What type of 'open' are we? (open, import, place, etc)
620      */
621     FileDialogType dialogType;
623     /**
624      * Our svg preview widget
625      */
626     SVGPreview svgPreview;
628     /**
629      * Callback for seeing if the preview needs to be drawn
630      */
631     void updatePreviewCallback();
633     /**
634      * Fix to allow the user to type the file name
635      */
636     Gtk::Entry fileNameEntry;
638     /**
639      *  Create a filter menu for this type of dialog
640      */
641     void createFilterMenu();
643     /**
644      * Callback for user input into fileNameEntry
645      */
646     void fileNameEntryChangedCallback();
648     /**
649      * Callback for user changing which item is selected on the list
650      */
651     void fileSelectedCallback();
654     /**
655      * Filter name->extension lookup
656      */
657     std::map<Glib::ustring, Inkscape::Extension::Extension *> extensionMap;
659     /**
660      * The extension to use to write this file
661      */
662     Inkscape::Extension::Extension *extension;
664     /**
665      * Filename that was given
666      */
667     Glib::ustring myFilename;
669 };
675 /**
676  * Callback for checking if the preview needs to be redrawn
677  */
678 void FileOpenDialogImpl::updatePreviewCallback()
680     Glib::ustring fileName = get_preview_filename();
681     if (fileName.length() < 1)
682         return;
683     svgPreview.set(fileName, dialogType);
690 /**
691  * Callback for fileNameEntry widget
692  */
693 void FileOpenDialogImpl::fileNameEntryChangedCallback()
695     Glib::ustring fileName = fileNameEntry.get_text();
697     // TODO remove this leak
698     fileName = Glib::filename_from_utf8(fileName);
700     //g_message("User hit return.  Text is '%s'\n", fName.c_str());
702     if (!Glib::path_is_absolute(fileName)) {
703         //try appending to the current path
704         // not this way: fileName = get_current_folder() + "/" + fName;
705         std::vector<Glib::ustring> pathSegments;
706         pathSegments.push_back( get_current_folder() );
707         pathSegments.push_back( fileName );
708         fileName = Glib::build_filename(pathSegments);
709     }
711     //g_message("path:'%s'\n", fName.c_str());
713     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
714         set_current_folder(fileName);
715     } else if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)) {
716         //dialog with either (1) select a regular file or (2) cd to dir
717         //simulate an 'OK'
718         set_filename(fileName);
719         response(Gtk::RESPONSE_OK);
720     }
727 /**
728  * Callback for fileNameEntry widget
729  */
730 void FileOpenDialogImpl::fileSelectedCallback()
732     Glib::ustring fileName     = get_filename();
733     if (!Glib::get_charset()) //If we are not utf8
734         fileName = Glib::filename_to_utf8(fileName);
735     //g_message("User selected '%s'\n",
736     //       filename().c_str());
738 #ifdef INK_DUMP_FILENAME_CONV
739     ::dump_ustr( get_filename() );
740 #endif
741     fileNameEntry.set_text(fileName);
747 void FileOpenDialogImpl::createFilterMenu()
749     //patterns added dynamically below
750     Gtk::FileFilter allImageFilter;
751     allImageFilter.set_name(_("All Images"));
752     extensionMap[Glib::ustring(_("All Images"))]=NULL;
753     add_filter(allImageFilter);
755     Gtk::FileFilter allFilter;
756     allFilter.set_name(_("All Files"));
757     extensionMap[Glib::ustring(_("All Files"))]=NULL;
758     allFilter.add_pattern("*");
759     add_filter(allFilter);
761     //patterns added dynamically below
762     Gtk::FileFilter allInkscapeFilter;
763     allInkscapeFilter.set_name(_("All Inkscape Files"));
764     extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL;
765     add_filter(allInkscapeFilter);
767     Inkscape::Extension::DB::InputList extension_list;
768     Inkscape::Extension::db.get_input_list(extension_list);
770     for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
771          current_item != extension_list.end(); current_item++)
772     {
773         Inkscape::Extension::Input * imod = *current_item;
775         // FIXME: would be nice to grey them out instead of not listing them
776         if (imod->deactivated()) continue;
778         Glib::ustring upattern("*");
779         FileDialogExtensionToPattern (upattern, imod->get_extension());
781         Gtk::FileFilter filter;
782         Glib::ustring uname(_(imod->get_filetypename()));
783         filter.set_name(uname);
784         filter.add_pattern(upattern);
785         add_filter(filter);
786         extensionMap[uname] = imod;
788         //g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str());
789         allInkscapeFilter.add_pattern(upattern);
790         if ( strncmp("image", imod->get_mimetype(), 5)==0 )
791             allImageFilter.add_pattern(upattern);
792     }
794     return;
799 /**
800  * Constructor.  Not called directly.  Use the factory.
801  */
802 FileOpenDialogImpl::FileOpenDialogImpl(char const *dir,
803                                        FileDialogType fileTypes,
804                                        char const *title) :
805                  Gtk::FileChooserDialog(Glib::ustring(title))
809     /* One file at a time */
810     /* And also Multiple Files */
811     set_select_multiple(true);
813     /* Initalize to Autodetect */
814     extension = NULL;
815     /* No filename to start out with */
816     myFilename = "";
818     /* Set our dialog type (open, import, etc...)*/
819     dialogType = fileTypes;
822     /* Set the pwd and/or the filename */
823     if (dir != NULL)
824     {
825         Glib::ustring udir(dir);
826         Glib::ustring::size_type len = udir.length();
827         // leaving a trailing backslash on the directory name leads to the infamous
828         // double-directory bug on win32
829         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
830         set_current_folder(udir.c_str());
831     }
833     //###### Add the file types menu
834     createFilterMenu();
836     //###### Add a preview widget
837     set_preview_widget(svgPreview);
838     set_preview_widget_active(true);
839     set_use_preview_label (false);
841     //Catch selection-changed events, so we can adjust the text widget
842     signal_update_preview().connect(
843          sigc::mem_fun(*this, &FileOpenDialogImpl::updatePreviewCallback) );
846     //###### Add a text entry bar, and tie it to file chooser events
847     fileNameEntry.set_text(get_current_folder());
848     set_extra_widget(fileNameEntry);
849     fileNameEntry.grab_focus();
851     //Catch when user hits [return] on the text field
852     fileNameEntry.signal_activate().connect(
853          sigc::mem_fun(*this, &FileOpenDialogImpl::fileNameEntryChangedCallback) );
855     //Catch selection-changed events, so we can adjust the text widget
856     signal_selection_changed().connect(
857          sigc::mem_fun(*this, &FileOpenDialogImpl::fileSelectedCallback) );
859     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
860     add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_OK);
868 /**
869  * Public factory.  Called by file.cpp, among others.
870  */
871 FileOpenDialog *FileOpenDialog::create(char const *path,
872                                        FileDialogType fileTypes,
873                                        char const *title)
875     FileOpenDialog *dialog = new FileOpenDialogImpl(path, fileTypes, title);
876     return dialog;
882 /**
883  * Destructor
884  */
885 FileOpenDialogImpl::~FileOpenDialogImpl()
891 /**
892  * Show this dialog modally.  Return true if user hits [OK]
893  */
894 bool
895 FileOpenDialogImpl::show()
897     set_current_folder(get_current_folder()); //hack to force initial dir listing
898     set_modal (TRUE);                      //Window
899     sp_transientize((GtkWidget *)gobj());  //Make transient
900     gint b = run();                        //Dialog
901     svgPreview.showNoPreview();
902     hide();
904     if (b == Gtk::RESPONSE_OK)
905         {
906         //This is a hack, to avoid the warning messages that
907         //Gtk::FileChooser::get_filter() returns
908         //should be:  Gtk::FileFilter *filter = get_filter();
909         GtkFileChooser *gtkFileChooser = Gtk::FileChooser::gobj();
910         GtkFileFilter *filter = gtk_file_chooser_get_filter(gtkFileChooser);
911         if (filter)
912             {
913             //Get which extension was chosen, if any
914             extension = extensionMap[gtk_file_filter_get_name(filter)];
915             }
916         myFilename = get_filename();
917         return TRUE;
918         }
919     else
920        {
921        return FALSE;
922        }
928 /**
929  * Get the file extension type that was selected by the user. Valid after an [OK]
930  */
931 Inkscape::Extension::Extension *
932 FileOpenDialogImpl::getSelectionType()
934     return extension;
938 /**
939  * Get the file name chosen by the user.   Valid after an [OK]
940  */
941 gchar *
942 FileOpenDialogImpl::getFilename (void)
944     return g_strdup(myFilename.c_str());
948 /**
949  * To Get Multiple filenames selected at-once.
950  */
951 Glib::SListHandle<Glib::ustring>FileOpenDialogImpl::getFilenames()
952 {    
953     return get_filenames();
961 /*#########################################################################
962 # F I L E    S A V E
963 #########################################################################*/
965 class FileType
967     public:
968     FileType() {}
969     ~FileType() {}
970     Glib::ustring name;
971     Glib::ustring pattern;
972     Inkscape::Extension::Extension *extension;
973 };
975 /**
976  * Our implementation of the FileSaveDialog interface.
977  */
978 class FileSaveDialogImpl : public FileSaveDialog, public Gtk::FileChooserDialog
981 public:
982     FileSaveDialogImpl(char const *dir,
983                        FileDialogType fileTypes,
984                        char const *title,
985                        char const *default_key);
987     virtual ~FileSaveDialogImpl();
989     bool show();
991     Inkscape::Extension::Extension *getSelectionType();
993     gchar *getFilename();
996 private:
998     /**
999      * What type of 'open' are we? (save, export, etc)
1000      */
1001     FileDialogType dialogType;
1003     /**
1004      * Our svg preview widget
1005      */
1006     SVGPreview svgPreview;
1008     /**
1009      * Fix to allow the user to type the file name
1010      */
1011     Gtk::Entry *fileNameEntry;
1013     /**
1014      * Callback for seeing if the preview needs to be drawn
1015      */
1016     void updatePreviewCallback();
1020     /**
1021      * Allow the specification of the output file type
1022      */
1023     Gtk::HBox fileTypeBox;
1025     /**
1026      * Allow the specification of the output file type
1027      */
1028     Gtk::ComboBoxText fileTypeComboBox;
1031     /**
1032      *  Data mirror of the combo box
1033      */
1034     std::vector<FileType> fileTypes;
1036     //# Child widgets
1037     Gtk::CheckButton fileTypeCheckbox;
1040     /**
1041      * Callback for user input into fileNameEntry
1042      */
1043     void fileTypeChangedCallback();
1045     /**
1046      *  Create a filter menu for this type of dialog
1047      */
1048     void createFileTypeMenu();
1051     bool append_extension;
1053     /**
1054      * The extension to use to write this file
1055      */
1056     Inkscape::Extension::Extension *extension;
1058     /**
1059      * Callback for user input into fileNameEntry
1060      */
1061     void fileNameEntryChangedCallback();
1063     /**
1064      * Filename that was given
1065      */
1066     Glib::ustring myFilename;
1067 };
1074 /**
1075  * Callback for checking if the preview needs to be redrawn
1076  */
1077 void FileSaveDialogImpl::updatePreviewCallback()
1079     Glib::ustring fileName = get_preview_filename();
1080     if (!fileName.c_str())
1081         return;
1082     bool retval = svgPreview.set(fileName, dialogType);
1083     set_preview_widget_active(retval);
1088 /**
1089  * Callback for fileNameEntry widget
1090  */
1091 void FileSaveDialogImpl::fileNameEntryChangedCallback()
1093     if (!fileNameEntry)
1094         return;
1096     Glib::ustring fileName = fileNameEntry->get_text();
1097     if (!Glib::get_charset()) //If we are not utf8
1098         fileName = Glib::filename_to_utf8(fileName);
1100     //g_message("User hit return.  Text is '%s'\n", fileName.c_str());
1102     if (!Glib::path_is_absolute(fileName)) {
1103         //try appending to the current path
1104         // not this way: fileName = get_current_folder() + "/" + fileName;
1105         std::vector<Glib::ustring> pathSegments;
1106         pathSegments.push_back( get_current_folder() );
1107         pathSegments.push_back( fileName );
1108         fileName = Glib::build_filename(pathSegments);
1109     }
1111     //g_message("path:'%s'\n", fileName.c_str());
1113     if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1114         set_current_folder(fileName);
1115     } else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1116         //dialog with either (1) select a regular file or (2) cd to dir
1117         //simulate an 'OK'
1118         set_filename(fileName);
1119         response(Gtk::RESPONSE_OK);
1120     }
1125 /**
1126  * Callback for fileNameEntry widget
1127  */
1128 void FileSaveDialogImpl::fileTypeChangedCallback()
1130     int sel = fileTypeComboBox.get_active_row_number();
1131     if (sel<0 || sel >= (int)fileTypes.size())
1132         return;
1133     FileType type = fileTypes[sel];
1134     //g_message("selected: %s\n", type.name.c_str());
1135     Gtk::FileFilter filter;
1136     filter.add_pattern(type.pattern);
1137     set_filter(filter);
1142 void FileSaveDialogImpl::createFileTypeMenu()
1144     Inkscape::Extension::DB::OutputList extension_list;
1145     Inkscape::Extension::db.get_output_list(extension_list);
1147     for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1148          current_item != extension_list.end(); current_item++)
1149     {
1150         Inkscape::Extension::Output * omod = *current_item;
1152         // FIXME: would be nice to grey them out instead of not listing them
1153         if (omod->deactivated()) continue;
1155         FileType type;
1156         type.name     = (_(omod->get_filetypename()));
1157         type.pattern  = "*";
1158         FileDialogExtensionToPattern (type.pattern, omod->get_extension());
1159         type.extension= omod;
1160         fileTypeComboBox.append_text(type.name);
1161         fileTypes.push_back(type);
1162     }
1164     //#Let user choose
1165     FileType guessType;
1166     guessType.name = _("Guess from extension");
1167     guessType.pattern = "*";
1168     guessType.extension = NULL;
1169     fileTypeComboBox.append_text(guessType.name);
1170     fileTypes.push_back(guessType);
1173     fileTypeComboBox.set_active(0);
1174     fileTypeChangedCallback(); //call at least once to set the filter
1178 void findEntryWidgets(Gtk::Container *parent, std::vector<Gtk::Entry *> &result)
1180     if (!parent)
1181         return;
1182     std::vector<Gtk::Widget *> children = parent->get_children();
1183     for (unsigned int i=0; i<children.size() ; i++)
1184         {
1185         Gtk::Widget *child = children[i];
1186         GtkWidget *wid = child->gobj();
1187         if (GTK_IS_ENTRY(wid))
1188            result.push_back((Gtk::Entry *)child);
1189         else if (GTK_IS_CONTAINER(wid))
1190             findEntryWidgets((Gtk::Container *)child, result);
1191         }
1195 void findExpanderWidgets(Gtk::Container *parent, std::vector<Gtk::Expander *> &result)
1197     if (!parent)
1198         return;
1199     std::vector<Gtk::Widget *> children = parent->get_children();
1200     for (unsigned int i=0; i<children.size() ; i++)
1201         {
1202         Gtk::Widget *child = children[i];
1203         GtkWidget *wid = child->gobj();
1204         if (GTK_IS_EXPANDER(wid))
1205            result.push_back((Gtk::Expander *)child);
1206         else if (GTK_IS_CONTAINER(wid))
1207             findExpanderWidgets((Gtk::Container *)child, result);
1208         }
1213 /**
1214  * Constructor
1215  */
1216 FileSaveDialogImpl::FileSaveDialogImpl(char const *dir,
1217                                        FileDialogType fileTypes,
1218                                        char const *title,
1219                                        char const *default_key) :
1220                                        Gtk::FileChooserDialog(Glib::ustring(title),
1221                                            Gtk::FILE_CHOOSER_ACTION_SAVE)
1223     append_extension = (bool)prefs_get_int_attribute("dialogs.save_as", "append_extension", 1);
1225     /* One file at a time */
1226     set_select_multiple(false);
1228     /* Initalize to Autodetect */
1229     extension = NULL;
1230     /* No filename to start out with */
1231     myFilename = "";
1233     /* Set our dialog type (save, export, etc...)*/
1234     dialogType = fileTypes;
1236     /* Set the pwd and/or the filename */
1237     if (dir != NULL)
1238     {
1239         Glib::ustring udir(dir);
1240         Glib::ustring::size_type len = udir.length();
1241         // leaving a trailing backslash on the directory name leads to the infamous
1242         // double-directory bug on win32
1243         if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
1244         set_current_folder(udir.c_str());
1245     }
1247     //###### Add the file types menu
1248     //createFilterMenu();
1250     //###### Do we want the .xxx extension automatically added?
1251     fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
1252     fileTypeCheckbox.set_active(append_extension);
1254     fileTypeBox.pack_start(fileTypeCheckbox);
1255     createFileTypeMenu();
1256     fileTypeComboBox.set_size_request(200,40);
1257     fileTypeComboBox.signal_changed().connect(
1258          sigc::mem_fun(*this, &FileSaveDialogImpl::fileTypeChangedCallback) );
1260     fileTypeBox.pack_start(fileTypeComboBox);
1262     set_extra_widget(fileTypeBox);
1263     //get_vbox()->pack_start(fileTypeBox, false, false, 0);
1264     //get_vbox()->reorder_child(fileTypeBox, 2);
1266     //###### Add a preview widget
1267     set_preview_widget(svgPreview);
1268     set_preview_widget_active(true);
1269     set_use_preview_label (false);
1271     //Catch selection-changed events, so we can adjust the text widget
1272     signal_update_preview().connect(
1273          sigc::mem_fun(*this, &FileSaveDialogImpl::updatePreviewCallback) );
1276     //Let's do some customization
1277     fileNameEntry = NULL;
1278     Gtk::Container *cont = get_toplevel();
1279     std::vector<Gtk::Entry *> entries;
1280     findEntryWidgets(cont, entries);
1281     //g_message("Found %d entry widgets\n", entries.size());
1282     if (entries.size() >=1 )
1283         {
1284         //Catch when user hits [return] on the text field
1285         fileNameEntry = entries[0];
1286         fileNameEntry->signal_activate().connect(
1287              sigc::mem_fun(*this, &FileSaveDialogImpl::fileNameEntryChangedCallback) );
1288         }
1290     //Let's do more customization
1291     std::vector<Gtk::Expander *> expanders;
1292     findExpanderWidgets(cont, expanders);
1293     //g_message("Found %d expander widgets\n", expanders.size());
1294     if (expanders.size() >=1 )
1295         {
1296         //Always show the file list
1297         Gtk::Expander *expander = expanders[0];
1298         expander->set_expanded(true);
1299         }
1302     //if (extension == NULL)
1303     //    checkbox.set_sensitive(FALSE);
1305     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1306     add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_OK);
1308     show_all_children();
1313 /**
1314  * Public factory method.  Used in file.cpp
1315  */
1316 FileSaveDialog *FileSaveDialog::create(char const *path,
1317                                        FileDialogType fileTypes,
1318                                        char const *title,
1319                                        char const *default_key)
1321     FileSaveDialog *dialog = new FileSaveDialogImpl(path, fileTypes, title, default_key);
1322     return dialog;
1329 /**
1330  * Destructor
1331  */
1332 FileSaveDialogImpl::~FileSaveDialogImpl()
1339 /**
1340  * Show this dialog modally.  Return true if user hits [OK]
1341  */
1342 bool
1343 FileSaveDialogImpl::show()
1345     set_current_folder(get_current_folder()); //hack to force initial dir listing
1346     set_modal (TRUE);                      //Window
1347     sp_transientize((GtkWidget *)gobj());  //Make transient
1348     gint b = run();                        //Dialog
1349     svgPreview.showNoPreview();
1350     hide();
1352     if (b == Gtk::RESPONSE_OK)
1353         {
1354         int sel = fileTypeComboBox.get_active_row_number ();
1355         if (sel>=0 && sel< (int)fileTypes.size())
1356             {
1357             FileType &type = fileTypes[sel];
1358             extension = type.extension;
1359             }
1360         myFilename = get_filename();
1362         /*
1364         // FIXME: Why do we have more code
1366         append_extension = checkbox.get_active();
1367         prefs_set_int_attribute("dialogs.save_as", "append_extension", append_extension);
1368         prefs_set_string_attribute("dialogs.save_as", "default",
1369                   ( extension != NULL ? extension->get_id() : "" ));
1370         */
1371         return TRUE;
1372         }
1373     else
1374         {
1375         return FALSE;
1376         }
1380 /**
1381  * Get the file extension type that was selected by the user. Valid after an [OK]
1382  */
1383 Inkscape::Extension::Extension *
1384 FileSaveDialogImpl::getSelectionType()
1386     return extension;
1390 /**
1391  * Get the file name chosen by the user.   Valid after an [OK]
1392  */
1393 gchar *
1394 FileSaveDialogImpl::getFilename()
1396     return g_strdup(myFilename.c_str());
1399 /**
1400     \brief  A quick function to turn a standard extension into a searchable
1401             pattern for the file dialogs
1402     \param  pattern  The patter that the extension should be written to
1403     \param  in_file_extension  The C string that represents the extension
1405     This function just goes through the string, and takes all characters
1406     and puts a [<upper><lower>] so that both are searched and shown in
1407     the file dialog.  This function edits the pattern string to make
1408     this happen.
1409 */
1410 void
1411 FileDialogExtensionToPattern (Glib::ustring &pattern, gchar * in_file_extension)
1413     Glib::ustring tmp(in_file_extension);
1415     for ( guint i = 0; i < tmp.length(); i++ ) {
1416         Glib::ustring::value_type ch = tmp.at(i);
1417         if ( Glib::Unicode::isalpha(ch) ) {
1418             pattern += '[';
1419             pattern += Glib::Unicode::toupper(ch);
1420             pattern += Glib::Unicode::tolower(ch);
1421             pattern += ']';
1422         } else {
1423             pattern += ch;
1424         }
1425     }
1428 } //namespace Dialogs
1429 } //namespace UI
1430 } //namespace Inkscape
1433 /*
1434   Local Variables:
1435   mode:c++
1436   c-file-style:"stroustrup"
1437   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1438   indent-tabs-mode:nil
1439   fill-column:99
1440   End:
1441 */
1442 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :