1 #define __SP_FILE_C__
3 /*
4 * File/Print operations
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * Chema Celorio <chema@celorio.com>
9 * bulia byak <buliabyak@users.sf.net>
10 * Bruno Dilly <bruno.dilly@gmail.com>
11 * Stephen Silver <sasilver@users.sourceforge.net>
12 *
13 * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
14 * Copyright (C) 1999-2008 Authors
15 * Copyright (C) 2004 David Turner
16 * Copyright (C) 2001-2002 Ximian, Inc.
17 *
18 * Released under GNU GPL, read the file 'COPYING' for more information
19 */
21 /** @file
22 * @note This file needs to be cleaned up extensively.
23 * What it probably needs is to have one .h file for
24 * the API, and two or more .cpp files for the implementations.
25 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <gtk/gtk.h>
32 #include <glib/gmem.h>
33 #include <libnr/nr-pixops.h>
35 #include "document-private.h"
36 #include "selection-chemistry.h"
37 #include "ui/view/view-widget.h"
38 #include "dir-util.h"
39 #include "helper/png-write.h"
40 #include "dialogs/export.h"
41 #include <glibmm/i18n.h>
42 #include "inkscape.h"
43 #include "desktop.h"
44 #include "selection.h"
45 #include "interface.h"
46 #include "style.h"
47 #include "print.h"
48 #include "file.h"
49 #include "message.h"
50 #include "message-stack.h"
51 #include "ui/dialog/filedialog.h"
52 #include "ui/dialog/ocaldialogs.h"
53 #include "preferences.h"
54 #include "path-prefix.h"
56 #include "sp-namedview.h"
57 #include "desktop-handles.h"
59 #include "extension/db.h"
60 #include "extension/input.h"
61 #include "extension/output.h"
62 /* #include "extension/menu.h" */
63 #include "extension/system.h"
65 #include "io/sys.h"
66 #include "application/application.h"
67 #include "application/editor.h"
68 #include "inkscape.h"
69 #include "uri.h"
70 #include "id-clash.h"
71 #include "dialogs/rdf.h"
73 #ifdef WITH_GNOME_VFS
74 # include <libgnomevfs/gnome-vfs.h>
75 #endif
77 #ifdef WITH_INKBOARD
78 #include "jabber_whiteboard/session-manager.h"
79 #endif
81 #ifdef WIN32
82 #include <windows.h>
83 #endif
85 //#define INK_DUMP_FILENAME_CONV 1
86 #undef INK_DUMP_FILENAME_CONV
88 //#define INK_DUMP_FOPEN 1
89 #undef INK_DUMP_FOPEN
91 void dump_str(gchar const *str, gchar const *prefix);
92 void dump_ustr(Glib::ustring const &ustr);
94 // what gets passed here is not actually an URI... it is an UTF-8 encoded filename (!)
95 static void sp_file_add_recent(gchar const *uri)
96 {
97 GtkRecentManager *recent = gtk_recent_manager_get_default();
98 gchar *fn = g_filename_from_utf8(uri, -1, NULL, NULL, NULL);
99 gchar *uri_to_add = g_filename_to_uri(fn, NULL, NULL);
100 if (uri_to_add) {
101 gtk_recent_manager_add_item(recent, uri_to_add);
102 }
103 g_free(uri_to_add);
104 g_free(fn);
105 }
108 /*######################
109 ## N E W
110 ######################*/
112 /**
113 * Create a blank document and add it to the desktop
114 */
115 SPDesktop*
116 sp_file_new(const Glib::ustring &templ)
117 {
118 char *templName = NULL;
119 if (templ.size()>0)
120 templName = (char *)templ.c_str();
121 SPDocument *doc = sp_document_new(templName, TRUE, true);
122 g_return_val_if_fail(doc != NULL, NULL);
124 SPDesktop *dt;
125 if (Inkscape::NSApplication::Application::getNewGui())
126 {
127 dt = Inkscape::NSApplication::Editor::createDesktop (doc);
128 } else {
129 SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL));
130 g_return_val_if_fail(dtw != NULL, NULL);
131 sp_document_unref(doc);
133 sp_create_window(dtw, TRUE);
134 dt = static_cast<SPDesktop*>(dtw->view);
135 sp_namedview_window_from_document(dt);
136 sp_namedview_update_layers_from_document(dt);
137 }
138 return dt;
139 }
141 SPDesktop*
142 sp_file_new_default()
143 {
144 std::list<gchar *> sources;
145 sources.push_back( profile_path("templates") ); // first try user's local dir
146 sources.push_back( g_strdup(INKSCAPE_TEMPLATESDIR) ); // then the system templates dir
148 while (!sources.empty()) {
149 gchar *dirname = sources.front();
150 if ( Inkscape::IO::file_test( dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ) ) {
152 // TRANSLATORS: default.svg is localizable - this is the name of the default document
153 // template. This way you can localize the default pagesize, translate the name of
154 // the default layer, etc. If you wish to localize this file, please create a
155 // localized share/templates/default.xx.svg file, where xx is your language code.
156 char *default_template = g_build_filename(dirname, _("default.svg"), NULL);
157 if (Inkscape::IO::file_test(default_template, G_FILE_TEST_IS_REGULAR)) {
158 return sp_file_new(default_template);
159 }
160 }
161 g_free(dirname);
162 sources.pop_front();
163 }
165 return sp_file_new("");
166 }
169 /*######################
170 ## D E L E T E
171 ######################*/
173 /**
174 * Perform document closures preceding an exit()
175 */
176 void
177 sp_file_exit()
178 {
179 sp_ui_close_all();
180 // no need to call inkscape_exit here; last document being closed will take care of that
181 }
184 /*######################
185 ## O P E N
186 ######################*/
188 /**
189 * Open a file, add the document to the desktop
190 *
191 * \param replace_empty if true, and the current desktop is empty, this document
192 * will replace the empty one.
193 */
194 bool
195 sp_file_open(const Glib::ustring &uri,
196 Inkscape::Extension::Extension *key,
197 bool add_to_recent, bool replace_empty)
198 {
199 SPDocument *doc = NULL;
200 try {
201 doc = Inkscape::Extension::open(key, uri.c_str());
202 } catch (Inkscape::Extension::Input::no_extension_found &e) {
203 doc = NULL;
204 } catch (Inkscape::Extension::Input::open_failed &e) {
205 doc = NULL;
206 }
208 if (doc) {
209 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
210 SPDocument *existing = desktop ? sp_desktop_document(desktop) : NULL;
212 if (existing && existing->virgin && replace_empty) {
213 // If the current desktop is empty, open the document there
214 sp_document_ensure_up_to_date (doc);
215 desktop->change_document(doc);
216 sp_document_resized_signal_emit (doc, sp_document_width(doc), sp_document_height(doc));
217 } else {
218 if (!Inkscape::NSApplication::Application::getNewGui()) {
219 // create a whole new desktop and window
220 SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL));
221 sp_create_window(dtw, TRUE);
222 desktop = static_cast<SPDesktop*>(dtw->view);
223 } else {
224 desktop = Inkscape::NSApplication::Editor::createDesktop (doc);
225 }
226 }
228 doc->virgin = FALSE;
229 // everyone who cares now has a reference, get rid of ours
230 sp_document_unref(doc);
231 // resize the window to match the document properties
232 sp_namedview_window_from_document(desktop);
233 sp_namedview_update_layers_from_document(desktop);
235 if (add_to_recent) {
236 sp_file_add_recent(SP_DOCUMENT_URI(doc));
237 }
239 return TRUE;
240 } else {
241 gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str());
242 gchar *text = g_strdup_printf(_("Failed to load the requested file %s"), safeUri);
243 sp_ui_error_dialog(text);
244 g_free(text);
245 g_free(safeUri);
246 return FALSE;
247 }
248 }
250 /**
251 * Handle prompting user for "do you want to revert"? Revert on "OK"
252 */
253 void
254 sp_file_revert_dialog()
255 {
256 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
257 g_assert(desktop != NULL);
259 SPDocument *doc = sp_desktop_document(desktop);
260 g_assert(doc != NULL);
262 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
263 g_assert(repr != NULL);
265 gchar const *uri = doc->uri;
266 if (!uri) {
267 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved yet. Cannot revert."));
268 return;
269 }
271 bool do_revert = true;
272 if (doc->isModifiedSinceSave()) {
273 gchar *text = g_strdup_printf(_("Changes will be lost! Are you sure you want to reload document %s?"), uri);
275 bool response = desktop->warnDialog (text);
276 g_free(text);
278 if (!response) {
279 do_revert = false;
280 }
281 }
283 bool reverted;
284 if (do_revert) {
285 // Allow overwriting of current document.
286 doc->virgin = TRUE;
288 // remember current zoom and view
289 double zoom = desktop->current_zoom();
290 Geom::Point c = desktop->get_display_area().midpoint();
292 reverted = sp_file_open(uri,NULL);
293 if (reverted) {
294 // restore zoom and view
295 desktop->zoom_absolute(c[Geom::X], c[Geom::Y], zoom);
296 }
297 } else {
298 reverted = false;
299 }
301 if (reverted) {
302 desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Document reverted."));
303 } else {
304 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not reverted."));
305 }
306 }
308 void dump_str(gchar const *str, gchar const *prefix)
309 {
310 Glib::ustring tmp;
311 tmp = prefix;
312 tmp += " [";
313 size_t const total = strlen(str);
314 for (unsigned i = 0; i < total; i++) {
315 gchar *const tmp2 = g_strdup_printf(" %02x", (0x0ff & str[i]));
316 tmp += tmp2;
317 g_free(tmp2);
318 }
320 tmp += "]";
321 g_message("%s", tmp.c_str());
322 }
324 void dump_ustr(Glib::ustring const &ustr)
325 {
326 char const *cstr = ustr.c_str();
327 char const *data = ustr.data();
328 Glib::ustring::size_type const byteLen = ustr.bytes();
329 Glib::ustring::size_type const dataLen = ustr.length();
330 Glib::ustring::size_type const cstrLen = strlen(cstr);
332 g_message(" size: %lu\n length: %lu\n bytes: %lu\n clen: %lu",
333 gulong(ustr.size()), gulong(dataLen), gulong(byteLen), gulong(cstrLen) );
334 g_message( " ASCII? %s", (ustr.is_ascii() ? "yes":"no") );
335 g_message( " UTF-8? %s", (ustr.validate() ? "yes":"no") );
337 try {
338 Glib::ustring tmp;
339 for (Glib::ustring::size_type i = 0; i < ustr.bytes(); i++) {
340 tmp = " ";
341 if (i < dataLen) {
342 Glib::ustring::value_type val = ustr.at(i);
343 gchar* tmp2 = g_strdup_printf( (((val & 0xff00) == 0) ? " %02x" : "%04x"), val );
344 tmp += tmp2;
345 g_free( tmp2 );
346 } else {
347 tmp += " ";
348 }
350 if (i < byteLen) {
351 int val = (0x0ff & data[i]);
352 gchar *tmp2 = g_strdup_printf(" %02x", val);
353 tmp += tmp2;
354 g_free( tmp2 );
355 if ( val > 32 && val < 127 ) {
356 tmp2 = g_strdup_printf( " '%c'", (gchar)val );
357 tmp += tmp2;
358 g_free( tmp2 );
359 } else {
360 tmp += " . ";
361 }
362 } else {
363 tmp += " ";
364 }
366 if ( i < cstrLen ) {
367 int val = (0x0ff & cstr[i]);
368 gchar* tmp2 = g_strdup_printf(" %02x", val);
369 tmp += tmp2;
370 g_free(tmp2);
371 if ( val > 32 && val < 127 ) {
372 tmp2 = g_strdup_printf(" '%c'", (gchar) val);
373 tmp += tmp2;
374 g_free( tmp2 );
375 } else {
376 tmp += " . ";
377 }
378 } else {
379 tmp += " ";
380 }
382 g_message( "%s", tmp.c_str() );
383 }
384 } catch (...) {
385 g_message("XXXXXXXXXXXXXXXXXX Exception" );
386 }
387 g_message("---------------");
388 }
390 /**
391 * Display an file Open selector. Open a document if OK is pressed.
392 * Can select single or multiple files for opening.
393 */
394 void
395 sp_file_open_dialog(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
396 {
397 //# Get the current directory for finding files
398 static Glib::ustring open_path;
399 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
401 if(open_path.empty())
402 {
403 Glib::ustring attr = prefs->getString("/dialogs/open/path");
404 if (!attr.empty()) open_path = attr;
405 }
407 //# Test if the open_path directory exists
408 if (!Inkscape::IO::file_test(open_path.c_str(),
409 (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
410 open_path = "";
412 #ifdef WIN32
413 //# If no open path, default to our win32 documents folder
414 if (open_path.empty())
415 {
416 // The path to the My Documents folder is read from the
417 // value "HKEY_CURRENT_USER\Software\Windows\CurrentVersion\Explorer\Shell Folders\Personal"
418 HKEY key = NULL;
419 if(RegOpenKeyExA(HKEY_CURRENT_USER,
420 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
421 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
422 {
423 WCHAR utf16path[_MAX_PATH];
424 DWORD value_type;
425 DWORD data_size = sizeof(utf16path);
426 if(RegQueryValueExW(key, L"Personal", NULL, &value_type,
427 (BYTE*)utf16path, &data_size) == ERROR_SUCCESS)
428 {
429 g_assert(value_type == REG_SZ);
430 gchar *utf8path = g_utf16_to_utf8(
431 (const gunichar2*)utf16path, -1, NULL, NULL, NULL);
432 if(utf8path)
433 {
434 open_path = Glib::ustring(utf8path);
435 g_free(utf8path);
436 }
437 }
438 }
439 }
440 #endif
442 //# If no open path, default to our home directory
443 if (open_path.empty())
444 {
445 open_path = g_get_home_dir();
446 open_path.append(G_DIR_SEPARATOR_S);
447 }
449 //# Create a dialog if we don't already have one
450 Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance =
451 Inkscape::UI::Dialog::FileOpenDialog::create(
452 parentWindow, open_path,
453 Inkscape::UI::Dialog::SVG_TYPES,
454 _("Select file to open"));
456 //# Show the dialog
457 bool const success = openDialogInstance->show();
459 //# Save the folder the user selected for later
460 open_path = openDialogInstance->getCurrentDirectory();
462 if (!success)
463 {
464 delete openDialogInstance;
465 return;
466 }
468 //# User selected something. Get name and type
469 Glib::ustring fileName = openDialogInstance->getFilename();
471 Inkscape::Extension::Extension *selection =
472 openDialogInstance->getSelectionType();
474 //# Code to check & open if multiple files.
475 std::vector<Glib::ustring> flist = openDialogInstance->getFilenames();
477 //# We no longer need the file dialog object - delete it
478 delete openDialogInstance;
479 openDialogInstance = NULL;
481 //# Iterate through filenames if more than 1
482 if (flist.size() > 1)
483 {
484 for (unsigned int i = 0; i < flist.size(); i++)
485 {
486 fileName = flist[i];
488 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
489 if ( newFileName.size() > 0 )
490 fileName = newFileName;
491 else
492 g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
494 #ifdef INK_DUMP_FILENAME_CONV
495 g_message("Opening File %s\n", fileName.c_str());
496 #endif
497 sp_file_open(fileName, selection);
498 }
500 return;
501 }
504 if (!fileName.empty())
505 {
506 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
508 if ( newFileName.size() > 0)
509 fileName = newFileName;
510 else
511 g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
513 open_path = Glib::path_get_dirname (fileName);
514 open_path.append(G_DIR_SEPARATOR_S);
515 prefs->setString("/dialogs/open/path", open_path);
517 sp_file_open(fileName, selection);
518 }
520 return;
521 }
524 /*######################
525 ## V A C U U M
526 ######################*/
528 /**
529 * Remove unreferenced defs from the defs section of the document.
530 */
533 void
534 sp_file_vacuum()
535 {
536 SPDocument *doc = SP_ACTIVE_DOCUMENT;
538 unsigned int diff = vacuum_document (doc);
540 sp_document_done(doc, SP_VERB_FILE_VACUUM,
541 _("Vacuum <defs>"));
543 SPDesktop *dt = SP_ACTIVE_DESKTOP;
544 if (diff > 0) {
545 dt->messageStack()->flashF(Inkscape::NORMAL_MESSAGE,
546 ngettext("Removed <b>%i</b> unused definition in <defs>.",
547 "Removed <b>%i</b> unused definitions in <defs>.",
548 diff),
549 diff);
550 } else {
551 dt->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No unused definitions in <defs>."));
552 }
553 }
557 /*######################
558 ## S A V E
559 ######################*/
561 /**
562 * This 'save' function called by the others below
563 *
564 * \param official whether to set :output_module and :modified in the
565 * document; is true for normal save, false for temporary saves
566 */
567 static bool
568 file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::ustring &uri,
569 Inkscape::Extension::Extension *key, bool saveas, bool official)
570 {
571 if (!doc || uri.size()<1) //Safety check
572 return false;
574 try {
575 Inkscape::Extension::save(key, doc, uri.c_str(),
576 false,
577 saveas, official);
578 } catch (Inkscape::Extension::Output::no_extension_found &e) {
579 gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str());
580 gchar *text = g_strdup_printf(_("No Inkscape extension found to save document (%s). This may have been caused by an unknown filename extension."), safeUri);
581 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
582 sp_ui_error_dialog(text);
583 g_free(text);
584 g_free(safeUri);
585 return FALSE;
586 } catch (Inkscape::Extension::Output::save_failed &e) {
587 gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str());
588 gchar *text = g_strdup_printf(_("File %s could not be saved."), safeUri);
589 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
590 sp_ui_error_dialog(text);
591 g_free(text);
592 g_free(safeUri);
593 return FALSE;
594 } catch (Inkscape::Extension::Output::save_cancelled &e) {
595 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
596 return FALSE;
597 } catch (Inkscape::Extension::Output::no_overwrite &e) {
598 return sp_file_save_dialog(parentWindow, doc);
599 }
601 SP_ACTIVE_DESKTOP->event_log->rememberFileSave();
602 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Document saved."));
603 return true;
604 }
606 /*
607 * Used only for remote saving using VFS and a specific uri. Gets the file at the /tmp.
608 */
609 bool
610 file_save_remote(SPDocument */*doc*/,
611 #ifdef WITH_GNOME_VFS
612 const Glib::ustring &uri,
613 #else
614 const Glib::ustring &/*uri*/,
615 #endif
616 Inkscape::Extension::Extension */*key*/, bool /*saveas*/, bool /*official*/)
617 {
618 #ifdef WITH_GNOME_VFS
620 #define BUF_SIZE 8192
621 gnome_vfs_init();
623 GnomeVFSHandle *from_handle = NULL;
624 GnomeVFSHandle *to_handle = NULL;
625 GnomeVFSFileSize bytes_read;
626 GnomeVFSFileSize bytes_written;
627 GnomeVFSResult result;
628 guint8 buffer[8192];
630 gchar* uri_local = g_filename_from_utf8( uri.c_str(), -1, NULL, NULL, NULL);
632 if ( uri_local == NULL ) {
633 g_warning( "Error converting filename to locale encoding.");
634 }
636 // Gets the temp file name.
637 Glib::ustring fileName = Glib::get_tmp_dir ();
638 fileName.append(G_DIR_SEPARATOR_S);
639 fileName.append((gnome_vfs_uri_extract_short_name(gnome_vfs_uri_new(uri_local))));
641 // Open the temp file to send.
642 result = gnome_vfs_open (&from_handle, fileName.c_str(), GNOME_VFS_OPEN_READ);
644 if (result != GNOME_VFS_OK) {
645 g_warning("Could not find the temp saving.");
646 return false;
647 }
649 result = gnome_vfs_create (&to_handle, uri_local, GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL);
650 result = gnome_vfs_open (&to_handle, uri_local, GNOME_VFS_OPEN_WRITE);
652 if (result != GNOME_VFS_OK) {
653 g_warning("file creating: %s", gnome_vfs_result_to_string(result));
654 return false;
655 }
657 while (1) {
659 result = gnome_vfs_read (from_handle, buffer, 8192, &bytes_read);
661 if ((result == GNOME_VFS_ERROR_EOF) &&(!bytes_read)){
662 result = gnome_vfs_close (from_handle);
663 result = gnome_vfs_close (to_handle);
664 return true;
665 }
667 if (result != GNOME_VFS_OK) {
668 g_warning("%s", gnome_vfs_result_to_string(result));
669 return false;
670 }
671 result = gnome_vfs_write (to_handle, buffer, bytes_read, &bytes_written);
672 if (result != GNOME_VFS_OK) {
673 g_warning("%s", gnome_vfs_result_to_string(result));
674 return false;
675 }
678 if (bytes_read != bytes_written){
679 return false;
680 }
682 }
683 return true;
684 #else
685 // in case we do not have GNOME_VFS
686 return false;
687 #endif
689 }
692 /**
693 * Display a SaveAs dialog. Save the document if OK pressed.
694 *
695 * \param ascopy (optional) wether to set the documents->uri to the new filename or not
696 */
697 bool
698 sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, bool is_copy)
699 {
701 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
702 Inkscape::Extension::Output *extension = 0;
703 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
705 //# Get the default extension name
706 Glib::ustring default_extension;
707 char *attr = (char *)repr->attribute("inkscape:output_extension");
708 if (!attr) {
709 Glib::ustring attr2 = prefs->getString("/dialogs/save_as/default");
710 if(!attr2.empty()) default_extension = attr2;
711 } else {
712 default_extension = attr;
713 }
714 //g_message("%s: extension name: '%s'", __FUNCTION__, default_extension);
716 Glib::ustring save_path;
717 Glib::ustring save_loc;
719 if (doc->uri == NULL) {
720 char formatBuf[256];
721 int i = 1;
723 Glib::ustring filename_extension = ".svg";
724 extension = dynamic_cast<Inkscape::Extension::Output *>
725 (Inkscape::Extension::db.get(default_extension.c_str()));
726 //g_warning("%s: extension ptr: 0x%x", __FUNCTION__, (unsigned int)extension);
727 if (extension)
728 filename_extension = extension->get_extension();
730 Glib::ustring attr3 = prefs->getString("/dialogs/save_as/path");
731 if (!attr3.empty())
732 save_path = attr3;
734 if (!Inkscape::IO::file_test(save_path.c_str(),
735 (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
736 save_path = "";
738 if (save_path.size()<1)
739 save_path = g_get_home_dir();
741 save_loc = save_path;
742 save_loc.append(G_DIR_SEPARATOR_S);
743 snprintf(formatBuf, 255, _("drawing%s"), filename_extension.c_str());
744 save_loc.append(formatBuf);
746 while (Inkscape::IO::file_test(save_loc.c_str(), G_FILE_TEST_EXISTS)) {
747 save_loc = save_path;
748 save_loc.append(G_DIR_SEPARATOR_S);
749 snprintf(formatBuf, 255, _("drawing-%d%s"), i++, filename_extension.c_str());
750 save_loc.append(formatBuf);
751 }
752 } else {
753 save_loc = Glib::build_filename(Glib::path_get_dirname(doc->uri),
754 Glib::path_get_basename(doc->uri));
755 }
757 // convert save_loc from utf-8 to locale
758 // is this needed any more, now that everything is handled in
759 // Inkscape::IO?
760 Glib::ustring save_loc_local = Glib::filename_from_utf8(save_loc);
762 if ( save_loc_local.size() > 0)
763 save_loc = save_loc_local;
765 //# Show the SaveAs dialog
766 char const * dialog_title;
767 if (is_copy) {
768 dialog_title = (char const *) _("Select file to save a copy to");
769 } else {
770 dialog_title = (char const *) _("Select file to save to");
771 }
772 gchar* doc_title = doc->root->title();
773 Inkscape::UI::Dialog::FileSaveDialog *saveDialog =
774 Inkscape::UI::Dialog::FileSaveDialog::create(
775 parentWindow,
776 save_loc,
777 Inkscape::UI::Dialog::SVG_TYPES,
778 dialog_title,
779 default_extension,
780 doc_title ? doc_title : ""
781 );
783 saveDialog->setSelectionType(extension);
785 bool success = saveDialog->show();
786 if (!success) {
787 delete saveDialog;
788 return success;
789 }
791 // set new title here (call RDF to ensure metadata and title element are updated)
792 rdf_set_work_entity(doc, rdf_find_entity("title"), saveDialog->getDocTitle().c_str());
793 // free up old string
794 if(doc_title) g_free(doc_title);
796 Glib::ustring fileName = saveDialog->getFilename();
797 Inkscape::Extension::Extension *selectionType = saveDialog->getSelectionType();
799 delete saveDialog;
801 saveDialog = 0;
803 if (fileName.size() > 0) {
804 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
806 if ( newFileName.size()>0 )
807 fileName = newFileName;
808 else
809 g_warning( "Error converting save filename to UTF-8." );
811 success = file_save(parentWindow, doc, fileName, selectionType, TRUE, !is_copy);
813 if (success) {
814 sp_file_add_recent(SP_DOCUMENT_URI(doc));
815 }
817 save_path = Glib::path_get_dirname(fileName);
818 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
819 prefs->setString("/dialogs/save_as/path", save_path);
821 return success;
822 }
825 return false;
826 }
829 /**
830 * Save a document, displaying a SaveAs dialog if necessary.
831 */
832 bool
833 sp_file_save_document(Gtk::Window &parentWindow, SPDocument *doc)
834 {
835 bool success = true;
837 if (doc->isModifiedSinceSave()) {
838 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
839 if ( doc->uri == NULL
840 || repr->attribute("inkscape:output_extension") == NULL )
841 {
842 return sp_file_save_dialog(parentWindow, doc, FALSE);
843 } else {
844 gchar const *fn = g_strdup(doc->uri);
845 gchar const *ext = repr->attribute("inkscape:output_extension");
846 success = file_save(parentWindow, doc, fn, Inkscape::Extension::db.get(ext), FALSE, TRUE);
847 g_free((void *) fn);
848 }
849 } else {
850 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No changes need to be saved."));
851 success = TRUE;
852 }
854 return success;
855 }
858 /**
859 * Save a document.
860 */
861 bool
862 sp_file_save(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
863 {
864 if (!SP_ACTIVE_DOCUMENT)
865 return false;
867 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Saving document..."));
869 sp_namedview_document_from_window(SP_ACTIVE_DESKTOP);
870 return sp_file_save_document(parentWindow, SP_ACTIVE_DOCUMENT);
871 }
874 /**
875 * Save a document, always displaying the SaveAs dialog.
876 */
877 bool
878 sp_file_save_as(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
879 {
880 if (!SP_ACTIVE_DOCUMENT)
881 return false;
882 sp_namedview_document_from_window(SP_ACTIVE_DESKTOP);
883 return sp_file_save_dialog(parentWindow, SP_ACTIVE_DOCUMENT, FALSE);
884 }
888 /**
889 * Save a copy of a document, always displaying a sort of SaveAs dialog.
890 */
891 bool
892 sp_file_save_a_copy(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
893 {
894 if (!SP_ACTIVE_DOCUMENT)
895 return false;
896 sp_namedview_document_from_window(SP_ACTIVE_DESKTOP);
897 return sp_file_save_dialog(parentWindow, SP_ACTIVE_DOCUMENT, TRUE);
898 }
901 /*######################
902 ## I M P O R T
903 ######################*/
905 /**
906 * Import a resource. Called by sp_file_import()
907 */
908 void
909 file_import(SPDocument *in_doc, const Glib::ustring &uri,
910 Inkscape::Extension::Extension *key)
911 {
912 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
914 //DEBUG_MESSAGE( fileImport, "file_import( in_doc:%p uri:[%s], key:%p", in_doc, uri, key );
915 SPDocument *doc;
916 try {
917 doc = Inkscape::Extension::open(key, uri.c_str());
918 } catch (Inkscape::Extension::Input::no_extension_found &e) {
919 doc = NULL;
920 } catch (Inkscape::Extension::Input::open_failed &e) {
921 doc = NULL;
922 }
924 if (doc != NULL) {
925 Inkscape::IO::fixupHrefs(doc, in_doc->base, true);
926 Inkscape::XML::Document *xml_in_doc = sp_document_repr_doc(in_doc);
928 prevent_id_clashes(doc, in_doc);
930 SPObject *in_defs = SP_DOCUMENT_DEFS(in_doc);
931 Inkscape::XML::Node *last_def = SP_OBJECT_REPR(in_defs)->lastChild();
933 SPCSSAttr *style = sp_css_attr_from_object(SP_DOCUMENT_ROOT(doc));
935 // Count the number of top-level items in the imported document.
936 guint items_count = 0;
937 for (SPObject *child = sp_object_first_child(SP_DOCUMENT_ROOT(doc));
938 child != NULL; child = SP_OBJECT_NEXT(child))
939 {
940 if (SP_IS_ITEM(child)) items_count++;
941 }
943 // Create a new group if necessary.
944 Inkscape::XML::Node *newgroup = NULL;
945 if ((style && style->firstChild()) || items_count > 1) {
946 newgroup = xml_in_doc->createElement("svg:g");
947 sp_repr_css_set(newgroup, style, "style");
948 }
950 // Determine the place to insert the new object.
951 // This will be the current layer, if possible.
952 // FIXME: If there's no desktop (command line run?) we need
953 // a document:: method to return the current layer.
954 // For now, we just use the root in this case.
955 SPObject *place_to_insert;
956 if (desktop) place_to_insert = desktop->currentLayer();
957 else place_to_insert = SP_DOCUMENT_ROOT(in_doc);
959 // Construct a new object representing the imported image,
960 // and insert it into the current document.
961 SPObject *new_obj = NULL;
962 for (SPObject *child = sp_object_first_child(SP_DOCUMENT_ROOT(doc));
963 child != NULL; child = SP_OBJECT_NEXT(child) )
964 {
965 if (SP_IS_ITEM(child)) {
966 Inkscape::XML::Node *newitem = SP_OBJECT_REPR(child)->duplicate(xml_in_doc);
968 // convert layers to groups, and make sure they are unlocked
969 // FIXME: add "preserve layers" mode where each layer from
970 // import is copied to the same-named layer in host
971 newitem->setAttribute("inkscape:groupmode", NULL);
972 newitem->setAttribute("sodipodi:insensitive", NULL);
974 if (newgroup) newgroup->appendChild(newitem);
975 else new_obj = place_to_insert->appendChildRepr(newitem);
976 }
978 // don't lose top-level defs or style elements
979 else if (SP_OBJECT_REPR(child)->type() == Inkscape::XML::ELEMENT_NODE) {
980 const gchar *tag = SP_OBJECT_REPR(child)->name();
981 if (!strcmp(tag, "svg:defs")) {
982 for (SPObject *x = sp_object_first_child(child);
983 x != NULL; x = SP_OBJECT_NEXT(x))
984 {
985 SP_OBJECT_REPR(in_defs)->addChild(SP_OBJECT_REPR(x)->duplicate(xml_in_doc), last_def);
986 }
987 }
988 else if (!strcmp(tag, "svg:style")) {
989 SP_DOCUMENT_ROOT(in_doc)->appendChildRepr(SP_OBJECT_REPR(child)->duplicate(xml_in_doc));
990 }
991 }
992 }
993 if (newgroup) new_obj = place_to_insert->appendChildRepr(newgroup);
995 // release some stuff
996 if (newgroup) Inkscape::GC::release(newgroup);
997 if (style) sp_repr_css_attr_unref(style);
999 // select and move the imported item
1000 if (new_obj && SP_IS_ITEM(new_obj)) {
1001 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1002 selection->set(SP_ITEM(new_obj));
1004 // To move the imported object, we must temporarily set the "transform pattern with
1005 // object" option.
1006 {
1007 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1008 bool const saved_pref = prefs->getBool("/options/transform/pattern", true);
1009 prefs->setBool("/options/transform/pattern", true);
1010 sp_document_ensure_up_to_date(sp_desktop_document(desktop));
1011 Geom::OptRect sel_bbox = selection->bounds();
1012 if (sel_bbox) {
1013 Geom::Point m( desktop->point() - sel_bbox->midpoint() );
1014 sp_selection_move_relative(selection, m);
1015 }
1016 prefs->setBool("/options/transform/pattern", saved_pref);
1017 }
1018 }
1020 sp_document_unref(doc);
1021 sp_document_done(in_doc, SP_VERB_FILE_IMPORT,
1022 _("Import"));
1024 } else {
1025 gchar *text = g_strdup_printf(_("Failed to load the requested file %s"), uri.c_str());
1026 sp_ui_error_dialog(text);
1027 g_free(text);
1028 }
1030 return;
1031 }
1034 static Inkscape::UI::Dialog::FileOpenDialog *importDialogInstance = NULL;
1036 /**
1037 * Display an Open dialog, import a resource if OK pressed.
1038 */
1039 void
1040 sp_file_import(Gtk::Window &parentWindow)
1041 {
1042 static Glib::ustring import_path;
1044 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1045 if (!doc)
1046 return;
1048 if (!importDialogInstance) {
1049 importDialogInstance =
1050 Inkscape::UI::Dialog::FileOpenDialog::create(
1051 parentWindow,
1052 import_path,
1053 Inkscape::UI::Dialog::IMPORT_TYPES,
1054 (char const *)_("Select file to import"));
1055 }
1057 bool success = importDialogInstance->show();
1058 if (!success)
1059 return;
1061 //# Get file name and extension type
1062 Glib::ustring fileName = importDialogInstance->getFilename();
1063 Inkscape::Extension::Extension *selection =
1064 importDialogInstance->getSelectionType();
1067 if (fileName.size() > 0) {
1069 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
1071 if ( newFileName.size() > 0)
1072 fileName = newFileName;
1073 else
1074 g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
1077 import_path = fileName;
1078 if (import_path.size()>0)
1079 import_path.append(G_DIR_SEPARATOR_S);
1081 file_import(doc, fileName, selection);
1082 }
1084 return;
1085 }
1089 /*######################
1090 ## E X P O R T
1091 ######################*/
1093 //#define NEW_EXPORT_DIALOG
1097 #ifdef NEW_EXPORT_DIALOG
1099 static Inkscape::UI::Dialog::FileExportDialog *exportDialogInstance = NULL;
1101 /**
1102 * Display an Export dialog, export as the selected type if OK pressed
1103 */
1104 bool
1105 sp_file_export_dialog(void *widget)
1106 {
1107 //# temp hack for 'doc' until we can switch to this dialog
1108 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1110 Glib::ustring export_path;
1111 Glib::ustring export_loc;
1113 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
1114 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1115 Inkscape::Extension::Output *extension;
1117 //# Get the default extension name
1118 Glib::ustring default_extension;
1119 char *attr = (char *)repr->attribute("inkscape:output_extension");
1120 if (!attr) {
1121 Glib::ustring attr2 = prefs->getString("/dialogs/save_as/default");
1122 if(!attr2.empty()) default_extension = attr2;
1123 } else {
1124 default_extension = attr;
1125 }
1126 //g_message("%s: extension name: '%s'", __FUNCTION__, default_extension);
1128 if (doc->uri == NULL)
1129 {
1130 char formatBuf[256];
1132 Glib::ustring filename_extension = ".svg";
1133 extension = dynamic_cast<Inkscape::Extension::Output *>
1134 (Inkscape::Extension::db.get(default_extension.c_str()));
1135 //g_warning("%s: extension ptr: 0x%x", __FUNCTION__, (unsigned int)extension);
1136 if (extension)
1137 filename_extension = extension->get_extension();
1139 Glib::ustring attr3 = prefs->getString("/dialogs/save_as/path");
1140 if (!attr3.empty())
1141 export_path = attr3;
1143 if (!Inkscape::IO::file_test(export_path.c_str(),
1144 (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1145 export_path = "";
1147 if (export_path.size()<1)
1148 export_path = g_get_home_dir();
1150 export_loc = export_path;
1151 export_loc.append(G_DIR_SEPARATOR_S);
1152 snprintf(formatBuf, 255, _("drawing%s"), filename_extension.c_str());
1153 export_loc.append(formatBuf);
1155 }
1156 else
1157 {
1158 export_path = Glib::path_get_dirname(doc->uri);
1159 }
1161 // convert save_loc from utf-8 to locale
1162 // is this needed any more, now that everything is handled in
1163 // Inkscape::IO?
1164 Glib::ustring export_path_local = Glib::filename_from_utf8(export_path);
1165 if ( export_path_local.size() > 0)
1166 export_path = export_path_local;
1168 //# Show the SaveAs dialog
1169 if (!exportDialogInstance)
1170 exportDialogInstance =
1171 Inkscape::UI::Dialog::FileExportDialog::create(
1172 export_path,
1173 Inkscape::UI::Dialog::EXPORT_TYPES,
1174 (char const *) _("Select file to export to"),
1175 default_extension
1176 );
1178 bool success = exportDialogInstance->show();
1179 if (!success)
1180 return success;
1182 Glib::ustring fileName = exportDialogInstance->getFilename();
1184 Inkscape::Extension::Extension *selectionType =
1185 exportDialogInstance->getSelectionType();
1188 if (fileName.size() > 0) {
1189 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
1191 if ( newFileName.size()>0 )
1192 fileName = newFileName;
1193 else
1194 g_warning( "Error converting save filename to UTF-8." );
1196 success = file_save(doc, fileName, selectionType, TRUE, FALSE);
1198 if (success) {
1199 Glib::RefPtr<Gtk::RecentManager> recent = Gtk::RecentManager::get_default();
1200 recent->add_item(SP_DOCUMENT_URI(doc));
1201 }
1203 export_path = fileName;
1204 prefs->setString("/dialogs/save_as/path", export_path);
1206 return success;
1207 }
1210 return false;
1211 }
1213 #else
1215 /**
1216 *
1217 */
1218 bool
1219 sp_file_export_dialog(void */*widget*/)
1220 {
1221 sp_export_dialog();
1222 return true;
1223 }
1225 #endif
1227 /*######################
1228 ## E X P O R T T O O C A L
1229 ######################*/
1231 /**
1232 * Display an Export dialog, export as the selected type if OK pressed
1233 */
1234 bool
1235 sp_file_export_to_ocal_dialog(Gtk::Window &parentWindow)
1236 {
1238 if (!SP_ACTIVE_DOCUMENT)
1239 return false;
1241 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1243 Glib::ustring export_path;
1244 Glib::ustring export_loc;
1245 Glib::ustring fileName;
1246 Inkscape::Extension::Extension *selectionType;
1248 bool success = false;
1250 static Inkscape::UI::Dialog::FileExportToOCALDialog *exportDialogInstance = NULL;
1251 static Inkscape::UI::Dialog::FileExportToOCALPasswordDialog *exportPasswordDialogInstance = NULL;
1252 static bool gotSuccess = false;
1254 Inkscape::XML::Node *repr = sp_document_repr_root(doc);
1255 (void)repr;
1257 if (!doc->uri && !doc->isModifiedSinceSave())
1258 return false;
1260 // Get the default extension name
1261 Glib::ustring default_extension = "org.inkscape.output.svg.inkscape";
1262 char formatBuf[256];
1264 Glib::ustring filename_extension = ".svg";
1265 selectionType = Inkscape::Extension::db.get(default_extension.c_str());
1267 export_path = Glib::get_tmp_dir ();
1269 export_loc = export_path;
1270 export_loc.append(G_DIR_SEPARATOR_S);
1271 snprintf(formatBuf, 255, _("drawing%s"), filename_extension.c_str());
1272 export_loc.append(formatBuf);
1274 // convert save_loc from utf-8 to locale
1275 // is this needed any more, now that everything is handled in
1276 // Inkscape::IO?
1277 Glib::ustring export_path_local = Glib::filename_from_utf8(export_path);
1278 if ( export_path_local.size() > 0)
1279 export_path = export_path_local;
1281 // Show the Export To OCAL dialog
1282 if (!exportDialogInstance)
1283 exportDialogInstance = new Inkscape::UI::Dialog::FileExportToOCALDialog(
1284 parentWindow,
1285 Inkscape::UI::Dialog::EXPORT_TYPES,
1286 (char const *) _("Select file to export to")
1287 );
1289 success = exportDialogInstance->show();
1290 if (!success)
1291 return success;
1293 fileName = exportDialogInstance->getFilename();
1295 fileName.append(filename_extension.c_str());
1296 if (fileName.size() > 0) {
1297 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
1299 if ( newFileName.size()>0 )
1300 fileName = newFileName;
1301 else
1302 g_warning( "Error converting save filename to UTF-8." );
1303 }
1304 Glib::ustring filePath = export_path;
1305 filePath.append(G_DIR_SEPARATOR_S);
1306 filePath.append(Glib::path_get_basename(fileName));
1308 fileName = filePath;
1310 success = file_save(parentWindow, doc, filePath, selectionType, FALSE, FALSE);
1312 if (!success){
1313 gchar *text = g_strdup_printf(_("Error saving a temporary copy"));
1314 sp_ui_error_dialog(text);
1316 return success;
1317 }
1319 // Start now the submition
1321 // Create the uri
1322 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1323 Glib::ustring uri = "dav://";
1324 Glib::ustring username = prefs->getString("/options/ocalusername/str");
1325 Glib::ustring password = prefs->getString("/options/ocalpassword/str");
1326 if (username.empty() || password.empty())
1327 {
1328 if(!gotSuccess)
1329 {
1330 if (!exportPasswordDialogInstance)
1331 exportPasswordDialogInstance = new Inkscape::UI::Dialog::FileExportToOCALPasswordDialog(
1332 parentWindow,
1333 (char const *) _("Open Clip Art Login"));
1334 success = exportPasswordDialogInstance->show();
1335 if (!success)
1336 return success;
1337 }
1338 username = exportPasswordDialogInstance->getUsername();
1339 password = exportPasswordDialogInstance->getPassword();
1340 }
1341 uri.append(username);
1342 uri.append(":");
1343 uri.append(password);
1344 uri.append("@");
1345 uri.append(prefs->getString("/options/ocalurl/str"));
1346 uri.append("/dav.php/");
1347 uri.append(Glib::path_get_basename(fileName));
1349 // Save as a remote file using the dav protocol.
1350 success = file_save_remote(doc, uri, selectionType, FALSE, FALSE);
1351 remove(fileName.c_str());
1352 if (!success)
1353 {
1354 gchar *text = g_strdup_printf(_("Error exporting the document. Verify if the server name, username and password are correct, if the server has support for webdav and verify if you didn't forget to choose a license."));
1355 sp_ui_error_dialog(text);
1356 }
1357 else
1358 gotSuccess = true;
1360 return success;
1361 }
1363 /**
1364 * Export the current document to OCAL
1365 */
1366 void
1367 sp_file_export_to_ocal(Gtk::Window &parentWindow)
1368 {
1370 // Try to execute the new code and return;
1371 if (!SP_ACTIVE_DOCUMENT)
1372 return;
1373 bool success = sp_file_export_to_ocal_dialog(parentWindow);
1374 if (success)
1375 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Document exported..."));
1376 }
1379 /*######################
1380 ## I M P O R T F R O M O C A L
1381 ######################*/
1383 /**
1384 * Display an ImportToOcal Dialog, and the selected document from OCAL
1385 */
1386 void
1387 sp_file_import_from_ocal(Gtk::Window &parentWindow)
1388 {
1389 static Glib::ustring import_path;
1391 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1392 if (!doc)
1393 return;
1395 static Inkscape::UI::Dialog::FileImportFromOCALDialog *importDialogInstance = NULL;
1397 if (!importDialogInstance) {
1398 importDialogInstance = new
1399 Inkscape::UI::Dialog::FileImportFromOCALDialog(
1400 parentWindow,
1401 import_path,
1402 Inkscape::UI::Dialog::IMPORT_TYPES,
1403 (char const *)_("Import From Open Clip Art Library"));
1404 }
1406 bool success = importDialogInstance->show();
1407 if (!success)
1408 return;
1410 // Get file name and extension type
1411 Glib::ustring fileName = importDialogInstance->getFilename();
1412 Inkscape::Extension::Extension *selection =
1413 importDialogInstance->getSelectionType();
1415 if (fileName.size() > 0) {
1417 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
1419 if ( newFileName.size() > 0)
1420 fileName = newFileName;
1421 else
1422 g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
1424 import_path = fileName;
1425 if (import_path.size()>0)
1426 import_path.append(G_DIR_SEPARATOR_S);
1428 file_import(doc, fileName, selection);
1429 }
1431 return;
1432 }
1434 /*######################
1435 ## P R I N T
1436 ######################*/
1439 /**
1440 * Print the current document, if any.
1441 */
1442 void
1443 sp_file_print(Gtk::Window& parentWindow)
1444 {
1445 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1446 if (doc)
1447 sp_print_document(parentWindow, doc);
1448 }
1450 /**
1451 * Display what the drawing would look like, if
1452 * printed.
1453 */
1454 void
1455 sp_file_print_preview(gpointer /*object*/, gpointer /*data*/)
1456 {
1458 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1459 if (doc)
1460 sp_print_preview_document(doc);
1462 }
1464 void Inkscape::IO::fixupHrefs( SPDocument *doc, const gchar *base, gboolean spns )
1465 {
1466 //g_message("Inkscape::IO::fixupHrefs( , [%s], )", base );
1468 if ( 0 ) {
1469 gchar const* things[] = {
1470 "data:foo,bar",
1471 "http://www.google.com/image.png",
1472 "ftp://ssd.com/doo",
1473 "/foo/dee/bar.svg",
1474 "foo.svg",
1475 "file:/foo/dee/bar.svg",
1476 "file:///foo/dee/bar.svg",
1477 "file:foo.svg",
1478 "/foo/bar\xe1\x84\x92.svg",
1479 "file:///foo/bar\xe1\x84\x92.svg",
1480 "file:///foo/bar%e1%84%92.svg",
1481 "/foo/bar%e1%84%92.svg",
1482 "bar\xe1\x84\x92.svg",
1483 "bar%e1%84%92.svg",
1484 NULL
1485 };
1486 g_message("+------");
1487 for ( int i = 0; things[i]; i++ )
1488 {
1489 try
1490 {
1491 URI uri(things[i]);
1492 gboolean isAbs = g_path_is_absolute( things[i] );
1493 gchar *str = uri.toString();
1494 g_message( "abs:%d isRel:%d scheme:[%s] path:[%s][%s] uri[%s] / [%s]", (int)isAbs,
1495 (int)uri.isRelative(),
1496 uri.getScheme(),
1497 uri.getPath(),
1498 uri.getOpaque(),
1499 things[i],
1500 str );
1501 g_free(str);
1502 }
1503 catch ( MalformedURIException err )
1504 {
1505 dump_str( things[i], "MalformedURIException" );
1506 xmlChar *redo = xmlURIEscape((xmlChar const *)things[i]);
1507 g_message(" gone from [%s] to [%s]", things[i], redo );
1508 if ( redo == NULL )
1509 {
1510 URI again = URI::fromUtf8( things[i] );
1511 gboolean isAbs = g_path_is_absolute( things[i] );
1512 gchar *str = again.toString();
1513 g_message( "abs:%d isRel:%d scheme:[%s] path:[%s][%s] uri[%s] / [%s]", (int)isAbs,
1514 (int)again.isRelative(),
1515 again.getScheme(),
1516 again.getPath(),
1517 again.getOpaque(),
1518 things[i],
1519 str );
1520 g_free(str);
1521 g_message(" ----");
1522 }
1523 }
1524 }
1525 g_message("+------");
1526 }
1528 GSList const *images = sp_document_get_resource_list(doc, "image");
1529 for (GSList const *l = images; l != NULL; l = l->next) {
1530 Inkscape::XML::Node *ir = SP_OBJECT_REPR(l->data);
1532 const gchar *href = ir->attribute("xlink:href");
1534 // First try to figure out an absolute path to the asset
1535 //g_message("image href [%s]", href );
1536 if (spns && !g_path_is_absolute(href)) {
1537 const gchar *absref = ir->attribute("sodipodi:absref");
1538 const gchar *base_href = g_build_filename(base, href, NULL);
1539 //g_message(" absr [%s]", absref );
1541 if ( absref && Inkscape::IO::file_test(absref, G_FILE_TEST_EXISTS) && !Inkscape::IO::file_test(base_href, G_FILE_TEST_EXISTS))
1542 {
1543 // only switch over if the absref is valid while href is not
1544 href = absref;
1545 //g_message(" copied absref to href");
1546 }
1547 }
1549 // Once we have an absolute path, convert it relative to the new location
1550 if (href && g_path_is_absolute(href)) {
1551 const gchar *relname = sp_relative_path_from_path(href, base);
1552 //g_message(" setting to [%s]", relname );
1553 ir->setAttribute("xlink:href", relname);
1554 }
1555 // TODO next refinement is to make the first choice keeping the relative path as-is if
1556 // based on the new location it gives us a valid file.
1557 }
1558 }
1561 /*
1562 Local Variables:
1563 mode:c++
1564 c-file-style:"stroustrup"
1565 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1566 indent-tabs-mode:nil
1567 fill-column:99
1568 End:
1569 */
1570 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :