~vaifrax/inkscape/bugfix170049

« back to all changes in this revision

Viewing changes to src/dialogs/filedialog.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
12
 
 
13
#ifdef HAVE_CONFIG_H
 
14
# include <config.h>
 
15
#endif
 
16
 
 
17
 
 
18
 
 
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>
 
23
 
 
24
//Another hack
 
25
#include <gtk/gtkentry.h>
 
26
#include <gtk/gtkexpander.h>
 
27
 
 
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>
 
39
 
 
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
 
 
49
#undef INK_DUMP_FILENAME_CONV
 
50
 
 
51
#ifdef INK_DUMP_FILENAME_CONV
 
52
void dump_str( const gchar* str, const gchar* prefix );
 
53
void dump_ustr( const Glib::ustring& ustr );
 
54
#endif
 
55
 
 
56
namespace Inkscape {
 
57
namespace UI {
 
58
namespace Dialogs {
 
59
 
 
60
void FileDialogExtensionToPattern (Glib::ustring &pattern, gchar * in_file_extension);
 
61
 
 
62
/*#########################################################################
 
63
### SVG Preview Widget
 
64
#########################################################################*/
 
65
/**
 
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.
 
69
 */
 
70
class SVGPreview : public Gtk::VBox
 
71
{
 
72
public:
 
73
    SVGPreview();
 
74
    ~SVGPreview();
 
75
 
 
76
    bool setDocument(SPDocument *doc);
 
77
 
 
78
    bool setFileName(Glib::ustring &fileName);
 
79
 
 
80
    bool setFromMem(char const *xmlBuffer);
 
81
 
 
82
    bool set(Glib::ustring &fileName, int dialogType);
 
83
 
 
84
    bool setURI(URI &uri);
 
85
 
 
86
    /**
 
87
     * Show image embedded in SVG
 
88
     */
 
89
    void showImage(Glib::ustring &fileName);
 
90
 
 
91
    /**
 
92
     * Show the "No preview" image
 
93
     */
 
94
    void showNoPreview();
 
95
 
 
96
    /**
 
97
     * Show the "Too large" image
 
98
     */
 
99
    void showTooLarge(long fileLength);
 
100
 
 
101
private:
 
102
    /**
 
103
     * The svg document we are currently showing
 
104
     */
 
105
    SPDocument *document;
 
106
 
 
107
    /**
 
108
     * The sp_svg_view widget
 
109
     */
 
110
    GtkWidget *viewerGtk;
 
111
 
 
112
    /**
 
113
     * are we currently showing the "no preview" image?
 
114
     */
 
115
    bool showingNoPreview;
 
116
 
 
117
};
 
118
 
 
119
 
 
120
bool SVGPreview::setDocument(SPDocument *doc)
 
121
{
 
122
    if (document)
 
123
        sp_document_unref(document);
 
124
 
 
125
    sp_document_ref(doc);
 
126
    document = doc;
 
127
 
 
128
    //This should remove it from the box, and free resources
 
129
    if (viewerGtk) {
 
130
        gtk_widget_destroy(viewerGtk);
 
131
    }
 
132
 
 
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);
 
137
 
 
138
    return true;
 
139
}
 
140
 
 
141
bool SVGPreview::setFileName(Glib::ustring &theFileName)
 
142
{
 
143
    Glib::ustring fileName = theFileName;
 
144
 
 
145
    fileName = Glib::filename_to_utf8(fileName);
 
146
 
 
147
    SPDocument *doc = sp_document_new (fileName.c_str(), 0);
 
148
    if (!doc) {
 
149
        g_warning("SVGView: error loading document '%s'\n", fileName.c_str());
 
150
        return false;
 
151
    }
 
152
 
 
153
    setDocument(doc);
 
154
 
 
155
    sp_document_unref(doc);
 
156
 
 
157
    return true;
 
158
}
 
159
 
 
160
 
 
161
 
 
162
bool SVGPreview::setFromMem(char const *xmlBuffer)
 
163
{
 
164
    if (!xmlBuffer)
 
165
        return false;
 
166
 
 
167
    gint len = (gint)strlen(xmlBuffer);
 
168
    SPDocument *doc = sp_document_new_from_mem(xmlBuffer, len, 0);
 
169
    if (!doc) {
 
170
        g_warning("SVGView: error loading buffer '%s'\n",xmlBuffer);
 
171
        return false;
 
172
    }
 
173
 
 
174
    setDocument(doc);
 
175
 
 
176
    sp_document_unref(doc);
 
177
 
 
178
    return true;
 
179
}
 
180
 
 
181
 
 
182
 
 
183
void SVGPreview::showImage(Glib::ustring &theFileName)
 
184
{
 
185
    Glib::ustring fileName = theFileName;
 
186
 
 
187
 
 
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
 
192
    # display it nicely?
 
193
    #####################################*/
 
194
 
 
195
    //Arbitrary size of svg doc -- rather 'portrait' shaped
 
196
    gint previewWidth  = 400;
 
197
    gint previewHeight = 600;
 
198
 
 
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();
 
203
 
 
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;
 
210
 
 
211
    //Now get the resized values
 
212
    gint scaledImgWidth  = (int) (scaleFactor * (double)imgWidth);
 
213
    gint scaledImgHeight = (int) (scaleFactor * (double)imgHeight);
 
214
 
 
215
    //center the image on the area
 
216
    gint imgX = (previewWidth  - scaledImgWidth)  / 2;
 
217
    gint imgY = (previewHeight - scaledImgHeight) / 2;
 
218
 
 
219
    //wrap a rectangle around the image
 
220
    gint rectX      = imgX-1;
 
221
    gint rectY      = imgY-1;
 
222
    gint rectWidth  = scaledImgWidth +2;
 
223
    gint rectHeight = scaledImgHeight+2;
 
224
 
 
225
    //Our template.  Modify to taste
 
226
    gchar const *xformat =
 
227
          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
228
          "<svg\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"
 
232
          "<rect\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"
 
237
          "<rect\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"
 
243
          "<text\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"
 
248
          "</svg>\n\n";
 
249
 
 
250
    //if (!Glib::get_charset()) //If we are not utf8
 
251
    fileName = Glib::filename_to_utf8(fileName);
 
252
 
 
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,
 
258
           fileName.c_str(),
 
259
           rectX, rectY, rectWidth, rectHeight,
 
260
           imgWidth, imgHeight);
 
261
 
 
262
    //g_message("%s\n", xmlBuffer);
 
263
 
 
264
    //now show it!
 
265
    setFromMem(xmlBuffer);
 
266
    g_free(xmlBuffer);
 
267
}
 
268
 
 
269
 
 
270
 
 
271
void SVGPreview::showNoPreview()
 
272
{
 
273
    //Are we already showing it?
 
274
    if (showingNoPreview)
 
275
        return;
 
276
 
 
277
    //Arbitrary size of svg doc -- rather 'portrait' shaped
 
278
    gint previewWidth  = 300;
 
279
    gint previewHeight = 600;
 
280
 
 
281
    //Our template.  Modify to taste
 
282
    gchar const *xformat =
 
283
          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
284
          "<svg\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"
 
289
          "<path\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"
 
294
          "<path\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"
 
300
          "<path\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"
 
307
          "<path\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"
 
313
          "<path\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"
 
351
          "</svg>\n\n";
 
352
 
 
353
    //Fill in the template
 
354
    gchar *xmlBuffer = g_strdup_printf(xformat,
 
355
           previewWidth, previewHeight, _("No preview"));
 
356
 
 
357
    //g_message("%s\n", xmlBuffer);
 
358
 
 
359
    //now show it!
 
360
    setFromMem(xmlBuffer);
 
361
    g_free(xmlBuffer);
 
362
    showingNoPreview = true;
 
363
 
 
364
}
 
365
 
 
366
void SVGPreview::showTooLarge(long fileLength)
 
367
{
 
368
 
 
369
    //Arbitrary size of svg doc -- rather 'portrait' shaped
 
370
    gint previewWidth  = 300;
 
371
    gint previewHeight = 600;
 
372
 
 
373
    //Our template.  Modify to taste
 
374
    gchar const *xformat =
 
375
          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
376
          "<svg\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"
 
381
          "<path\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"
 
386
          "<path\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"
 
392
          "<path\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"
 
399
          "<path\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"
 
405
          "<path\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"
 
436
          "</g>\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"
 
449
          "</svg>\n\n";
 
450
 
 
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"));
 
457
 
 
458
    //g_message("%s\n", xmlBuffer);
 
459
 
 
460
    //now show it!
 
461
    setFromMem(xmlBuffer);
 
462
    g_free(xmlBuffer);
 
463
 
 
464
}
 
465
 
 
466
static bool
 
467
hasSuffix(Glib::ustring &str, Glib::ustring &ext)
 
468
{
 
469
    int strLen = str.length();
 
470
    int extLen = ext.length();
 
471
    if (extLen > strLen)
 
472
    {
 
473
        return false;
 
474
    }
 
475
    int strpos = strLen-1;
 
476
    for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
 
477
    {
 
478
        Glib::ustring::value_type ch = str[strpos];
 
479
        if (ch != ext[extpos])
 
480
        {
 
481
            if ( ((ch & 0xff80) != 0) ||
 
482
                 static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
 
483
            {
 
484
                return false;
 
485
            }
 
486
        }
 
487
    }
 
488
    return true;
 
489
}
 
490
 
 
491
 
 
492
/**
 
493
 * Return true if the image is loadable by Gdk, else false
 
494
 */
 
495
static bool
 
496
isValidImageFile(Glib::ustring &fileName)
 
497
{
 
498
    std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
 
499
    for (unsigned int i=0; i<formats.size(); i++)
 
500
        {
 
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++)
 
504
            {
 
505
            Glib::ustring ext = extensions[j];
 
506
            if (hasSuffix(fileName, ext))
 
507
                {
 
508
                return true;
 
509
                }
 
510
            }
 
511
        }
 
512
    return false;
 
513
}
 
514
 
 
515
bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
 
516
{
 
517
 
 
518
    if (!Glib::file_test(fileName, Glib::FILE_TEST_EXISTS))
 
519
        return false;
 
520
 
 
521
    gchar *fName = (gchar *)fileName.c_str();
 
522
    //g_message("fname:%s\n", fName);
 
523
 
 
524
 
 
525
    if (Glib::file_test(fileName, Glib::FILE_TEST_IS_REGULAR))
 
526
        {
 
527
        struct stat info;
 
528
        if (stat(fName, &info))
 
529
            {
 
530
            return FALSE;
 
531
            }
 
532
        long fileLen = info.st_size;
 
533
        if (fileLen > 0x150000L)
 
534
            {
 
535
            showingNoPreview = false;
 
536
            showTooLarge(fileLen);
 
537
            return FALSE;
 
538
            }
 
539
        }
 
540
 
 
541
    Glib::ustring svg = ".svg";
 
542
    Glib::ustring svgz = ".svgz";
 
543
 
 
544
    if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
 
545
           (hasSuffix(fileName, svg) || hasSuffix(fileName, svgz)   )
 
546
         )
 
547
        {
 
548
        bool retval = setFileName(fileName);
 
549
        showingNoPreview = false;
 
550
        return retval;
 
551
        }
 
552
    else if (isValidImageFile(fileName))
 
553
        {
 
554
        showImage(fileName);
 
555
        showingNoPreview = false;
 
556
        return true;
 
557
        }
 
558
    else
 
559
        {
 
560
        showNoPreview();
 
561
        return false;
 
562
        }
 
563
}
 
564
 
 
565
 
 
566
SVGPreview::SVGPreview()
 
567
{
 
568
    if (!INKSCAPE)
 
569
        inkscape_application_init("",false);
 
570
    document = NULL;
 
571
    viewerGtk = NULL;
 
572
    set_size_request(150,150);
 
573
    showingNoPreview = false;
 
574
}
 
575
 
 
576
SVGPreview::~SVGPreview()
 
577
{
 
578
 
 
579
}
 
580
 
 
581
 
 
582
 
 
583
 
 
584
 
 
585
/*#########################################################################
 
586
### F I L E    O P E N
 
587
#########################################################################*/
 
588
 
 
589
/**
 
590
 * Our implementation class for the FileOpenDialog interface..
 
591
 */
 
592
class FileOpenDialogImpl : public FileOpenDialog, public Gtk::FileChooserDialog
 
593
{
 
594
public:
 
595
    FileOpenDialogImpl(char const *dir,
 
596
                       FileDialogType fileTypes,
 
597
                       char const *title);
 
598
 
 
599
    virtual ~FileOpenDialogImpl();
 
600
 
 
601
    bool show();
 
602
 
 
603
    Inkscape::Extension::Extension *getSelectionType();
 
604
 
 
605
    gchar *getFilename();
 
606
 
 
607
    Glib::SListHandle<Glib::ustring> getFilenames ();
 
608
protected:
 
609
 
 
610
 
 
611
 
 
612
private:
 
613
 
 
614
 
 
615
    /**
 
616
     * What type of 'open' are we? (open, import, place, etc)
 
617
     */
 
618
    FileDialogType dialogType;
 
619
 
 
620
    /**
 
621
     * Our svg preview widget
 
622
     */
 
623
    SVGPreview svgPreview;
 
624
 
 
625
    /**
 
626
     * Callback for seeing if the preview needs to be drawn
 
627
     */
 
628
    void updatePreviewCallback();
 
629
 
 
630
    /**
 
631
     * Fix to allow the user to type the file name
 
632
     */
 
633
    Gtk::Entry fileNameEntry;
 
634
 
 
635
    /**
 
636
     *  Create a filter menu for this type of dialog
 
637
     */
 
638
    void createFilterMenu();
 
639
 
 
640
    /**
 
641
     * Callback for user input into fileNameEntry
 
642
     */
 
643
    void fileNameEntryChangedCallback();
 
644
 
 
645
    /**
 
646
     * Callback for user changing which item is selected on the list
 
647
     */
 
648
    void fileSelectedCallback();
 
649
 
 
650
 
 
651
    /**
 
652
     * Filter name->extension lookup
 
653
     */
 
654
    std::map<Glib::ustring, Inkscape::Extension::Extension *> extensionMap;
 
655
 
 
656
    /**
 
657
     * The extension to use to write this file
 
658
     */
 
659
    Inkscape::Extension::Extension *extension;
 
660
 
 
661
    /**
 
662
     * Filename that was given
 
663
     */
 
664
    Glib::ustring myFilename;
 
665
 
 
666
};
 
