2
* Implementation of the file dialog interfaces defined in filedialog.h
6
* Other dudes from The Inkscape Organization
8
* Copyright (C) 2004 The Inkscape Organization
10
* Released under GNU GPL, read the file 'COPYING' for more information
20
//Remove these after the get_filter() calls in
21
//show() on both classes are fixed
22
#include <gtk/gtkfilechooser.h>
25
#include <gtk/gtkentry.h>
26
#include <gtk/gtkexpander.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>
46
#include "svg-view-widget.h"
47
#include "filedialog.h"
49
#undef INK_DUMP_FILENAME_CONV
51
#ifdef INK_DUMP_FILENAME_CONV
52
void dump_str( const gchar* str, const gchar* prefix );
53
void dump_ustr( const Glib::ustring& ustr );
60
void FileDialogExtensionToPattern (Glib::ustring &pattern, gchar * in_file_extension);
62
/*#########################################################################
63
### SVG Preview Widget
64
#########################################################################*/
66
* Simple class for displaying an SVG file in the "preview widget."
67
* Currently, this is just a wrapper of the sp_svg_view Gtk widget.
68
* Hopefully we will eventually replace with a pure Gtkmm widget.
70
class SVGPreview : public Gtk::VBox
76
bool setDocument(SPDocument *doc);
78
bool setFileName(Glib::ustring &fileName);
80
bool setFromMem(char const *xmlBuffer);
82
bool set(Glib::ustring &fileName, int dialogType);
84
bool setURI(URI &uri);
87
* Show image embedded in SVG
89
void showImage(Glib::ustring &fileName);
92
* Show the "No preview" image
97
* Show the "Too large" image
99
void showTooLarge(long fileLength);
103
* The svg document we are currently showing
105
SPDocument *document;
108
* The sp_svg_view widget
110
GtkWidget *viewerGtk;
113
* are we currently showing the "no preview" image?
115
bool showingNoPreview;
120
bool SVGPreview::setDocument(SPDocument *doc)
123
sp_document_unref(document);
125
sp_document_ref(doc);
128
//This should remove it from the box, and free resources
130
gtk_widget_destroy(viewerGtk);
133
viewerGtk = sp_svg_view_widget_new(doc);
134
GtkWidget *vbox = (GtkWidget *)gobj();
135
gtk_box_pack_start(GTK_BOX(vbox), viewerGtk, TRUE, TRUE, 0);
136
gtk_widget_show(viewerGtk);
141
bool SVGPreview::setFileName(Glib::ustring &theFileName)
143
Glib::ustring fileName = theFileName;
145
fileName = Glib::filename_to_utf8(fileName);
147
SPDocument *doc = sp_document_new (fileName.c_str(), 0);
149
g_warning("SVGView: error loading document '%s'\n", fileName.c_str());
155
sp_document_unref(doc);
162
bool SVGPreview::setFromMem(char const *xmlBuffer)
167
gint len = (gint)strlen(xmlBuffer);
168
SPDocument *doc = sp_document_new_from_mem(xmlBuffer, len, 0);
170
g_warning("SVGView: error loading buffer '%s'\n",xmlBuffer);
176
sp_document_unref(doc);
183
void SVGPreview::showImage(Glib::ustring &theFileName)
185
Glib::ustring fileName = theFileName;
188
/*#####################################
189
# LET'S HAVE SOME FUN WITH SVG!
190
# Instead of just loading an image, why
191
# don't we make a lovely little svg and
193
#####################################*/
195
//Arbitrary size of svg doc -- rather 'portrait' shaped
196
gint previewWidth = 400;
197
gint previewHeight = 600;
199
//Get some image info. Smart pointer does not need to be deleted
200
Glib::RefPtr<Gdk::Pixbuf> img = Gdk::Pixbuf::create_from_file(fileName);
201
gint imgWidth = img->get_width();
202
gint imgHeight = img->get_height();
204
//Find the minimum scale to fit the image inside the preview area
205
double scaleFactorX = (0.9 *(double)previewWidth) / ((double)imgWidth);
206
double scaleFactorY = (0.9 *(double)previewHeight) / ((double)imgHeight);
207
double scaleFactor = scaleFactorX;
208
if (scaleFactorX > scaleFactorY)
209
scaleFactor = scaleFactorY;
211
//Now get the resized values
212
gint scaledImgWidth = (int) (scaleFactor * (double)imgWidth);
213
gint scaledImgHeight = (int) (scaleFactor * (double)imgHeight);
215
//center the image on the area
216
gint imgX = (previewWidth - scaledImgWidth) / 2;
217
gint imgY = (previewHeight - scaledImgHeight) / 2;
219
//wrap a rectangle around the image
222
gint rectWidth = scaledImgWidth +2;
223
gint rectHeight = scaledImgHeight+2;
225
//Our template. Modify to taste
226
gchar const *xformat =
227
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
229
"xmlns=\"http://www.w3.org/2000/svg\"\n"
230
"xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
231
"width=\"%d\" height=\"%d\">\n"
233
" style=\"fill:#eeeeee;stroke:none\"\n"
234
" x=\"-100\" y=\"-100\" width=\"4000\" height=\"4000\"/>\n"
235
"<image x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"\n"
236
"xlink:href=\"%s\"/>\n"
238
" style=\"fill:none;"
239
" stroke:#000000;stroke-width:1.0;"
240
" stroke-linejoin:miter;stroke-opacity:1.0000000;"
241
" stroke-miterlimit:4.0000000;stroke-dasharray:none\"\n"
242
" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
244
" style=\"font-size:24.000000;font-style:normal;font-weight:normal;"
245
" fill:#000000;fill-opacity:1.0000000;stroke:none;"
246
" font-family:Bitstream Vera Sans\"\n"
247
" x=\"10\" y=\"26\">%d x %d</text>\n"
250
//if (!Glib::get_charset()) //If we are not utf8
251
fileName = Glib::filename_to_utf8(fileName);
253
//Fill in the template
254
/* FIXME: Do proper XML quoting for fileName. */
255
gchar *xmlBuffer = g_strdup_printf(xformat,
256
previewWidth, previewHeight,
257
imgX, imgY, scaledImgWidth, scaledImgHeight,
259
rectX, rectY, rectWidth, rectHeight,
260
imgWidth, imgHeight);
262
//g_message("%s\n", xmlBuffer);
265
setFromMem(xmlBuffer);
271
void SVGPreview::showNoPreview()
273
//Are we already showing it?
274
if (showingNoPreview)
277
//Arbitrary size of svg doc -- rather 'portrait' shaped
278
gint previewWidth = 300;
279
gint previewHeight = 600;
281
//Our template. Modify to taste
282
gchar const *xformat =
283
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
285
"xmlns=\"http://www.w3.org/2000/svg\"\n"
286
"xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
287
"width=\"%d\" height=\"%d\">\n"
288
"<g transform=\"translate(-190,24.27184)\" style=\"opacity:0.12\">\n"
290
"style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
291
"d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
292
"29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
293
"id=\"whiteSpace\" />\n"
295
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
296
"d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
297
"C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
298
"356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
299
"id=\"droplet01\" />\n"
301
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
302
"d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
303
"C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
304
"267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
305
"287.18046 343.1206 286.46194 340.42914 z \"\n"
306
"id=\"droplet02\" />\n"
308
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
309
"d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
310
"C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
311
"308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
312
"id=\"droplet03\" />\n"
314
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
315
"d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
316
"L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
317
"L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
318
"C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
319
"C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
320
"199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
321
"326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
322
"378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
323
"405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
324
"363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
325
"302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
326
"276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
327
"219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
328
"219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
329
"34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
330
"41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
331
"104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
332
"451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
333
"109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
334
"455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
335
"115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
336
"118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
337
"131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
338
"138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
339
"77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
340
"41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
341
"275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
342
"274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
343
"id=\"mountainDroplet\" />\n"
344
"</g> <g transform=\"translate(-20,0)\">\n"
345
"<text xml:space=\"preserve\"\n"
346
"style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
347
"font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
348
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
349
"font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
350
"x=\"190\" y=\"240\">%s</text></g>\n"
353
//Fill in the template
354
gchar *xmlBuffer = g_strdup_printf(xformat,
355
previewWidth, previewHeight, _("No preview"));
357
//g_message("%s\n", xmlBuffer);
360
setFromMem(xmlBuffer);
362
showingNoPreview = true;
366
void SVGPreview::showTooLarge(long fileLength)
369
//Arbitrary size of svg doc -- rather 'portrait' shaped
370
gint previewWidth = 300;
371
gint previewHeight = 600;
373
//Our template. Modify to taste
374
gchar const *xformat =
375
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
377
"xmlns=\"http://www.w3.org/2000/svg\"\n"
378
"xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
379
"width=\"%d\" height=\"%d\">\n"
380
"<g transform=\"translate(-170,24.27184)\" style=\"opacity:0.12\">\n"
382
"style=\"font-size:12;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.936193pt\"\n"
383
"d=\"M 397.64309 320.25301 L 280.39197 282.517 L 250.74227 124.83447 L 345.08225 "
384
"29.146783 L 393.59996 46.667064 L 483.89679 135.61619 L 397.64309 320.25301 z \"\n"
385
"id=\"whiteSpace\" />\n"
387
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
388
"d=\"M 476.95792 339.17168 C 495.78197 342.93607 499.54842 356.11361 495.78197 359.87802 "
389
"C 492.01856 363.6434 482.6065 367.40781 475.07663 361.76014 C 467.54478 "
390
"356.11361 467.54478 342.93607 476.95792 339.17168 z \"\n"
391
"id=\"droplet01\" />\n"
393
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
394
"d=\"M 286.46194 340.42914 C 284.6277 340.91835 269.30405 327.71337 257.16909 333.8338 "
395
"C 245.03722 339.95336 236.89276 353.65666 248.22676 359.27982 C 259.56184 364.90298 "
396
"267.66433 358.41867 277.60113 351.44119 C 287.53903 344.46477 "
397
"287.18046 343.1206 286.46194 340.42914 z \"\n"
398
"id=\"droplet02\" />\n"
400
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
401
"d=\"M 510.35756 306.92856 C 520.59494 304.36879 544.24333 306.92856 540.47688 321.98634 "
402
"C 536.71354 337.04806 504.71297 331.39827 484.00371 323.87156 C 482.12141 "
403
"308.81083 505.53237 308.13423 510.35756 306.92856 z \"\n"
404
"id=\"droplet03\" />\n"
406
"style=\"font-size:12;fill-rule:evenodd;stroke-width:1pt;fill:#000000;fill-opacity:1\"\n"
407
"d=\"M 359.2403 21.362537 C 347.92693 21.362537 336.6347 25.683095 327.96556 34.35223 "
408
"L 173.87387 188.41466 C 165.37697 196.9114 161.1116 207.95813 160.94269 219.04577 "
409
"L 160.88418 219.04577 C 160.88418 219.08524 160.94076 219.12322 160.94269 219.16279 "
410
"C 160.94033 219.34888 160.88418 219.53256 160.88418 219.71865 L 161.14748 219.71865 "
411
"C 164.0966 230.93917 240.29699 245.24198 248.79866 253.74346 C 261.63771 266.58263 "
412
"199.5652 276.01151 212.4041 288.85074 C 225.24316 301.68979 289.99433 313.6933 302.8346 "
413
"326.53254 C 315.67368 339.37161 276.5961 353.04289 289.43532 365.88196 C 302.27439 "
414
"378.72118 345.40201 362.67257 337.5908 396.16198 C 354.92909 413.50026 391.10302 "
415
"405.2208 415.32417 387.88252 C 428.16323 375.04345 390.6948 376.17577 403.53397 "
416
"363.33668 C 416.37304 350.49745 448.78128 350.4282 476.08902 319.71589 C 465.09739 "
417
"302.62116 429.10801 295.34136 441.94719 282.50217 C 454.78625 269.66311 479.74708 "
418
"276.18423 533.60644 251.72479 C 559.89837 239.78398 557.72636 230.71459 557.62567 "
419
"219.71865 C 557.62356 219.48727 557.62567 219.27892 557.62567 219.04577 L 557.56716 "
420
"219.04577 C 557.3983 207.95812 553.10345 196.9114 544.60673 188.41466 L 390.54428 "
421
"34.35223 C 381.87515 25.683095 370.55366 21.362537 359.2403 21.362537 z M 357.92378 "
422
"41.402939 C 362.95327 41.533963 367.01541 45.368018 374.98006 50.530832 L 447.76915 "
423
"104.50827 C 448.56596 105.02498 449.32484 105.564 450.02187 106.11735 C 450.7189 106.67062 "
424
"451.3556 107.25745 451.95277 107.84347 C 452.54997 108.42842 453.09281 109.01553 453.59111 "
425
"109.62808 C 454.08837 110.24052 454.53956 110.86661 454.93688 111.50048 C 455.33532 112.13538 "
426
"455.69164 112.78029 455.9901 113.43137 C 456.28877 114.08363 456.52291 114.75639 456.7215 "
427
"115.42078 C 456.92126 116.08419 457.08982 116.73973 457.18961 117.41019 C 457.28949 "
428
"118.08184 457.33588 118.75535 457.33588 119.42886 L 414.21245 98.598549 L 409.9118 "
429
"131.16055 L 386.18512 120.04324 L 349.55654 144.50131 L 335.54288 96.1703 L 317.4919 "
430
"138.4453 L 267.08369 143.47735 L 267.63956 121.03795 C 267.63956 115.64823 296.69685 "
431
"77.915899 314.39075 68.932902 L 346.77721 45.674327 C 351.55594 42.576634 354.90608 "
432
"41.324327 357.92378 41.402939 z M 290.92738 261.61333 C 313.87149 267.56365 339.40299 "
433
"275.37038 359.88393 275.50997 L 360.76161 284.72563 C 343.2235 282.91785 306.11346 "
434
"274.45012 297.36372 269.98057 L 290.92738 261.61333 z \"\n"
435
"id=\"mountainDroplet\" />\n"
437
"<text xml:space=\"preserve\"\n"
438
"style=\"font-size:32.000000;font-style:normal;font-variant:normal;font-weight:bold;"
439
"font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
440
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
441
"font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
442
"x=\"170\" y=\"215\">%5.1f MB</text>\n"
443
"<text xml:space=\"preserve\"\n"
444
"style=\"font-size:24.000000;font-style:normal;font-variant:normal;font-weight:bold;"
445
"font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000pt;"
446
"stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;"
447
"font-family:Bitstream Vera Sans;text-anchor:middle;writing-mode:lr\"\n"
448
"x=\"180\" y=\"245\">%s</text>\n"
451
//Fill in the template
452
double floatFileLength = ((double)fileLength) / 1048576.0;
453
//printf("%ld %f\n", fileLength, floatFileLength);
454
gchar *xmlBuffer = g_strdup_printf(xformat,
455
previewWidth, previewHeight, floatFileLength,
456
_("too large for preview"));
458
//g_message("%s\n", xmlBuffer);
461
setFromMem(xmlBuffer);
467
hasSuffix(Glib::ustring &str, Glib::ustring &ext)
469
int strLen = str.length();
470
int extLen = ext.length();
475
int strpos = strLen-1;
476
for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
478
Glib::ustring::value_type ch = str[strpos];
479
if (ch != ext[extpos])
481
if ( ((ch & 0xff80) != 0) ||
482
static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
493
* Return true if the image is loadable by Gdk, else false
496
isValidImageFile(Glib::ustring &fileName)
498
std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
499
for (unsigned int i=0; i<formats.size(); i++)
501
Gdk::PixbufFormat format = formats[i];
502
std::vector<Glib::ustring>extensions = format.get_extensions();
503
for (unsigned int j=0; j<extensions.size(); j++)
505
Glib::ustring ext = extensions[j];
506
if (hasSuffix(fileName, ext))
515
bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
518
if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS))
521
gchar *fName = (gchar *)fileName.c_str();
522
//g_message("fname:%s\n", fName);
525
if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR))
528
if (stat(fName, &info))
532
long fileLen = info.st_size;
533
if (fileLen > 0x150000L)
535
showingNoPreview = false;
536
showTooLarge(fileLen);
541
Glib::ustring svg = ".svg";
542
Glib::ustring svgz = ".svgz";
544
if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
545
(hasSuffix(fileName, svg) || hasSuffix(fileName, svgz) )
548
bool retval = setFileName(fileName);
549
showingNoPreview = false;
552
else if (isValidImageFile(fileName))
555
showingNoPreview = false;
566
SVGPreview::SVGPreview()
569
inkscape_application_init("",false);
572
set_size_request(150,150);
573
showingNoPreview = false;
576
SVGPreview::~SVGPreview()
585
/*#########################################################################
587
#########################################################################*/
590
* Our implementation class for the FileOpenDialog interface..
592
class FileOpenDialogImpl : public FileOpenDialog, public Gtk::FileChooserDialog
595
FileOpenDialogImpl(char const *dir,
596
FileDialogType fileTypes,
599
virtual ~FileOpenDialogImpl();
603
Inkscape::Extension::Extension *getSelectionType();
605
gchar *getFilename();
607
Glib::SListHandle<Glib::ustring> getFilenames ();
616
* What type of 'open' are we? (open, import, place, etc)
618
FileDialogType dialogType;
621
* Our svg preview widget
623
SVGPreview svgPreview;
626
* Callback for seeing if the preview needs to be drawn
628
void updatePreviewCallback();
631
* Fix to allow the user to type the file name
633
Gtk::Entry fileNameEntry;
636
* Create a filter menu for this type of dialog
638
void createFilterMenu();
641
* Callback for user input into fileNameEntry
643
void fileNameEntryChangedCallback();
646
* Callback for user changing which item is selected on the list
648
void fileSelectedCallback();
652
* Filter name->extension lookup
654
std::map<Glib::ustring, Inkscape::Extension::Extension *> extensionMap;
657
* The extension to use to write this file
659
Inkscape::Extension::Extension *extension;
662
* Filename that was given
664
Glib::ustring myFilename;
673
* Callback for checking if the preview needs to be redrawn
675
void FileOpenDialogImpl::updatePreviewCallback()
677
Glib::ustring fileName = get_preview_filename();
679
if (fileName.length() < 1)
682
svgPreview.set(fileName, dialogType);
690
* Callback for fileNameEntry widget
692
void FileOpenDialogImpl::fileNameEntryChangedCallback()
694
Glib::ustring fileName = fileNameEntry.get_text();
696
// TODO remove this leak
697
fileName = Glib::filename_from_utf8(fileName);
699
//g_message("User hit return. Text is '%s'\n", fName.c_str());
701
if (!Glib::path_is_absolute(fileName)) {
702
//try appending to the current path
703
// not this way: fileName = get_current_folder() + "/" + fName;
704
std::vector<Glib::ustring> pathSegments;
705
pathSegments.push_back( get_current_folder() );
706
pathSegments.push_back( fileName );
707
fileName = Glib::build_filename(pathSegments);
710
//g_message("path:'%s'\n", fName.c_str());
712
if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
713
set_current_folder(fileName);
714
} else if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)) {
715
//dialog with either (1) select a regular file or (2) cd to dir
717
set_filename(fileName);
718
response(Gtk::RESPONSE_OK);
727
* Callback for fileNameEntry widget
729
void FileOpenDialogImpl::fileSelectedCallback()
731
Glib::ustring fileName = get_filename();
732
if (!Glib::get_charset()) //If we are not utf8
733
fileName = Glib::filename_to_utf8(fileName);
734
//g_message("User selected '%s'\n",
735
// filename().c_str());
737
#ifdef INK_DUMP_FILENAME_CONV
738
::dump_ustr( get_filename() );
740
fileNameEntry.set_text(fileName);
746
void FileOpenDialogImpl::createFilterMenu()
748
//patterns added dynamically below
749
Gtk::FileFilter allImageFilter;
750
allImageFilter.set_name(_("All Images"));
751
extensionMap[Glib::ustring(_("All Images"))]=NULL;
752
add_filter(allImageFilter);
754
Gtk::FileFilter allFilter;
755
allFilter.set_name(_("All Files"));
756
extensionMap[Glib::ustring(_("All Files"))]=NULL;
757
allFilter.add_pattern("*");
758
add_filter(allFilter);
760
//patterns added dynamically below
761
Gtk::FileFilter allInkscapeFilter;
762
allInkscapeFilter.set_name(_("All Inkscape Files"));
763
extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL;
764
add_filter(allInkscapeFilter);
766
Inkscape::Extension::DB::InputList extension_list;
767
Inkscape::Extension::db.get_input_list(extension_list);
769
for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
770
current_item != extension_list.end(); current_item++)
772
Inkscape::Extension::Input * imod = *current_item;
774
// FIXME: would be nice to grey them out instead of not listing them
775
if (imod->deactivated()) continue;
777
Glib::ustring upattern("*");
778
FileDialogExtensionToPattern (upattern, imod->get_extension());
780
Gtk::FileFilter filter;
781
Glib::ustring uname(_(imod->get_filetypename()));
782
filter.set_name(uname);
783
filter.add_pattern(upattern);
785
extensionMap[uname] = imod;
787
//g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str());
788
allInkscapeFilter.add_pattern(upattern);
789
if ( strncmp("image", imod->get_mimetype(), 5)==0 )
790
allImageFilter.add_pattern(upattern);
799
* Constructor. Not called directly. Use the factory.
801
FileOpenDialogImpl::FileOpenDialogImpl(char const *dir,
802
FileDialogType fileTypes,
804
Gtk::FileChooserDialog(Glib::ustring(title))
808
/* One file at a time */
809
/* And also Multiple Files */
810
set_select_multiple(true);
812
/* Initalize to Autodetect */
814
/* No filename to start out with */
817
/* Set our dialog type (open, import, etc...)*/
818
dialogType = fileTypes;
821
/* Set the pwd and/or the filename */
824
Glib::ustring udir(dir);
825
Glib::ustring::size_type len = udir.length();
826
// leaving a trailing backslash on the directory name leads to the infamous
827
// double-directory bug on win32
828
if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
829
set_current_folder(udir.c_str());
832
//###### Add the file types menu
835
//###### Add a preview widget
836
set_preview_widget(svgPreview);
837
set_preview_widget_active(true);
838
set_use_preview_label (false);
840
//Catch selection-changed events, so we can adjust the text widget
841
signal_update_preview().connect(
842
sigc::mem_fun(*this, &FileOpenDialogImpl::updatePreviewCallback) );
845
//###### Add a text entry bar, and tie it to file chooser events
846
fileNameEntry.set_text(get_current_folder());
847
set_extra_widget(fileNameEntry);
848
fileNameEntry.grab_focus();
850
//Catch when user hits [return] on the text field
851
fileNameEntry.signal_activate().connect(
852
sigc::mem_fun(*this, &FileOpenDialogImpl::fileNameEntryChangedCallback) );
854
//Catch selection-changed events, so we can adjust the text widget
855
signal_selection_changed().connect(
856
sigc::mem_fun(*this, &FileOpenDialogImpl::fileSelectedCallback) );
858
add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
859
add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
868
* Public factory. Called by file.cpp, among others.
870
FileOpenDialog *FileOpenDialog::create(char const *path,
871
FileDialogType fileTypes,
874
FileOpenDialog *dialog = new FileOpenDialogImpl(path, fileTypes, title);
884
FileOpenDialogImpl::~FileOpenDialogImpl()
891
* Show this dialog modally. Return true if user hits [OK]
894
FileOpenDialogImpl::show()
896
set_current_folder(get_current_folder()); //hack to force initial dir listing
897
set_modal (TRUE); //Window
898
sp_transientize((GtkWidget *)gobj()); //Make transient
899
gint b = run(); //Dialog
902
if (b == Gtk::RESPONSE_OK)
904
//This is a hack, to avoid the warning messages that
905
//Gtk::FileChooser::get_filter() returns
906
//should be: Gtk::FileFilter *filter = get_filter();
907
GtkFileChooser *gtkFileChooser = Gtk::FileChooser::gobj();
908
GtkFileFilter *filter = gtk_file_chooser_get_filter(gtkFileChooser);
911
//Get which extension was chosen, if any
912
extension = extensionMap[gtk_file_filter_get_name(filter)];
914
myFilename = get_filename();
927
* Get the file extension type that was selected by the user. Valid after an [OK]
929
Inkscape::Extension::Extension *
930
FileOpenDialogImpl::getSelectionType()
937
* Get the file name chosen by the user. Valid after an [OK]
940
FileOpenDialogImpl::getFilename (void)
942
return g_strdup(myFilename.c_str());
947
* To Get Multiple filenames selected at-once.
949
Glib::SListHandle<Glib::ustring>FileOpenDialogImpl::getFilenames()
951
return get_filenames();
959
/*#########################################################################
961
#########################################################################*/
969
Glib::ustring pattern;
970
Inkscape::Extension::Extension *extension;
974
* Our implementation of the FileSaveDialog interface.
976
class FileSaveDialogImpl : public FileSaveDialog, public Gtk::FileChooserDialog
980
FileSaveDialogImpl(char const *dir,
981
FileDialogType fileTypes,
983
char const *default_key);
985
virtual ~FileSaveDialogImpl();
989
Inkscape::Extension::Extension *getSelectionType();
991
gchar *getFilename();
997
* What type of 'open' are we? (save, export, etc)
999
FileDialogType dialogType;
1002
* Our svg preview widget
1004
SVGPreview svgPreview;
1007
* Fix to allow the user to type the file name
1009
Gtk::Entry *fileNameEntry;
1012
* Callback for seeing if the preview needs to be drawn
1014
void updatePreviewCallback();
1019
* Allow the specification of the output file type
1021
Gtk::HBox fileTypeBox;
1024
* Allow the specification of the output file type
1026
Gtk::ComboBoxText fileTypeComboBox;
1030
* Data mirror of the combo box
1032
std::vector<FileType> fileTypes;
1035
Gtk::CheckButton fileTypeCheckbox;
1039
* Callback for user input into fileNameEntry
1041
void fileTypeChangedCallback();
1044
* Create a filter menu for this type of dialog
1046
void createFileTypeMenu();
1049
bool append_extension;
1052
* The extension to use to write this file
1054
Inkscape::Extension::Extension *extension;
1057
* Callback for user input into fileNameEntry
1059
void fileNameEntryChangedCallback();
1062
* Filename that was given
1064
Glib::ustring myFilename;
1073
* Callback for checking if the preview needs to be redrawn
1075
void FileSaveDialogImpl::updatePreviewCallback()
1077
Glib::ustring fileName = get_preview_filename();
1078
if (!fileName.c_str())
1080
bool retval = svgPreview.set(fileName, dialogType);
1081
set_preview_widget_active(retval);
1087
* Callback for fileNameEntry widget
1089
void FileSaveDialogImpl::fileNameEntryChangedCallback()
1094
Glib::ustring fileName = fileNameEntry->get_text();
1095
if (!Glib::get_charset()) //If we are not utf8
1096
fileName = Glib::filename_to_utf8(fileName);
1098
//g_message("User hit return. Text is '%s'\n", fileName.c_str());
1100
if (!Glib::path_is_absolute(fileName)) {
1101
//try appending to the current path
1102
// not this way: fileName = get_current_folder() + "/" + fileName;
1103
std::vector<Glib::ustring> pathSegments;
1104
pathSegments.push_back( get_current_folder() );
1105
pathSegments.push_back( fileName );
1106
fileName = Glib::build_filename(pathSegments);
1109
//g_message("path:'%s'\n", fileName.c_str());
1111
if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
1112
set_current_folder(fileName);
1113
} else if (/*Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR)*/1) {
1114
//dialog with either (1) select a regular file or (2) cd to dir
1116
set_filename(fileName);
1117
response(Gtk::RESPONSE_OK);
1124
* Callback for fileNameEntry widget
1126
void FileSaveDialogImpl::fileTypeChangedCallback()
1128
int sel = fileTypeComboBox.get_active_row_number();
1129
if (sel<0 || sel >= (int)fileTypes.size())
1131
FileType type = fileTypes[sel];
1132
//g_message("selected: %s\n", type.name.c_str());
1133
Gtk::FileFilter filter;
1134
filter.add_pattern(type.pattern);
1140
void FileSaveDialogImpl::createFileTypeMenu()
1142
Inkscape::Extension::DB::OutputList extension_list;
1143
Inkscape::Extension::db.get_output_list(extension_list);
1145
for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
1146
current_item != extension_list.end(); current_item++)
1148
Inkscape::Extension::Output * omod = *current_item;
1150
// FIXME: would be nice to grey them out instead of not listing them
1151
if (omod->deactivated()) continue;
1154
type.name = (_(omod->get_filetypename()));
1156
FileDialogExtensionToPattern (type.pattern, omod->get_extension());
1157
type.extension= omod;
1158
fileTypeComboBox.append_text(type.name);
1159
fileTypes.push_back(type);
1164
guessType.name = _("Guess from extension");
1165
guessType.pattern = "*";
1166
guessType.extension = NULL;
1167
fileTypeComboBox.append_text(guessType.name);
1168
fileTypes.push_back(guessType);
1171
fileTypeComboBox.set_active(0);
1172
fileTypeChangedCallback(); //call at least once to set the filter
1176
void findEntryWidgets(Gtk::Container *parent, std::vector<Gtk::Entry *> &result)
1180
std::vector<Gtk::Widget *> children = parent->get_children();
1181
for (unsigned int i=0; i<children.size() ; i++)
1183
Gtk::Widget *child = children[i];
1184
GtkWidget *wid = child->gobj();
1185
if (GTK_IS_ENTRY(wid))
1186
result.push_back((Gtk::Entry *)child);
1187
else if (GTK_IS_CONTAINER(wid))
1188
findEntryWidgets((Gtk::Container *)child, result);
1193
void findExpanderWidgets(Gtk::Container *parent, std::vector<Gtk::Expander *> &result)
1197
std::vector<Gtk::Widget *> children = parent->get_children();
1198
for (unsigned int i=0; i<children.size() ; i++)
1200
Gtk::Widget *child = children[i];
1201
GtkWidget *wid = child->gobj();
1202
if (GTK_IS_EXPANDER(wid))
1203
result.push_back((Gtk::Expander *)child);
1204
else if (GTK_IS_CONTAINER(wid))
1205
findExpanderWidgets((Gtk::Container *)child, result);
1214
FileSaveDialogImpl::FileSaveDialogImpl(char const *dir,
1215
FileDialogType fileTypes,
1217
char const *default_key) :
1218
Gtk::FileChooserDialog(Glib::ustring(title),
1219
Gtk::FILE_CHOOSER_ACTION_SAVE)
1221
append_extension = (bool)prefs_get_int_attribute("dialogs.save_as", "append_extension", 1);
1223
/* One file at a time */
1224
set_select_multiple(false);
1226
/* Initalize to Autodetect */
1228
/* No filename to start out with */
1231
/* Set our dialog type (save, export, etc...)*/
1232
dialogType = fileTypes;
1234
/* Set the pwd and/or the filename */
1237
Glib::ustring udir(dir);
1238
Glib::ustring::size_type len = udir.length();
1239
// leaving a trailing backslash on the directory name leads to the infamous
1240
// double-directory bug on win32
1241
if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1);
1242
set_current_folder(udir.c_str());
1245
//###### Add the file types menu
1246
//createFilterMenu();
1248
//###### Do we want the .xxx extension automatically added?
1249
fileTypeCheckbox.set_label(Glib::ustring(_("Append filename extension automatically")));
1250
fileTypeCheckbox.set_active(append_extension);
1252
fileTypeBox.pack_start(fileTypeCheckbox);
1253
createFileTypeMenu();
1254
fileTypeComboBox.set_size_request(200,40);
1255
fileTypeComboBox.signal_changed().connect(
1256
sigc::mem_fun(*this, &FileSaveDialogImpl::fileTypeChangedCallback) );
1258
fileTypeBox.pack_start(fileTypeComboBox);
1260
set_extra_widget(fileTypeBox);
1261
//get_vbox()->pack_start(fileTypeBox, false, false, 0);
1262
//get_vbox()->reorder_child(fileTypeBox, 2);
1264
//###### Add a preview widget
1265
set_preview_widget(svgPreview);
1266
set_preview_widget_active(true);
1267
set_use_preview_label (false);
1269
//Catch selection-changed events, so we can adjust the text widget
1270
signal_update_preview().connect(
1271
sigc::mem_fun(*this, &FileSaveDialogImpl::updatePreviewCallback) );
1274
//Let's do some customization
1275
fileNameEntry = NULL;
1276
Gtk::Container *cont = get_toplevel();
1277
std::vector<Gtk::Entry *> entries;
1278
findEntryWidgets(cont, entries);
1279
//g_message("Found %d entry widgets\n", entries.size());
1280
if (entries.size() >=1 )
1282
//Catch when user hits [return] on the text field
1283
fileNameEntry = entries[0];
1284
fileNameEntry->signal_activate().connect(
1285
sigc::mem_fun(*this, &FileSaveDialogImpl::fileNameEntryChangedCallback) );
1288
//Let's do more customization
1289
std::vector<Gtk::Expander *> expanders;
1290
findExpanderWidgets(cont, expanders);
1291
//g_message("Found %d expander widgets\n", expanders.size());
1292
if (expanders.size() >=1 )
1294
//Always show the file list
1295
Gtk::Expander *expander = expanders[0];
1296
expander->set_expanded(true);
1300
//if (extension == NULL)
1301
// checkbox.set_sensitive(FALSE);
1303
add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1304
add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1306
show_all_children();
1312
* Public factory method. Used in file.cpp
1314
FileSaveDialog *FileSaveDialog::create(char const *path,
1315
FileDialogType fileTypes,
1317
char const *default_key)
1319
FileSaveDialog *dialog = new FileSaveDialogImpl(path, fileTypes, title, default_key);
1330
FileSaveDialogImpl::~FileSaveDialogImpl()
1338
* Show this dialog modally. Return true if user hits [OK]
1341
FileSaveDialogImpl::show()
1343
set_current_folder(get_current_folder()); //hack to force initial dir listing
1344
set_modal (TRUE); //Window
1345
sp_transientize((GtkWidget *)gobj()); //Make transient
1346
gint b = run(); //Dialog
1349
if (b == Gtk::RESPONSE_OK)
1351
int sel = fileTypeComboBox.get_active_row_number ();
1352
if (sel>=0 && sel< (int)fileTypes.size())
1354
FileType &type = fileTypes[sel];
1355
extension = type.extension;
1357
myFilename = get_filename();
1361
// FIXME: Why do we have more code
1363
append_extension = checkbox.get_active();
1364
prefs_set_int_attribute("dialogs.save_as", "append_extension", append_extension);
1365
prefs_set_string_attribute("dialogs.save_as", "default",
1366
( extension != NULL ? extension->get_id() : "" ));
1378
* Get the file extension type that was selected by the user. Valid after an [OK]
1380
Inkscape::Extension::Extension *
1381
FileSaveDialogImpl::getSelectionType()
1388
* Get the file name chosen by the user. Valid after an [OK]
1391
FileSaveDialogImpl::getFilename()
1393
return g_strdup(myFilename.c_str());
1397
\brief A quick function to turn a standard extension into a searchable
1398
pattern for the file dialogs
1399
\param pattern The patter that the extension should be written to
1400
\param in_file_extension The C string that represents the extension
1402
This function just goes through the string, and takes all characters
1403
and puts a [<upper><lower>] so that both are searched and shown in
1404
the file dialog. This function edits the pattern string to make
1408
FileDialogExtensionToPattern (Glib::ustring &pattern, gchar * in_file_extension)
1410
Glib::ustring tmp(in_file_extension);
1412
for ( guint i = 0; i < tmp.length(); i++ ) {
1413
Glib::ustring::value_type ch = tmp.at(i);
1414
if ( Glib::Unicode::isalpha(ch) ) {
1416
pattern += Glib::Unicode::toupper(ch);
1417
pattern += Glib::Unicode::tolower(ch);
1425
} //namespace Dialogs
1427
} //namespace Inkscape
1433
c-file-style:"stroustrup"
1434
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1435
indent-tabs-mode:nil
1439
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :