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)
122 {
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;
140 }
142 bool SVGPreview::setFileName(Glib::ustring &theFileName)
143 {
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;
159 }
163 bool SVGPreview::setFromMem(char const *xmlBuffer)
164 {
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;
182 }
186 void SVGPreview::showImage(Glib::ustring &theFileName)
187 {
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);
270 }
274 void SVGPreview::showNoPreview()
275 {
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;
367 }
369 void SVGPreview::showTooLarge(long fileLength)
370 {
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);
467 }
469 static bool
470 hasSuffix(Glib::ustring &str, Glib::ustring &ext)
471 {
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;
492 }
495 /**
496 * Return true if the image is loadable by Gdk, else false
497 */
498 static bool
499 isValidImageFile(Glib::ustring &fileName)
500 {
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;
516 }
518 bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
519 {
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 }
566 }
569 SVGPreview::SVGPreview()
570 {
571 if (!INKSCAPE)
572 inkscape_application_init("",false);
573 document = NULL;
574 viewerGtk = NULL;
575 set_size_request(150,150);
576 showingNoPreview = false;
577 }
579 SVGPreview::~SVGPreview()
580 {
582 }
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
596 {
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()
679 {
680 Glib::ustring fileName = get_preview_filename();
681 if (fileName.length() < 1)
682 return;
683 svgPreview.set(fileName, dialogType);
684 }
690 /**
691 * Callback for fileNameEntry widget
692 */
693 void FileOpenDialogImpl::fileNameEntryChangedCallback()
694 {
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 }
721 }
727 /**
728 * Callback for fileNameEntry widget
729 */
730 void FileOpenDialogImpl::fileSelectedCallback()
731 {
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);
742 }
747 void FileOpenDialogImpl::createFilterMenu()
748 {
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;
795 }
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))
806 {
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);
862 }
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)
874 {
875 FileOpenDialog *dialog = new FileOpenDialogImpl(path, fileTypes, title);
876 return dialog;
877 }
882 /**
883 * Destructor
884 */
885 FileOpenDialogImpl::~FileOpenDialogImpl()
886 {
888 }
891 /**
892 * Show this dialog modally. Return true if user hits [OK]
893 */
894 bool
895 FileOpenDialogImpl::show()
896 {
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 }
923 }
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()
933 {
934 return extension;
935 }
938 /**
939 * Get the file name chosen by the user. Valid after an [OK]
940 */
941 gchar *
942 FileOpenDialogImpl::getFilename (void)
943 {
944 return g_strdup(myFilename.c_str());
945 }
948 /**
949 * To Get Multiple filenames selected at-once.
950 */
951 Glib::SListHandle<Glib::ustring>FileOpenDialogImpl::getFilenames()
952 {
953 return get_filenames();
954 }
961 /*#########################################################################
962 # F I L E S A V E
963 #########################################################################*/
965 class FileType
966 {
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
979 {
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()
1078 {
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);
1084 }
1088 /**
1089 * Callback for fileNameEntry widget
1090 */
1091 void FileSaveDialogImpl::fileNameEntryChangedCallback()
1092 {
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 }
1121 }
1125 /**
1126 * Callback for fileNameEntry widget
1127 */
1128 void FileSaveDialogImpl::fileTypeChangedCallback()
1129 {
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);
1138 }
1142 void FileSaveDialogImpl::createFileTypeMenu()
1143 {
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
1175 }
1178 void findEntryWidgets(Gtk::Container *parent, std::vector<Gtk::Entry *> &result)
1179 {
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 }
1193 }
1195 void findExpanderWidgets(Gtk::Container *parent, std::vector<Gtk::Expander *> &result)
1196 {
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 }
1210 }
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)
1222 {
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();
1309 }
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)
1320 {
1321 FileSaveDialog *dialog = new FileSaveDialogImpl(path, fileTypes, title, default_key);
1322 return dialog;
1323 }
1329 /**
1330 * Destructor
1331 */
1332 FileSaveDialogImpl::~FileSaveDialogImpl()
1333 {
1334 }
1339 /**
1340 * Show this dialog modally. Return true if user hits [OK]
1341 */
1342 bool
1343 FileSaveDialogImpl::show()
1344 {
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 }
1377 }
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()
1385 {
1386 return extension;
1387 }
1390 /**
1391 * Get the file name chosen by the user. Valid after an [OK]
1392 */
1393 gchar *
1394 FileSaveDialogImpl::getFilename()
1395 {
1396 return g_strdup(myFilename.c_str());
1397 }
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)
1412 {
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 }
1426 }
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 :