667
 
 
668
 
 
669
 
 
670
 
 
671
 
 
672
/**
 
673
 * Callback for checking if the preview needs to be redrawn
 
674
 */
 
675
void FileOpenDialogImpl::updatePreviewCallback()
 
676
{
 
677
    Glib::ustring fileName = get_preview_filename();
 
678
 
 
679
    if (fileName.length() < 1)
 
680
        return;
 
681
 
 
682
    svgPreview.set(fileName, dialogType);
 
683
}
 
684
 
 
685
 
 
686
 
 
687
 
 
688
 
 
689
/**
 
690
 * Callback for fileNameEntry widget
 
691
 */
 
692
void FileOpenDialogImpl::fileNameEntryChangedCallback()
 
693
{
 
694
    Glib::ustring fileName = fileNameEntry.get_text();
 
695
 
 
696
    // TODO remove this leak
 
697
    fileName = Glib::filename_from_utf8(fileName);
 
698
 
 
699
    //g_message("User hit return.  Text is '%s'\n", fName.c_str());
 
700
 
 
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);
 
708
    }
 
709
 
 
710
    //g_message("path:'%s'\n", fName.c_str());
 
711
 
 
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
 
716
        //simulate an 'OK'
 
717
        set_filename(fileName);
 
718
        response(Gtk::RESPONSE_OK);
 
