1 /**\r
2 * Implementation of the file dialog interfaces defined in filedialogimpl.h\r
3 *\r
4 * Authors:\r
5 * Bob Jamison\r
6 * Joel Holdsworth\r
7 * Bruno Dilly\r
8 * Other dudes from The Inkscape Organization\r
9 *\r
10 * Copyright (C) 2004-2007 Bob Jamison\r
11 * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>\r
12 * Copyright (C) 2004-2007 The Inkscape Organization\r
13 * Copyright (C) 2007 Joel Holdsworth\r
14 *\r
15 * Released under GNU GPL, read the file 'COPYING' for more information\r
16 */\r
17 \r
18 #include "filedialog.h"\r
19 \r
20 //General includes\r
21 #include <unistd.h>\r
22 #include <sys/stat.h>\r
23 #include <errno.h>\r
24 #include <set>\r
25 #include <libxml/parser.h>\r
26 #include <libxml/tree.h>\r
27 \r
28 \r
29 //Gtk includes\r
30 #include <glibmm/i18n.h>\r
31 #include <glib/gstdio.h>\r
32 \r
33 //Temporary ugly hack\r
34 //Remove this after the get_filter() calls in\r
35 //show() on both classes are fixed\r
36 #include <gtk/gtkfilechooser.h>\r
37 \r
38 //Another hack\r
39 #include <gtk/gtkentry.h>\r
40 #include <gtk/gtkexpander.h>\r
41 #ifdef WITH_GNOME_VFS\r
42 # include <libgnomevfs/gnome-vfs-init.h> // gnome_vfs_initialized\r
43 #endif\r
44 \r
45 //Inkscape includes\r
46 #include "prefs-utils.h"\r
47 #include <extension/input.h>\r
48 #include <extension/output.h>\r
49 #include <extension/db.h>\r
50 #include "inkscape.h"\r
51 #include "svg-view-widget.h"\r
52 #include "gc-core.h"\r
53 \r
54 //For export dialog\r
55 #include "ui/widget/scalar-unit.h"\r
56 \r
57 namespace Inkscape\r
58 {\r
59 namespace UI\r
60 {\r
61 namespace Dialog\r
62 {\r
63 \r
64 /*#########################################################################\r
65 ### SVG Preview Widget\r
66 #########################################################################*/\r
67 \r
68 /**\r
69 * Simple class for displaying an SVG file in the "preview widget."\r
70 * Currently, this is just a wrapper of the sp_svg_view Gtk widget.\r
71 * Hopefully we will eventually replace with a pure Gtkmm widget.\r
72 */\r
73 class SVGPreview : public Gtk::VBox\r
74 {\r
75 public:\r
76 \r
77 SVGPreview();\r
78 \r
79 ~SVGPreview();\r
80 \r
81 bool setDocument(SPDocument *doc);\r
82 \r
83 bool setFileName(Glib::ustring &fileName);\r
84 \r
85 bool setFromMem(char const *xmlBuffer);\r
86 \r
87 bool set(Glib::ustring &fileName, int dialogType);\r
88 \r
89 bool setURI(URI &uri);\r
90 \r
91 /**\r
92 * Show image embedded in SVG\r
93 */\r
94 void showImage(Glib::ustring &fileName);\r
95 \r
96 /**\r
97 * Show the "No preview" image\r
98 */\r
99 void showNoPreview();\r
100 \r
101 /**\r
102 * Show the "Too large" image\r
103 */\r
104 void showTooLarge(long fileLength);\r
105 \r
106 private:\r
107 /**\r
108 * The svg document we are currently showing\r
109 */\r
110 SPDocument *document;\r
111 \r
112 /**\r
113 * The sp_svg_view widget\r
114 */\r
115 GtkWidget *viewerGtk;\r
116 \r
117 /**\r
118 * are we currently showing the "no preview" image?\r
119 */\r
120 bool showingNoPreview;\r
121 \r
122 };\r
123 \r
124 /*#########################################################################\r
125 ### F I L E D I A L O G B A S E C L A S S\r
126 #########################################################################*/\r
127 \r
128 /**\r
129 * This class is the base implementation for the others. This\r
130 * reduces redundancies and bugs.\r
131 */\r
132 class FileDialogBaseGtk : public Gtk::FileChooserDialog\r
133 {\r
134 public:\r
135 \r
136 /**\r
137 *\r
138 */\r
139 FileDialogBaseGtk(Gtk::Window& parentWindow, const Glib::ustring &title,\r
140 FileDialogType type, gchar const* preferenceBase) :\r
141 Gtk::FileChooserDialog(parentWindow, title),\r
142 preferenceBase(preferenceBase ? preferenceBase : "unknown"),\r
143 dialogType(type)\r
144 {\r
145 internalSetup();\r
146 }\r
147 \r
148 /**\r
149 *\r
150 */\r
151 FileDialogBaseGtk(Gtk::Window& parentWindow, const Glib::ustring &title,\r
152 Gtk::FileChooserAction dialogType, FileDialogType type, gchar const* preferenceBase) :\r
153 Gtk::FileChooserDialog(parentWindow, title, dialogType),\r
154 preferenceBase(preferenceBase ? preferenceBase : "unknown"),\r
155 dialogType(type)\r
156 {\r
157 internalSetup();\r
158 }\r
159 \r
160 /**\r
161 *\r
162 */\r
163 virtual ~FileDialogBaseGtk()\r
164 {}\r
165 \r
166 protected:\r
167 void cleanup( bool showConfirmed );\r
168 \r
169 Glib::ustring preferenceBase;\r
170 /**\r
171 * What type of 'open' are we? (open, import, place, etc)\r
172 */\r
173 FileDialogType dialogType;\r
174 \r
175 /**\r
176 * Our svg preview widget\r
177 */\r
178 SVGPreview svgPreview;\r
179 \r
180 //# Child widgets\r
181 Gtk::CheckButton previewCheckbox;\r
182 \r
183 private:\r
184 void internalSetup();\r
185 \r
186 /**\r
187 * Callback for user changing preview checkbox\r
188 */\r
189 void _previewEnabledCB();\r
190 \r
191 /**\r
192 * Callback for seeing if the preview needs to be drawn\r
193 */\r
194 void _updatePreviewCallback();\r
195 };\r
196 \r
197 \r
198 \r
199 \r
200 /*#########################################################################\r
201 ### F I L E O P E N\r
202 #########################################################################*/\r
203 \r
204 /**\r
205 * Our implementation class for the FileOpenDialog interface..\r
206 */\r
207 class FileOpenDialogImplGtk : public FileOpenDialog, public FileDialogBaseGtk\r
208 {\r
209 public:\r
210 \r
211 FileOpenDialogImplGtk(Gtk::Window& parentWindow,\r
212 const Glib::ustring &dir,\r
213 FileDialogType fileTypes,\r
214 const Glib::ustring &title);\r
215 \r
216 virtual ~FileOpenDialogImplGtk();\r
217 \r
218 bool show();\r
219 \r
220 Inkscape::Extension::Extension *getSelectionType();\r
221 \r
222 Glib::ustring getFilename();\r
223 \r
224 std::vector<Glib::ustring> getFilenames ();\r
225 \r
226 private:\r
227 \r
228 /**\r
229 * Create a filter menu for this type of dialog\r
230 */\r
231 void createFilterMenu();\r
232 \r
233 /**\r
234 * Filter name->extension lookup\r
235 */\r
236 std::map<Glib::ustring, Inkscape::Extension::Extension *> extensionMap;\r
237 \r
238 /**\r
239 * The extension to use to write this file\r
240 */\r
241 Inkscape::Extension::Extension *extension;\r
242 \r
243 /**\r
244 * Filename that was given\r
245 */\r
246 Glib::ustring myFilename;\r
247 \r
248 };\r
249 \r
250 \r
251 class FileType\r
252 {\r
253 public:\r
254 FileType() {}\r
255 ~FileType() {}\r
256 Glib::ustring name;\r
257 Glib::ustring pattern;\r
258 Inkscape::Extension::Extension *extension;\r
259 };\r
260 \r
261 \r
262 \r
263 //########################################################################\r
264 //# F I L E S A V E\r
265 //########################################################################\r
266 \r
267 /**\r
268 * Our implementation of the FileSaveDialog interface.\r
269 */\r
270 class FileSaveDialogImplGtk : public FileSaveDialog, public FileDialogBaseGtk\r
271 {\r
272 \r
273 public:\r
274 FileSaveDialogImplGtk(Gtk::Window &parentWindow, \r
275 const Glib::ustring &dir,\r
276 FileDialogType fileTypes,\r
277 const Glib::ustring &title,\r
278 const Glib::ustring &default_key);\r
279 \r
280 virtual ~FileSaveDialogImplGtk();\r
281 \r
282 bool show();\r
283 \r
284 Inkscape::Extension::Extension *getSelectionType();\r
285 virtual void setSelectionType( Inkscape::Extension::Extension * key );\r
286 \r
287 Glib::ustring getFilename();\r
288 \r
289 void change_title(const Glib::ustring& title);\r
290 void change_path(const Glib::ustring& path);\r
291 void updateNameAndExtension();\r
292 \r
293 private:\r
294 \r
295 /**\r
296 * Fix to allow the user to type the file name\r
297 */\r
298 Gtk::Entry *fileNameEntry;\r
299 \r
300 \r
301 /**\r
302 * Allow the specification of the output file type\r
303 */\r
304 Gtk::ComboBoxText fileTypeComboBox;\r
305 \r
306 \r
307 /**\r
308 * Data mirror of the combo box\r
309 */\r
310 std::vector<FileType> fileTypes;\r
311 \r
312 //# Child widgets\r
313 Gtk::HBox childBox;\r
314 Gtk::VBox checksBox;\r
315 \r
316 Gtk::CheckButton fileTypeCheckbox;\r
317 \r
318 /**\r
319 * Callback for user input into fileNameEntry\r
320 */\r
321 void fileTypeChangedCallback();\r
322 \r
323 /**\r
324 * Create a filter menu for this type of dialog\r
325 */\r
326 void createFileTypeMenu();\r
327 \r
328 \r
329 /**\r
330 * The extension to use to write this file\r
331 */\r
332 Inkscape::Extension::Extension *extension;\r
333 \r
334 /**\r
335 * Callback for user input into fileNameEntry\r
336 */\r
337 void fileNameEntryChangedCallback();\r
338 \r
339 /**\r
340 * Filename that was given\r
341 */\r
342 Glib::ustring myFilename;\r
343 \r
344 /**\r
345 * List of known file extensions.\r
346 */\r
347 std::set<Glib::ustring> knownExtensions;\r
348 };\r
349 \r
350 \r
351 \r
352 \r
353 //########################################################################\r
354 //# F I L E E X P O R T\r
355 //########################################################################\r
356 \r
357 /**\r
358 * Our implementation of the FileExportDialog interface.\r
359 */\r
360 class FileExportDialogImpl : public FileExportDialog, public FileDialogBaseGtk\r
361 {\r
362 \r
363 public:\r
364 FileExportDialogImpl(Gtk::Window& parentWindow, \r
365 const Glib::ustring &dir,\r
366 FileDialogType fileTypes,\r
367 const Glib::ustring &title,\r
368 const Glib::ustring &default_key);\r
369 \r
370 virtual ~FileExportDialogImpl();\r
371 \r
372 bool show();\r
373 \r
374 Inkscape::Extension::Extension *getSelectionType();\r
375 \r
376 Glib::ustring getFilename();\r
377 \r
378 \r
379 /**\r
380 * Return the scope of the export. One of the enumerated types\r
381 * in ScopeType \r
382 */\r
383 ScopeType getScope()\r
384 { \r
385 if (pageButton.get_active())\r
386 return SCOPE_PAGE;\r
387 else if (selectionButton.get_active())\r
388 return SCOPE_SELECTION;\r
389 else if (customButton.get_active())\r
390 return SCOPE_CUSTOM;\r
391 else\r
392 return SCOPE_DOCUMENT;\r
393 \r
394 }\r
395 \r
396 /**\r
397 * Return left side of the exported region\r
398 */\r
399 double getSourceX()\r
400 { return sourceX0Spinner.getValue(); }\r
401 \r
402 /**\r
403 * Return the top of the exported region\r
404 */\r
405 double getSourceY()\r
406 { return sourceY1Spinner.getValue(); }\r
407 \r
408 /**\r
409 * Return the width of the exported region\r
410 */\r
411 double getSourceWidth()\r
412 { return sourceWidthSpinner.getValue(); }\r
413 \r
414 /**\r
415 * Return the height of the exported region\r
416 */\r
417 double getSourceHeight()\r
418 { return sourceHeightSpinner.getValue(); }\r
419 \r
420 /**\r
421 * Return the units of the coordinates of exported region\r
422 */\r
423 Glib::ustring getSourceUnits()\r
424 { return sourceUnitsSpinner.getUnitAbbr(); }\r
425 \r
426 /**\r
427 * Return the width of the destination document\r
428 */\r
429 double getDestinationWidth()\r
430 { return destWidthSpinner.getValue(); }\r
431 \r
432 /**\r
433 * Return the height of the destination document\r
434 */\r
435 double getDestinationHeight()\r
436 { return destHeightSpinner.getValue(); }\r
437 \r
438 /**\r
439 * Return the height of the exported region\r
440 */\r
441 Glib::ustring getDestinationUnits()\r
442 { return destUnitsSpinner.getUnitAbbr(); }\r
443 \r
444 /**\r
445 * Return the destination DPI image resulution, if bitmap\r
446 */\r
447 double getDestinationDPI()\r
448 { return destDPISpinner.getValue(); }\r
449 \r
450 /**\r
451 * Return whether we should use Cairo for rendering\r
452 */\r
453 bool getUseCairo()\r
454 { return cairoButton.get_active(); }\r
455 \r
456 /**\r
457 * Return whether we should use antialiasing\r
458 */\r
459 bool getUseAntialias()\r
460 { return antiAliasButton.get_active(); }\r
461 \r
462 /**\r
463 * Return the background color for exporting\r
464 */\r
465 unsigned long getBackground()\r
466 { return backgroundButton.get_color().get_pixel(); }\r
467 \r
468 private:\r
469 \r
470 /**\r
471 * Fix to allow the user to type the file name\r
472 */\r
473 Gtk::Entry *fileNameEntry;\r
474 \r
475 //##########################################\r
476 //# EXTRA WIDGET -- SOURCE SIDE\r
477 //##########################################\r
478 \r
479 Gtk::Frame sourceFrame;\r
480 Gtk::VBox sourceBox;\r
481 \r
482 Gtk::HBox scopeBox;\r
483 Gtk::RadioButtonGroup scopeGroup;\r
484 Gtk::RadioButton documentButton;\r
485 Gtk::RadioButton pageButton;\r
486 Gtk::RadioButton selectionButton;\r
487 Gtk::RadioButton customButton;\r
488 \r
489 Gtk::Table sourceTable;\r
490 Inkscape::UI::Widget::Scalar sourceX0Spinner;\r
491 Inkscape::UI::Widget::Scalar sourceY0Spinner;\r
492 Inkscape::UI::Widget::Scalar sourceX1Spinner;\r
493 Inkscape::UI::Widget::Scalar sourceY1Spinner;\r
494 Inkscape::UI::Widget::Scalar sourceWidthSpinner;\r
495 Inkscape::UI::Widget::Scalar sourceHeightSpinner;\r
496 Inkscape::UI::Widget::UnitMenu sourceUnitsSpinner;\r
497 \r
498 \r
499 //##########################################\r
500 //# EXTRA WIDGET -- DESTINATION SIDE\r
501 //##########################################\r
502 \r
503 Gtk::Frame destFrame;\r
504 Gtk::VBox destBox;\r
505 \r
506 Gtk::Table destTable;\r
507 Inkscape::UI::Widget::Scalar destWidthSpinner;\r
508 Inkscape::UI::Widget::Scalar destHeightSpinner;\r
509 Inkscape::UI::Widget::Scalar destDPISpinner;\r
510 Inkscape::UI::Widget::UnitMenu destUnitsSpinner;\r
511 \r
512 Gtk::HBox otherOptionBox;\r
513 Gtk::CheckButton cairoButton;\r
514 Gtk::CheckButton antiAliasButton;\r
515 Gtk::ColorButton backgroundButton;\r
516 \r
517 \r
518 /**\r
519 * 'Extra' widget that holds two boxes above\r
520 */\r
521 Gtk::HBox exportOptionsBox;\r
522 \r
523 \r
524 //# Child widgets\r
525 Gtk::CheckButton fileTypeCheckbox;\r
526 \r
527 /**\r
528 * Allow the specification of the output file type\r
529 */\r
530 Gtk::ComboBoxText fileTypeComboBox;\r
531 \r
532 \r
533 /**\r
534 * Data mirror of the combo box\r
535 */\r
536 std::vector<FileType> fileTypes;\r
537 \r
538 \r
539 \r
540 /**\r
541 * Callback for user input into fileNameEntry\r
542 */\r
543 void fileTypeChangedCallback();\r
544 \r
545 /**\r
546 * Create a filter menu for this type of dialog\r
547 */\r
548 void createFileTypeMenu();\r
549 \r
550 \r
551 bool append_extension;\r
552 \r
553 /**\r
554 * The extension to use to write this file\r
555 */\r
556 Inkscape::Extension::Extension *extension;\r
557 \r
558 /**\r
559 * Callback for user input into fileNameEntry\r
560 */\r
561 void fileNameEntryChangedCallback();\r
562 \r
563 /**\r
564 * Filename that was given\r
565 */\r
566 Glib::ustring myFilename;\r
567 };\r
568 \r
569 \r
570 \r
571 /*#########################################################################\r
572 ### F I L E D I A L O G O C A L B A S E C L A S S\r
573 #########################################################################*/\r
574 \r
575 /**\r
576 * This class is the base implementation for export to OCAL.\r
577 */\r
578 class FileDialogOCALBase : public Gtk::Dialog\r
579 {\r
580 public:\r
581 \r
582 /**\r
583 *\r
584 */\r
585 FileDialogOCALBase(const Glib::ustring &title) : Gtk::Dialog(title,true)\r
586 {}\r
587 /*\r
588 *\r
589 */\r
590 virtual ~FileDialogOCALBase()\r
591 {}\r
592 \r
593 protected:\r
594 void cleanup( bool showConfirmed );\r
595 \r
596 //Glib::ustring preferenceBase;\r
597 /**\r
598 * What type of 'open' are we? (open, import, place, etc)\r
599 */\r
600 FileDialogType dialogType;\r
601 };\r
602 \r
603 \r
604 \r
605 \r
606 //########################################################################\r
607 //# F I L E E X P O R T T O O C A L\r
608 //########################################################################\r
609 \r
610 \r
611 \r
612 /**\r
613 * Our implementation of the FileExportToOCALDialog interface.\r
614 */\r
615 class FileExportToOCALDialogImpl : public FileExportToOCALDialog, public FileDialogOCALBase\r
616 {\r
617 \r
618 public:\r
619 FileExportToOCALDialogImpl(Gtk::Window& parentWindow, \r
620 FileDialogType fileTypes,\r
621 const Glib::ustring &title,\r
622 const Glib::ustring &default_key);\r
623 \r
624 virtual ~FileExportToOCALDialogImpl();\r
625 \r
626 bool show();\r
627 \r
628 Inkscape::Extension::Extension *getSelectionType();\r
629 virtual void setSelectionType( Inkscape::Extension::Extension * key );\r
630 \r
631 Glib::ustring getFilename();\r
632 \r
633 Glib::ustring myFilename;\r
634 \r
635 void change_title(const Glib::ustring& title);\r
636 void updateNameAndExtension();\r
637 \r
638 private:\r
639 \r
640 /**\r
641 * Fix to allow the user to type the file name\r
642 */\r
643 Gtk::Entry *fileNameEntry;\r
644 \r
645 \r
646 /**\r
647 * Allow the specification of the output file type\r
648 */\r
649 Gtk::ComboBoxText fileTypeComboBox;\r
650 \r
651 \r
652 /**\r
653 * Data mirror of the combo box\r
654 */\r
655 std::vector<FileType> fileTypes;\r
656 \r
657 // Child widgets\r
658 Gtk::HBox childBox;\r
659 Gtk::VBox checksBox;\r
660 Gtk::HBox fileBox;\r
661 \r
662 Gtk::CheckButton fileTypeCheckbox;\r
663 \r
664 /**\r
665 * Callback for user input into fileNameEntry\r
666 */\r
667 void fileTypeChangedCallback();\r
668 \r
669 /**\r
670 * Create a filter menu for this type of dialog\r
671 */\r
672 void createFileTypeMenu();\r
673 \r
674 \r
675 /**\r
676 * The extension to use to write this file\r
677 */\r
678 Inkscape::Extension::Extension *extension;\r
679 \r
680 /**\r
681 * Callback for user input into fileNameEntry\r
682 */\r
683 void fileNameEntryChangedCallback();\r
684 \r
685 /**\r
686 * List of known file extensions.\r
687 */\r
688 std::set<Glib::ustring> knownExtensions;\r
689 };\r
690 \r
691 \r
692 //#########################################################################\r
693 //### F I L E I M P O R T F R O M O C A L\r
694 //#########################################################################\r
695 \r
696 /**\r
697 * Our implementation class for filesListView\r
698 */\r
699 class FileListViewText : public Gtk::ListViewText\r
700 {\r
701 public:\r
702 FileListViewText(guint columns_count, SVGPreview& filesPreview):ListViewText(columns_count)\r
703 {\r
704 myPreview = &filesPreview;\r
705 }\r
706 Glib::ustring getFilename();\r
707 protected:\r
708 void on_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);\r
709 private:\r
710 Glib::ustring myFilename;\r
711 SVGPreview *myPreview;\r
712 };\r
713 \r
714 /**\r
715 * Our implementation class for the FileImportFromOCALDialog interface..\r
716 */\r
717 class FileImportFromOCALDialogImplGtk : public FileImportFromOCALDialog, public FileDialogOCALBase\r
718 {\r
719 public:\r
720 \r
721 FileImportFromOCALDialogImplGtk(Gtk::Window& parentWindow,\r
722 const Glib::ustring &dir,\r
723 FileDialogType fileTypes,\r
724 const Glib::ustring &title);\r
725 \r
726 virtual ~FileImportFromOCALDialogImplGtk();\r
727 \r
728 bool show();\r
729 \r
730 Inkscape::Extension::Extension *getSelectionType();\r
731 \r
732 Glib::ustring getFilename();\r
733 \r
734 private:\r
735 \r
736 /**\r
737 * Allow the user to type the tag to be searched\r
738 */\r
739 Gtk::Entry *searchTagEntry;\r
740 FileListViewText *filesList;\r
741 SVGPreview *filesPreview;\r
742 Gtk::Label *notFoundLabel;\r
743 \r
744 // Child widgets\r
745 Gtk::HBox tagBox;\r
746 Gtk::HBox filesBox;\r
747 Gtk::HBox messageBox;\r
748 Gtk::ScrolledWindow listScrolledWindow;\r
749 Glib::RefPtr<Gtk::TreeSelection> selection;\r
750 \r
751 /**\r
752 * Callback for user input into searchTagEntry\r
753 */\r
754 void searchTagEntryChangedCallback();\r
755 \r
756 \r
757 /**\r
758 * Prints the names of the all the xml elements \r
759 * that are siblings or children of a given xml node\r
760 */\r
761 void print_xml_element_names(xmlNode * a_node);\r
762 \r
763 /**\r
764 * The extension to use to write this file\r
765 */\r
766 Inkscape::Extension::Extension *extension;\r
767 };\r
768 \r
769 }\r
770 }\r
771 }\r
772 \r
773 /*\r
774 Local Variables:\r
775 mode:c++\r
776 c-file-style:"stroustrup"\r
777 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
778 indent-tabs-mode:nil\r
779 fill-column:99\r
780 End:\r
781 */\r
782 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r