719
    }
 
720
}
 
721
 
 
722
 
 
723
 
 
724
 
 
725
 
 
726
/**
 
727
 * Callback for fileNameEntry widget
 
728
 */
 
729
void FileOpenDialogImpl::fileSelectedCallback()
 
730
{
 
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());
 
736
 
 
737
#ifdef INK_DUMP_FILENAME_CONV
 
738
    ::dump_ustr( get_filename() );
 
739
#endif
 
740
    fileNameEntry.set_text(fileName);
 
741
}
 
742
 
 
743
 
 
744
 
 
745
 
 
746
void FileOpenDialogImpl::createFilterMenu()
 
747
{
 
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);
 
753
 
 
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);
 
759
 
 
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);
 
765
 
 
766
    Inkscape::Extension::DB::InputList extension_list;
 
767
    Inkscape::Extension::db.get_input_list(extension_list);
 
768
 
 
769
    for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
 
770
         current_item != extension_list.end(); current_item++)
 
771
    {
 
772
        Inkscape::Extension::Input * imod = *current_item;
 
773
 
 
774
        // FIXME: would be nice to grey them out instead of not listing them
 
775
        if (imod->deactivated()) continue;
 
776
 
 
777
        Glib::ustring upattern("*");
 
778
        FileDialogExtensionToPattern (upattern, imod->get_extension());
 
779
 
 
780
        Gtk::FileFilter filter;
 
781
        Glib::ustring uname(_(imod->get_filetypename()));
 
782
        filter.set_name(uname);
 
783
        filter.add_pattern(upattern);
 
784
        add_filter(filter);
 
785
        extensionMap[uname] = imod;
 
786
 
 
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);
 
791
    }
 
792
 
 
793
    return;
 
794
}
 
795
 
 
796
 
 
797
 
 
798
/**
 
799
 * Constructor.  Not called directly.  Use the factory.
 
800
 */
 
801
FileOpenDialogImpl::FileOpenDialogImpl(char const *dir,
 
802
                                       FileDialogType fileTypes,
 
803
                                       char const *title) :
 
804
                 Gtk::FileChooserDialog(Glib::ustring(title))
 
805
{
 
806
 
 
807
 
 
808
    /* One file at a time */
 
809
    /* And also Multiple Files */
 
810
    set_select_multiple(true);
 
811
 
 
812
    /* Initalize to Autodetect */
 
813
    extension = NULL;
 
814
    /* No filename to start out with */
 
815
    myFilename = "";
 
816
 
 
817
    /* Set our dialog type (open, import, etc...)*/
 
818
    dialogType = fileTypes;
 
819
 
 
820
 
 
821
    /* Set the pwd and/or the filename */
 
822
    if (dir != NULL)
 
823
    {
 
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());
 
830
    }
 
831
 
 
832
    //###### Add the file types menu
 
833
    createFilterMenu();
 
834
 
 
835
    //###### Add a preview widget
 
836
    set_preview_widget(svgPreview);
 
837
    set_preview_widget_active(true);
 
838
    set_use_preview_label (false);
 
839
 
 
840
    //Catch selection-changed events, so we can adjust the text widget
 
841
    signal_update_preview().connect(
 
842
         sigc::mem_fun(*this, &FileOpenDialogImpl::updatePreviewCallback) );
 
843
 
 
844
 
 
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();
 
849
 
 
850
    //Catch when user hits [return] on the text field
 
851
    fileNameEntry.signal_activate().connect(
 
852
         sigc::mem_fun(*this, &FileOpenDialogImpl::fileNameEntryChangedCallback) );
 
853
 
 
854
    //Catch selection-changed events, so we can adjust the text widget
 
855
    signal_selection_changed().connect(
 
856
         sigc::mem_fun(*this, &FileOpenDialogImpl::fileSelectedCallback) );
 
857
 
 
858
    add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
 
859
    add_button(Gtk::Stock::OPEN,   Gtk::RESPONSE_OK);
 
860
 
 
861
}
 
862
 
 
863
 
 
864
 
 
865
 
 
866
 
 
867
/**
 
868
 * Public factory.  Called by file.cpp, among others.
 
869
 */
 
870
FileOpenDialog *FileOpenDialog::create(char const *path,
 
871
                                       FileDialogType fileTypes,
 
872
                                       char const *title)
 
873
{
 
874
    FileOpenDialog *dialog = new FileOpenDialogImpl(path, fileTypes, title);
 
875
    return dialog;
 
876
}
 
877
 
 
878
 
 
879
 
 
880
 
 
881
/**
 
882
 * Destructor
 
883
 */
 
884
FileOpenDialogImpl::~FileOpenDialogImpl()
 
885
{
 
886
 
 
887
}
 
888
 
 
889
 
 
890
/**
 
891
 * Show this dialog modally.  Return true if user hits [OK]
 
892
 */
 
893
bool
 
894
FileOpenDialogImpl::show()
 
895
{
 
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
 
900
    hide();
 
901
 
 
902
    if (b == Gtk::RESPONSE_OK)
 
903
        {
 
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);
 
909
        if (filter)
 
910
            {
 
911
            //Get which extension was chosen, if any
 
912
            extension = extensionMap[gtk_file_filter_get_name(filter)];
 
913
            }
 
914
        myFilename = get_filename();
 
915
        return TRUE;
 
916
        }
 
917
    else
 
918
       {
 
919
       return FALSE;
 
920
       }
 
921
}
 
922
 
 
923
 
 
924
 
 
925
 
 
926
/**
 
927
 * Get the file extension type that was selected by the user. Valid after an [OK]
 
928
 */
 
929
Inkscape::Extension::Extension *
 
930
FileOpenDialogImpl::getSelectionType()
 
931
{
 
932
    return extension;
 
933
}
 
934
 
 
935
 
 
936
/**
 
937
 * Get the file name chosen by the user.   Valid after an [OK]
 
938
 */
 
939
gchar *
 
940
FileOpenDialogImpl::getFilename (void)
 
941
{
 
942
    return g_strdup(myFilename.c_str());
 
943
}
 
944
 
 
945
 
 
946
/**
 
947
 * To Get Multiple filenames selected at-once.
 
948
 */
 
949
Glib::SListHandle<Glib::ustring>FileOpenDialogImpl::getFilenames()
 
950
{    
 
951
    return get_filenames();
 
952
}
 
953
 
 
954
 
 
955
 
 
956
 
 
957
 
 
958
 
 
959
/*#########################################################################
 
960
# F I L E    S A V E
 
961
#########################################################################*/
 
962
 
 
963
class FileType
 
964
{
 
965
    public:
 
966
    FileType() {}
 
967
    ~FileType() {}
 
968
    Glib::ustring name;
 
969
    Glib::ustring pattern;
 
970
    Inkscape::Extension::Extension *extension;
 
971
};
 
972
 
 
973
/**
 
974
 * Our implementation of the FileSaveDialog interface.
 
975
 */
 
976
class FileSaveDialogImpl : public FileSaveDialog, public Gtk::FileChooserDialog
 
977
{
 
978
 
 
979
public:
 
980
    FileSaveDialogImpl(char const *dir,
 
981
                       FileDialogType fileTypes,
 
982
                       char const *title,
 
983
                       char const *default_key);
 
984
 
 
985
    virtual ~FileSaveDialogImpl();
 
986
 
 
987
    bool show();
 
988
 
 
989
    Inkscape::Extension::Extension *getSelectionType();
 
990
 
 
991
    gchar *getFilename();
 
992
 
 
993
 
 
994
private:
 
995
 
 
996
    /**
 
997
     * What type of 'open' are we? (save, export, etc)
 
998
     */
 
999
    FileDialogType dialogType;
 
1000
 
 
1001
    /**
 
1002
     * Our svg preview widget
 
1003
     */
 
1004
    SVGPreview svgPreview;
 
1005
 
 
1006
    /**
 
1007
     * Fix to allow the user to type the file name
 
1008
     */
 
1009
    Gtk::Entry *fileNameEntry;
 
1010
 
 
1011
    /**
 
1012
     * Callback for seeing if the preview needs to be drawn
 
1013
     */
 
1014
    void updatePreviewCallback();
 
1015
 
 
1016
 
 
1017
 
 
1018
    /**
 
1019
     * Allow the specification of the output file type
 
1020
     */
 
1021
    Gtk::HBox fileTypeBox;
 
1022
 
 
1023
    /**
 
1024
     * Allow the specification of the output file type
 
1025
     */
 
1026
    Gtk::ComboBoxText fileTypeComboBox;
 
1027
 
 
1028
 
 
1029
    /**
 
1030
     *  Data mirror of the combo box
 
1031
     */
 
1032
    std::vector<FileType> fileTypes;
 
1033
 
 
1034
    //# Child widgets
 
1035
    Gtk::CheckButton fileTypeCheckbox;
 
1036
 
 
1037
 
 
1038
    /**
 
1039
     * Callback for user input into fileNameEntry
 
1040
     */
 
1041
    void fileTypeChangedCallback();
 
1042
 
 
1043
    /**
 
1044
     *  Create a filter menu for this type of dialog
 
1045
     */
 
1046
    void createFileTypeMenu();
 
1047
 
 
1048
 
 
1049
    bool append_extension;
 
1050
 
 
1051
    /**
 
1052
     * The extension to use to write this file
 
1053
     */
 
1054
    Inkscape::Extension::Extension *extension;
 
1055
 
 
1056
    /**
 
1057
     * Callback for user input into fileNameEntry
 
1058
     */
 
1059
    void fileNameEntryChangedCallback();
 
1060
 
 
1061
    /**
 
1062
     * Filename that was given
 
1063
     */
 
1064
    Glib::ustring myFilename;
 
1065
};
 
1066
 
 
1067
 
 
1068
 
 
1069
 
 
1070
 
 
1071
 
 
1072
/**
 
1073
 * Callback for checking if the preview needs to be redrawn
 
1074
 */
 
1075
void FileSaveDialogImpl::updatePreviewCallback()
 
1076
{
 
1077
    Glib::ustring fileName = get_preview_filename();
 
1078
    if (!fileName.c_str())
 
1079
        return;
 
1080
    bool retval = svgPreview.set(fileName, dialogType);
 
1081
    set_preview_widget_active(retval);
 
1082
}
 
1083
 
 
1084
 
 
1085
 
 
1086
/**
 
1087
 * Callback for fileNameEntry widget
 
1088
 */
 
1089
void FileSaveDialogImpl::fileNameEntryChangedCallback()
 
1090
{
 
1091
    if (!fileNameEntry)
 
1092
        return;
 
1093
 
 
1094
    Glib::ustring fileName = fileNameEntry->get_text();
 
1095
    if (!Glib::get_charset()) //If we are not utf8
 
1096
        fileName = Glib::filename_to_utf8(fileName);
 
1097
 
 
1098
    //g_message("User hit return.  Text is '%s'\n", fileName.c_str());
 
1099
 
 
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);
 
1107
    }
 
1108
 
 
1109
    //g_message("path:'%s'\n", fileName.c_str());
 
1110
 
 
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
 
1115
        //simulate an 'OK'
 
1116
        set_filename(fileName);
 
1117
        response(Gtk::RESPONSE_OK);
 
1118
    }
 
1119
}
 
1120
 
 
1121
 
 
1122
 
 
1123
/**
 
1124
 * Callback for fileNameEntry widget
 
1125
 */
 
1126
void FileSaveDialogImpl::fileTypeChangedCallback()
 
1127
{
 
1128
    int sel = fileTypeComboBox.get_active_row_number();
 
1129
    if (sel<0 || sel >= (int)fileTypes.size())
 
1130
        return;
 
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);
 
1135
    set_filter(filter);
 
1136
}
 
1137
 
 
1138
 
 
1139
 
 
1140
void FileSaveDialogImpl::createFileTypeMenu()
 
1141
{
 
1142
    Inkscape::Extension::DB::OutputList extension_list;
 
1143
    Inkscape::Extension::db.get_output_list(extension_list);
 
1144
 
 
1145
    for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
 
1146
         current_item != extension_list.end(); current_item++)
 
1147
    {
 
1148
        Inkscape::Extension::Output * omod = *current_item;
 
1149
 
 
1150
        // FIXME: would be nice to grey them out instead of not listing them
 
1151
        if (omod->deactivated()) continue;
 
1152
 
 
1153
        FileType type;
 
1154
        type.name     = (_(omod->get_filetypename()));
 
1155
        type.pattern  = "*";
 
1156
        FileDialogExtensionToPattern (type.pattern, omod->get_extension());
 
1157
        type.extension= omod;
 
1158
        fileTypeComboBox.append_text(type.name);
 
1159
        fileTypes.push_back(type);
 
1160
    }
 
1161
 
 
1162
    //#Let user choose
 
1163
    FileType guessType;
 
1164
    guessType.name = _("Guess from extension");
 
1165
    guessType.pattern = "*";
 
1166
    guessType.extension = NULL;
 
1167
    fileTypeComboBox.append_text(guessType.name);
 
1168
    fileTypes.push_back(guessType);
 
1169
 
 
1170
 
 
1171
    fileTypeComboBox.set_active(0);
 
1172
    fileTypeChangedCallback(); //call at least once to set the filter
 
1173
}
 
1174
 
 
1175
 
 
1176
void findEntryWidgets(Gtk::Container *parent, std::vector<Gtk::Entry *> &result)
 
1177
{
 
1178
    if (!parent)
 
1179
        return;
 
1180
    std::vector<Gtk::Widget *> children = parent->get_children();
 
1181
    for (unsigned int i=0; i<children.size() ; i++)
 
1182
        {
 
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);
 
1189
        }
 
1190
 
 
1191
}
 
1192
 
 
1193
void findExpanderWidgets(Gtk::Container *parent, std::vector<Gtk::Expander *> &result)
 
1194
{
 
1195
    if (!parent)
 
1196
        return;
 
1197
    std::vector<Gtk::Widget *> children = parent->get_children();
 
1198
    for (unsigned int i=0; i<children.size() ; i++)
 
1199
        {
 
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);
 
1206
        }
 
1207
 
 
1208
}
 
1209
 
 
1210
 
 
1211
/**
 
1212
 * Constructor
 
1213
 */
 
1214
FileSaveDialogImpl::FileSaveDialogImpl(char const *dir,
 
1215
                                       FileDialogType fileTypes,
 
1216
                                       char const *title,
 
1217
                                       char const *default_key) :
 
1218
                                       Gtk::FileChooserDialog(Glib::ustring(title),
 
1219
                                           Gtk::FILE_CHOOSER_ACTION_SAVE)
 
1220
{
 
1221
    append_extension = (bool)prefs_get_int_attribute("dialogs.save_as", "append_extension", 1);
 
1222
 
 
1223
    /* One file at a time */
 
1224
    set_select_multiple(false);
 
1225
 
 
1226
    /* Initalize to Autodetect */
 
1227
    extension = NULL;
 
1228
    /* No filename to start out with */
 
1229
    myFilename = "";
 
1230
 
 
1231
    /* Set our dialog type (save, export, etc...)*/
 
1232
    dialogType = fileTypes;
 
1233
 
 
1234
    /* Set the pwd and/or the filename */
 
1235
    if (dir != NULL)
 
1236
    {
 
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());
 
1243
    }
 
1244
 
 
1245
    //###### Add the file types menu
 
1246
    //createFilterMenu();
 
1247
 
 
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);
 
1251
 
 
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) );
 
1257
 
 
1258
    fileTypeBox.pack_start(fileTypeComboBox);
 
1259
 
 
1260
    set_extra_widget(fileTypeBox);
 
1261
    //get_vbox()->pack_start(fileTypeBox, false, false, 0);
 
1262
    //get_vbox()->reorder_child(fileTypeBox, 2);
 
1263
 
 
1264
    //###### Add a preview widget
 
1265
    set_preview_widget(svgPreview);
 
1266
    set_preview_widget_active(true);
 
1267
    set_use_preview_label (false);
 
1268
 
 
1269
    //Catch selection-changed events, so we can adjust the text widget
 
1270
    signal_update_preview().connect(
 
1271
         sigc::mem_fun(*this, &FileSaveDialogImpl::updatePreviewCallback) );
 
1272
 
 
1273
 
 
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 )
 
1281
        {
 
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) );
 
1286
        }
 
1287
 
 
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 )
 
1293
        {
 
1294
        //Always show the file list
 
1295
        Gtk::Expander *expander = expanders[0];
 
1296
        expander->set_expanded(true);
 
1297
        }
 
1298
 
 
1299
 
 
1300
    //if (extension == NULL)
 
1301
    //    checkbox.set_sensitive(FALSE);
 
1302
 
 
1303
    add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
 
1304
    add_button(Gtk::Stock::SAVE,   Gtk::RESPONSE_OK);
 
1305
 
 
1306
    show_all_children();
 
1307
}
 
1308
 
 
1309
 
 
1310
 
 
1311
/**
 
1312
 * Public factory method.  Used in file.cpp
 
1313
 */
 
1314
FileSaveDialog *FileSaveDialog::create(char const *path,
 
1315
                                       FileDialogType fileTypes,
 
1316
                                       char const *title,
 
1317
                                       char const *default_key)
 
1318
{
 
1319
    FileSaveDialog *dialog = new FileSaveDialogImpl(path, fileTypes, title, default_key);
 
1320
    return dialog;
 
1321
}
 
1322
 
 
1323
 
 
1324
 
 
1325
 
 
1326
 
 
1327
/**
 
1328
 * Destructor
 
1329
 */
 
1330
FileSaveDialogImpl::~FileSaveDialogImpl()
 
1331
{
 
1332
}
 
1333
 
 
1334
 
 
1335
 
 
1336
 
 
1337
/**
 
1338
 * Show this dialog modally.  Return true if user hits [OK]
 
1339
 */
 
1340
bool
 
1341
FileSaveDialogImpl::show()
 
1342
{
 
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
 
1347
    hide();
 
1348
 
 
1349
    if (b == Gtk::RESPONSE_OK)
 
1350
        {
 
1351
        int sel = fileTypeComboBox.get_active_row_number ();
 
1352
        if (sel>=0 && sel< (int)fileTypes.size())
 
1353
            {
 
1354
            FileType &type = fileTypes[sel];
 
1355
            extension = type.extension;
 
1356
            }
 
1357
        myFilename = get_filename();
 
1358
 
 
1359
        /*
 
1360
 
 
1361
        // FIXME: Why do we have more code
 
1362
 
 
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() : "" ));
 
1367
        */
 
1368
        return TRUE;
 
1369
        }
 
1370
    else
 
1371
        {
 
1372
        return FALSE;
 
1373
        }
 
1374
}
 
1375
 
 
1376
 
 
1377
/**
 
1378
 * Get the file extension type that was selected by the user. Valid after an [OK]
 
1379
 */
 
1380
Inkscape::Extension::Extension *
 
1381
FileSaveDialogImpl::getSelectionType()
 
1382
{
 
1383
    return extension;
 
1384
}
 
1385
 
 
1386
 
 
1387
/**
 
1388
 * Get the file name chosen by the user.   Valid after an [OK]
 
1389
 */
 
1390
gchar *
 
1391
FileSaveDialogImpl::getFilename()
 
1392
{
 
1393
    return g_strdup(myFilename.c_str());
 
1394
}
 
1395
 
 
1396
/**
 
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
 
1401
 
 
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
 
1405
    this happen.
 
1406
*/
 
1407
void
 
1408
FileDialogExtensionToPattern (Glib::ustring &pattern, gchar * in_file_extension)
 
1409
{
 
1410
    Glib::ustring tmp(in_file_extension);
 
1411
 
 
1412
    for ( guint i = 0; i < tmp.length(); i++ ) {
 
1413
        Glib::ustring::value_type ch = tmp.at(i);
 
1414
        if ( Glib::Unicode::isalpha(ch) ) {
 
1415
            pattern += '[';
 
1416
            pattern += Glib::Unicode::toupper(ch);
 
1417
            pattern += Glib::Unicode::tolower(ch);
 
1418
            pattern += ']';
 
1419
        } else {
 
1420
            pattern += ch;
 
1421
        }
 
1422
    }
 
1423
}
 
1424
 
 
1425
} //namespace Dialogs
 
1426
} //namespace UI
 
1427
} //namespace Inkscape
 
1428
 
 
1429
 
 
1430
/*
 
1431
  Local Variables:
 
1432
  mode:c++
 
1433
  c-file-style:"stroustrup"
 
1434
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
1435
  indent-tabs-mode:nil
 
1436
  fill-column:99
 
1437
  End:
 
1438
*/
 
1439
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :