Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
file.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
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 * Jon A. Cruz <jon@joncruz.org>
13 * Abhishek Sharma
14 * Tavmjong Bah
15 *
16 * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
17 * Copyright (C) 1999-2016 Authors
18 * Copyright (C) 2004 David Turner
19 * Copyright (C) 2001-2002 Ximian, Inc.
20 *
21 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
22 */
23
30#ifdef HAVE_CONFIG_H
31# include "config.h" // only include where actually required!
32#endif
33
34#include <gtkmm.h>
35
36#include "desktop.h"
37#include "document-undo.h"
38#include "event-log.h"
39#include "extension/db.h"
40#include "extension/effect.h"
41#include "extension/input.h"
42#include "extension/output.h"
43#include "file.h"
44#include "id-clash.h"
46#include "inkscape-version.h"
47#include "inkscape-window.h"
48#include "inkscape.h"
49#include "io/file.h"
50#include "io/fix-broken-links.h"
51#include "io/resource.h"
52#include "io/sys.h"
53#include "layer-manager.h"
55#include "message-stack.h"
56#include "object/sp-defs.h"
57#include "object/sp-namedview.h"
58#include "object/sp-page.h"
59#include "object/sp-root.h"
60#include "object/sp-use.h"
61#include "page-manager.h"
62#include "path-prefix.h"
63#include "print.h"
64#include "rdf.h"
65#include "selection.h"
66#include "style.h"
67#include "svg/svg.h" // for sp_svg_transform_write, used in sp_import_document
70#include "ui/icon-names.h"
71#include "ui/interface.h"
72#include "ui/tools/tool-base.h"
74#include "xml/rebase-hrefs.h"
75#include "xml/sp-css-attr.h"
76
80
81
82/*######################
83## N E W
84######################*/
85
90SPDesktop *sp_file_new(const std::string &templ)
91{
93
94 auto doc = app->document_new(templ);
95 if (!doc) {
96 std::cerr << "sp_file_new: failed to open document: " << templ << std::endl;
97 }
98
99 return app->desktopOpen(doc);
100}
101
103{
104 return Inkscape::IO::Resource::get_filename(TEMPLATES, "default.svg", true);
105}
106
108{
110 //rdf_add_from_preferences( SP_ACTIVE_DOCUMENT );
111
112 return desk;
113}
114
119{
120 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
121 g_assert(desktop != nullptr);
122
124 g_assert(doc != nullptr);
125
126 Inkscape::XML::Node *repr = doc->getReprRoot();
127 g_assert(repr != nullptr);
128
129 gchar const *filename = doc->getDocumentFilename();
130 if (!filename) {
131 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved yet. Cannot revert."));
132 return;
133 }
134
135 bool do_revert = true;
136 if (doc->isModifiedSinceSave()) {
137 Glib::ustring tmpString = Glib::ustring::compose(_("Changes will be lost! Are you sure you want to reload document %1?"), filename);
138 bool response = desktop->warnDialog (tmpString);
139 if (!response) {
140 do_revert = false;
141 }
142 }
143
144 bool reverted = false;
145 if (do_revert) {
146 auto *app = InkscapeApplication::instance();
147 reverted = app->document_revert (doc);
148 }
149
150 if (reverted) {
151 desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Document reverted."));
152 } else {
153 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not reverted."));
154 }
155}
156
157
158/*######################
159## V A C U U M
160######################*/
161
166{
167 unsigned int diff = doc->vacuumDocument();
168
169 DocumentUndo::done(doc, _("Clean up document"), INKSCAPE_ICON("document-cleanup"));
170
171 SPDesktop *dt = SP_ACTIVE_DESKTOP;
172 if (dt != nullptr) {
173 // Show status messages when in GUI mode
174 if (diff > 0) {
176 ngettext("Removed <b>%i</b> unused definition in &lt;defs&gt;.",
177 "Removed <b>%i</b> unused definitions in &lt;defs&gt;.",
178 diff),
179 diff);
180 } else {
181 dt->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No unused definitions in &lt;defs&gt;."));
182 }
183 }
184}
185
186/*######################
187## S A V E
188######################*/
189
196static bool
197file_save(Gtk::Window &parentWindow,
198 SPDocument *doc,
199 const Glib::RefPtr<Gio::File> file,
201 bool checkoverwrite,
202 bool official,
204{
205 if (!doc) { //Safety check
206 return false;
207 }
208
209 auto path = file->get_path();
210 auto display_name = file->get_parse_name();
211
212 Inkscape::Version const saved_version = doc->getRoot()->inkscape.getVersion();
213 doc->getReprRoot()->setAttribute("inkscape:version", Inkscape::version_string);
214 try {
215 Inkscape::Extension::save(key, doc, file->get_path().c_str(),
216 checkoverwrite, official,
217 save_method);
219 gchar *text = g_strdup_printf(_("No Inkscape extension found to save document (%s). This may have been caused by an unknown or missing filename extension."), display_name.c_str());
220 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
221 sp_ui_error_dialog(text);
222 g_free(text);
223 // Restore Inkscape version
224 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
225 return false;
227 gchar *text = g_strdup_printf(_("File %s is write protected. Please remove write protection and try again."), display_name.c_str());
228 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
229 sp_ui_error_dialog(text);
230 g_free(text);
231 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
232 return false;
234 gchar *text = g_strdup_printf(_("File %s could not be saved."), display_name.c_str());
235 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
236 sp_ui_error_dialog(text);
237 g_free(text);
238 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
239 return false;
241 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
242 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
243 return false;
245 gchar *text = g_strdup_printf(_("File could not be saved:\nNo object with ID '%s' found."), e.id);
246 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
247 sp_ui_error_dialog(text);
248 g_free(text);
249 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
250 return false;
252 return sp_file_save_dialog(parentWindow, doc, save_method);
253 } catch (std::exception &e) {
254 gchar *text = g_strdup_printf(_("File %s could not be saved.\n\n"
255 "The following additional information was returned by the output extension:\n"
256 "'%s'"), display_name.c_str(), e.what());
257 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
258 sp_ui_error_dialog(text);
259 g_free(text);
260 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
261 return false;
262 } catch (...) {
263 g_critical("Extension '%s' threw an unspecified exception.", key ? key->get_id() : nullptr);
264 gchar *text = g_strdup_printf(_("File %s could not be saved."), display_name.c_str());
265 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Document not saved."));
266 sp_ui_error_dialog(text);
267 g_free(text);
268 doc->getReprRoot()->setAttribute("inkscape:version", saved_version.str());
269 return false;
270 }
271
272 if (SP_ACTIVE_DESKTOP) {
273 if (! SP_ACTIVE_DESKTOP->messageStack()) {
274 g_message("file_save: ->messageStack() == NULL. please report to bug #967416");
275 }
276 } else {
277 g_message("file_save: SP_ACTIVE_DESKTOP == NULL. please report to bug #967416");
278 }
279
280 auto font_lister = Inkscape::FontLister::get_instance();
281 auto recently_used = Inkscape::RecentlyUsedFonts::get();
282 recently_used->prepend_to_list(font_lister->get_font_family());
283 recently_used->set_continuous_streak(false);
284
286 Glib::ustring msg;
287 if (doc->getDocumentFilename() == nullptr) {
288 msg = Glib::ustring::format(_("Document saved."));
289 } else {
290 msg = Glib::ustring::format(_("Document saved."), " ", doc->getDocumentFilename());
291 }
292 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::NORMAL_MESSAGE, msg.c_str());
293 return true;
294}
295
299bool
300sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, Inkscape::Extension::FileSaveMethod save_method)
301{
302 bool is_copy = (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY);
303
304 // Note: default_extension has the format "org.inkscape.output.svg.inkscape",
305 // whereas filename_extension only uses ".svg"
306 auto default_extension = Inkscape::Extension::get_file_save_extension(save_method);
307 auto extension = dynamic_cast<Inkscape::Extension::Output *>(Inkscape::Extension::db.get(default_extension.c_str()));
308
309 std::string filename_extension = ".svg";
310 if (extension) {
311 filename_extension = extension->get_extension(); // Glib::ustring -> std::string FIXME
312 }
313
314 std::string save_path = Inkscape::Extension::get_file_save_path(doc, save_method); // Glib::ustring -> std::string FIXME
315
316 if (!Inkscape::IO::file_test(save_path.c_str(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
317 save_path.clear();
318 }
319
320 if (save_path.empty()) {
321 save_path = Glib::get_home_dir();
322 }
323
324 std::string save_loc = save_path;
325 save_loc.append(G_DIR_SEPARATOR_S);
326
327 int i = 1;
328 if ( !doc->getDocumentFilename() ) {
329 // We are saving for the first time; create a unique default filename
330 save_loc = save_loc + _("drawing") + filename_extension;
331
332 while (Inkscape::IO::file_test(save_loc.c_str(), G_FILE_TEST_EXISTS)) {
333 save_loc = save_path;
334 save_loc.append(G_DIR_SEPARATOR_S);
335 save_loc = save_loc + Glib::ustring::compose(_("drawing-%1"), i++) + filename_extension;
336 }
337 } else {
338 save_loc.append(Glib::path_get_basename(doc->getDocumentFilename()));
339 }
340
341 // Show the SaveAs dialog.
342 const Glib::ustring dialog_title = is_copy ?
343 _("Select file to save a copy to") :
344 _("Select file to save to");
345
346 // Note, there are currently multiple modules per filename extension (.svg, .dxf, .zip).
347 // We cannot distinguish between them.
348 std::string basename = Glib::path_get_basename(save_loc);
349 std::string dirname = Glib::path_get_dirname(save_loc);
350 auto file = choose_file_save( dialog_title, &parentWindow,
352 basename,
353 dirname);
354
355 if (!file) {
356 return false; // Cancelled
357 }
358
359 // Set title here (call RDF to ensure metadata and title element are updated).
360 // Is this necessary? In 1.4.x, the Windows native dialog shows the title in
361 // an entry which can be changed but 1.5.x doesn't allow that.
362 gchar* doc_title = doc->getRoot()->title();
363 if (doc_title) {
364 rdf_set_work_entity(doc, rdf_find_entity("title"), doc_title);
365 g_free(doc_title);
366 }
367
368 // Find output module from file extension.
369 auto file_extension = Inkscape::IO::get_file_extension(file->get_path());
370
373 bool found = false;
374
375 for (auto omod : extension_list) {
376 if (file_extension == omod->get_extension()) {
377 extension = omod;
378 found = true;
379 break;
380 }
381 }
382
383 if (!found) {
384 std::cerr << "sp_file_save_dialog(): Cannot find output module for file type: "
385 << file_extension << "!" << std::endl;
386 return false;
387 }
388
389 if (file_save(parentWindow, doc, file, extension, true, !is_copy, save_method)) {
390
391 if (doc->getDocumentFilename()) {
392 Glib::RefPtr<Gtk::RecentManager> recent = Gtk::RecentManager::get_default();
393 recent->add_item(file->get_uri()); // Gtk4 add_item(file)
394 }
395
396 save_path = Glib::path_get_dirname(file->get_path());
397 Inkscape::Extension::store_save_path_in_prefs(save_path, save_method);
398
399 return true;
400 }
401
402 return false;
403}
404
408bool
409sp_file_save_document(Gtk::Window &parentWindow, SPDocument *doc)
410{
411 bool success = true;
412
413 if (doc->isModifiedSinceSave()) {
414 if ( doc->getDocumentFilename() == nullptr )
415 {
416 // In this case, an argument should be given that indicates that the document is the first
417 // time saved, so that .svg is selected as the default and not the last one "Save as ..." extension used
419 } else {
420 std::string path = doc->getDocumentFilename();
421
422 // Try to determine the extension from the filename; this may not lead to a valid extension,
423 // but this case is caught in the file_save method below (or rather in Extension::save()
424 // further down the line).
425 std::string ext;
426 std::string::size_type pos = path.rfind('.');
427 if (pos != std::string::npos) {
428 // FIXME: this could/should be more sophisticated (see FileSaveDialog::appendExtension()),
429 // but hopefully it's a reasonable workaround for now
430 ext = path.substr( pos );
431 }
432 auto file = Gio::File::create_for_path(path);
433 success = file_save(parentWindow, doc, file, Inkscape::Extension::db.get(ext.c_str()), false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS);
434 if (success == false) {
435 // give the user the chance to change filename or extension
437 }
438 }
439 } else {
440 Glib::ustring msg;
441 if (doc->getDocumentFilename() == nullptr) {
442 msg = Glib::ustring::format(_("No changes need to be saved."));
443 } else {
444 msg = Glib::ustring::format(_("No changes need to be saved."), " ", doc->getDocumentFilename());
445 }
446 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, msg.c_str());
447 success = true;
448 }
449
450 return success;
451}
452
456bool
457sp_file_save(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
458{
459 if (!SP_ACTIVE_DOCUMENT) {
460 return false;
461 }
462
463 SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Saving document..."));
464
465 sp_namedview_document_from_window(SP_ACTIVE_DESKTOP);
466 return sp_file_save_document(parentWindow, SP_ACTIVE_DOCUMENT);
467}
468
472bool
473sp_file_save_as(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
474{
475 if (!SP_ACTIVE_DOCUMENT) {
476 return false;
477 }
478
479 sp_namedview_document_from_window(SP_ACTIVE_DESKTOP);
480 return sp_file_save_dialog(parentWindow, SP_ACTIVE_DOCUMENT, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS);
481}
482
486bool
487sp_file_save_a_copy(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
488{
489 if (!SP_ACTIVE_DOCUMENT) {
490 return false;
491 }
492
493 sp_namedview_document_from_window(SP_ACTIVE_DESKTOP);
494 return sp_file_save_dialog(parentWindow, SP_ACTIVE_DOCUMENT, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY);
495}
496
500bool
501sp_file_save_template(Gtk::Window &parentWindow, Glib::ustring name,
502 Glib::ustring author, Glib::ustring description, Glib::ustring keywords,
503 bool isDefault)
504{
505 if (!SP_ACTIVE_DOCUMENT || name.length() == 0)
506 return true;
507
508 auto document = SP_ACTIVE_DOCUMENT;
509
510 DocumentUndo::ScopedInsensitive _no_undo(document);
511
512 auto root = document->getReprRoot();
513 auto xml_doc = document->getReprDoc();
514
515 auto templateinfo_node = xml_doc->createElement("inkscape:templateinfo");
516 Inkscape::GC::release(templateinfo_node);
517
518 auto element_node = xml_doc->createElement("inkscape:name");
519 Inkscape::GC::release(element_node);
520
521 element_node->appendChild(xml_doc->createTextNode(name.c_str()));
522 templateinfo_node->appendChild(element_node);
523
524 if (author.length() != 0) {
525
526 element_node = xml_doc->createElement("inkscape:author");
527 Inkscape::GC::release(element_node);
528
529 element_node->appendChild(xml_doc->createTextNode(author.c_str()));
530 templateinfo_node->appendChild(element_node);
531 }
532
533 if (description.length() != 0) {
534
535 element_node = xml_doc->createElement("inkscape:shortdesc");
536 Inkscape::GC::release(element_node);
537
538 element_node->appendChild(xml_doc->createTextNode(description.c_str()));
539 templateinfo_node->appendChild(element_node);
540
541 }
542
543 element_node = xml_doc->createElement("inkscape:date");
544 Inkscape::GC::release(element_node);
545
546 element_node->appendChild(xml_doc->createTextNode(
547 Glib::DateTime::create_now_local().format("%F").c_str()));
548 templateinfo_node->appendChild(element_node);
549
550 if (keywords.length() != 0) {
551
552 element_node = xml_doc->createElement("inkscape:keywords");
553 Inkscape::GC::release(element_node);
554
555 element_node->appendChild(xml_doc->createTextNode(keywords.c_str()));
556 templateinfo_node->appendChild(element_node);
557
558 }
559
560 root->appendChild(templateinfo_node);
561
562 // Escape filenames for windows users, but filenames are not URIs so
563 // Allow UTF-8 and don't escape spaces which are popular chars.
564 auto encodedName = Glib::uri_escape_string(name, " ", true);
565 encodedName.append(".svg");
566
567 auto path = Inkscape::IO::Resource::get_path_string(USER, TEMPLATES, encodedName.c_str());
568
569 auto operation_confirmed = sp_ui_overwrite_file(path);
570
571 auto file = Gio::File::create_for_path(path);
572
573 if (operation_confirmed) {
574 file_save(parentWindow, document, file,
575 Inkscape::Extension::db.get(".svg"), false, false,
577
578 if (isDefault) {
579 // save as "default.svg" by default (so it works independently of UI language), unless
580 // a localized template like "default.de.svg" is already present (which overrides "default.svg")
581 std::string default_svg_localized = std::string("default.") + _("en") + ".svg";
582 path = Inkscape::IO::Resource::get_path_string(USER, TEMPLATES, default_svg_localized.c_str());
583
584 if (!Inkscape::IO::file_test(path.c_str(), G_FILE_TEST_EXISTS)) {
585 path = Inkscape::IO::Resource::get_path_string(USER, TEMPLATES, "default.svg");
586 }
587
588 file = Gio::File::create_for_path(path);
589 file_save(parentWindow, document, file,
590 Inkscape::Extension::db.get(".svg"), false, false,
592 }
593 }
594
595 // remove this node from current document after saving it as template
596 root->removeChild(templateinfo_node);
597
598 return operation_confirmed;
599}
600
601/*######################
602## I M P O R T
603######################*/
604
611void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place, bool on_page)
612{
613 //TODO: merge with file_import()
614
615 SPDocument *target_document = desktop->getDocument();
617 auto layer = desktop->layerManager().currentLayer();
618 Inkscape::XML::Node *target_parent = layer->getRepr();
619
620 Inkscape::XML::rebase_hrefs(clipdoc, target_document->getDocumentBase(), false);
621
623
624 // Get page manager for on_page pasting, this must be done before selection changes
625 Inkscape::PageManager &pm = target_document->getPageManager();
626 SPPage *to_page = pm.getSelected();
627
628 auto *node_after = desktop->getSelection()->topRepr();
629 if (node_after && prefs->getBool("/options/paste/aboveselected", true) && node_after != target_parent) {
630 target_parent = node_after->parent();
631
632 // find parent group
633 for (auto p = target_document->getObjectByRepr(node_after->parent()); p; p = p->parent) {
634 if (auto parent_group = cast<SPGroup>(p)) {
635 layer = parent_group;
636 break;
637 }
638 }
639 } else {
640 node_after = target_parent->lastChild();
641 }
642
643 // copy definitions
644 desktop->doc()->importDefs(clipdoc);
645
646 Inkscape::XML::Node* clipboard = nullptr;
647 // copy objects
648 std::vector<Inkscape::XML::Node*> pasted_objects;
649 for (Inkscape::XML::Node *obj = root->firstChild() ; obj ; obj = obj->next()) {
650 // Don't copy metadata, defs, named views and internal clipboard contents to the document
651 if (!strcmp(obj->name(), "svg:defs")) {
652 continue;
653 }
654 if (!strcmp(obj->name(), "svg:metadata")) {
655 continue;
656 }
657 if (!strcmp(obj->name(), "sodipodi:namedview")) {
658 continue;
659 }
660 if (!strcmp(obj->name(), "inkscape:clipboard")) {
661 clipboard = obj;
662 continue;
663 }
664
665 Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc());
666 target_parent->addChild(obj_copy, node_after);
667 node_after = obj_copy;
668 Inkscape::GC::release(obj_copy);
669
670 // if we are pasting a clone to an already existing object, its
671 // transform is relative to the document, not to its original (see ui/clipboard.cpp)
672 auto spobject = target_document->getObjectByRepr(obj_copy);
673 auto use = cast<SPUse>(spobject);
674 if (use) {
675 SPItem *original = use->get_original();
676 if (original) {
677 Geom::Affine relative_use_transform = original->transform.inverse() * use->transform;
678 obj_copy->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(relative_use_transform));
679 }
680 }
681
682 if (is<SPItem>(spobject)) {
683 pasted_objects.push_back(obj_copy);
684 }
685 }
686
687 std::vector<Inkscape::XML::Node*> pasted_objects_not;
688 Geom::Affine doc2parent = layer->i2doc_affine().inverse();
689
690 Geom::OptRect from_page;
691 if (clipboard) {
692 if (clipboard->attribute("page-min")) {
693 from_page = Geom::OptRect(clipboard->getAttributePoint("page-min"), clipboard->getAttributePoint("page-max"));
694 }
695
696 for (Inkscape::XML::Node *obj = clipboard->firstChild(); obj; obj = obj->next()) {
697 if (target_document->getObjectById(obj->attribute("id")))
698 continue;
699 Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc());
700 layer->appendChildRepr(obj_copy);
701 Inkscape::GC::release(obj_copy);
702 pasted_objects_not.push_back(obj_copy);
703 }
704 }
705 target_document->ensureUpToDate();
707 selection->setReprList(pasted_objects_not);
708
709 selection->deleteItems(true);
710
711 // Change the selection to the freshly pasted objects
712 selection->setReprList(pasted_objects);
713 for (auto item : selection->items()) {
714 auto pasted_lpe_item = cast<SPLPEItem>(item);
715 if (pasted_lpe_item) {
716 sp_lpe_item_enable_path_effects(pasted_lpe_item, false);
717 }
718 }
719 // Apply inverse of parent transform
720 selection->applyAffine(desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false);
721
722 // Update (among other things) all curves in paths, for bounds() to work
723 target_document->ensureUpToDate();
724
725 // move selection either to original position (in_place) or to mouse pointer
726 Geom::OptRect sel_bbox = selection->visualBounds();
727 if (sel_bbox) {
728 // get offset of selection to original position of copied elements
729 Geom::Point pos_original;
730 Inkscape::XML::Node *clipnode = sp_repr_lookup_name(root, "inkscape:clipboard", 1);
731 if (clipnode) {
732 Geom::Point min, max;
733 min = clipnode->getAttributePoint("min", min);
734 max = clipnode->getAttributePoint("max", max);
735 pos_original = Geom::Point(min[Geom::X], max[Geom::Y]);
736 }
737 Geom::Point offset = pos_original - sel_bbox->corner(3);
738
739 if (!in_place) {
740 auto &m = desktop->getNamedView()->snap_manager;
741 m.setup(desktop);
743
744 // Get offset from mouse pointer rounded to the pixel to bbox center, snap to grid if enabled
745 Geom::Point mouse_offset = (desktop->point() - sel_bbox->midpoint()).round();
746 offset = m.multipleOfGridPitch(mouse_offset - offset, sel_bbox->midpoint() + offset) + offset;
747 m.unSetup();
748 } else if (on_page && from_page && to_page) {
749 // Moving to the same location on a different page requires us to remove the original page translation
750 offset *= Geom::Translate(from_page->min()).inverse();
751 // Then add the new page's transform on top.
752 offset *= Geom::Translate(to_page->getDesktopRect().min());
753 }
754
755 selection->moveRelative(offset);
756 for (auto po : pasted_objects) {
757 auto lpeitem = cast<SPLPEItem>(target_document->getObjectByRepr(po));
758 if (lpeitem) {
759 sp_lpe_item_enable_path_effects(lpeitem, true);
760 }
761 }
762 }
763 target_document->emitReconstructionFinish();
764}
765
770SPObject *
771file_import(SPDocument *in_doc, const std::string &path, Inkscape::Extension::Extension *key)
772{
773 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
774 bool cancelled = false;
775 auto prefs = Inkscape::Preferences::get();
776
777 // Store mouse pointer location before opening any dialogs, so we can drop the item where initially intended.
778 auto pointer_location = desktop->point();
779
780 // We need access to the module locally for our import logic
781 if (!key) {
783 }
784
785 //DEBUG_MESSAGE( fileImport, "file_import( in_doc:%p uri:[%s], key:%p", in_doc, uri, key );
786 std::unique_ptr<SPDocument> doc;
787 try {
788 doc = Inkscape::Extension::open(key, path.c_str(), true);
792 cancelled = true;
793 }
794
795 bool is_svg = key && !strcmp(key->get_id(), SP_MODULE_KEY_INPUT_SVG);
796
797 if (doc && is_svg && prefs->getString("/dialogs/import/import_mode_svg") == "new") {
798 // Opened instead of imported, open and return nothing
799 auto *app = InkscapeApplication::instance();
800 auto doc_ptr = app->document_add(std::move(doc));
801 app->desktopOpen(doc_ptr);
802 return nullptr;
803 } else if (doc) {
804 // Always preserve any imported text kerning / formatting
805 auto root_repr = in_doc->getReprRoot();
806 root_repr->setAttribute("xml:space", "preserve");
807
808 Inkscape::XML::rebase_hrefs(doc.get(), in_doc->getDocumentBase(), false);
809 Inkscape::XML::Document *xml_in_doc = in_doc->getReprDoc();
810 prevent_id_clashes(doc.get(), in_doc, true);
811 sp_file_fix_lpe(doc.get());
812
813 in_doc->importDefs(doc.get());
814
815 // The extension should set it's pages enabled or disabled when opening
816 // in order to indicate if pages are being imported or if objects are.
817 if (doc->getPageManager().hasPages()) {
818 file_import_pages(in_doc, doc.get());
819 DocumentUndo::done(in_doc, _("Import Pages"), INKSCAPE_ICON("document-import"));
820 // This return is only used by dbus in document-interface.cpp (now removed).
821 return nullptr;
822 }
823
824 SPCSSAttr *style = sp_css_attr_from_object(doc->getRoot());
825
826 // Count the number of top-level items in the imported document.
827 guint items_count = 0;
828 SPObject *o = nullptr;
829 for (auto& child: doc->getRoot()->children) {
830 if (is<SPItem>(&child)) {
831 items_count++;
832 o = &child;
833 }
834 }
835
836 //ungroup if necessary
837 bool did_ungroup = false;
838 while(items_count==1 && o && is<SPGroup>(o) && o->children.size()==1){
839 std::vector<SPItem *>v;
840 sp_item_group_ungroup(cast<SPGroup>(o), v);
841 o = v.empty() ? nullptr : v[0];
842 did_ungroup=true;
843 }
844
845 // Create a new group if necessary.
846 Inkscape::XML::Node *newgroup = nullptr;
847 const auto & al = style->attributeList();
848 if ((style && !al.empty()) || items_count > 1) {
849 newgroup = xml_in_doc->createElement("svg:g");
850 sp_repr_css_set(newgroup, style, "style");
851 }
852
853 // Determine the place to insert the new object.
854 // This will be the current layer, if possible.
855 // FIXME: If there's no desktop (command line run?) we need
856 // a document:: method to return the current layer.
857 // For now, we just use the root in this case.
858 SPObject *place_to_insert;
859 if (desktop) {
860 place_to_insert = desktop->layerManager().currentLayer();
861 } else {
862 place_to_insert = in_doc->getRoot();
863 }
864
865 // Construct a new object representing the imported image,
866 // and insert it into the current document.
867 SPObject *new_obj = nullptr;
868 for (auto& child: doc->getRoot()->children) {
869 if (is<SPItem>(&child)) {
870 Inkscape::XML::Node *newitem = did_ungroup ? o->getRepr()->duplicate(xml_in_doc) : child.getRepr()->duplicate(xml_in_doc);
871
872 // convert layers to groups, and make sure they are unlocked
873 // FIXME: add "preserve layers" mode where each layer from
874 // import is copied to the same-named layer in host
875 newitem->removeAttribute("inkscape:groupmode");
876 newitem->removeAttribute("sodipodi:insensitive");
877
878 if (newgroup) newgroup->appendChild(newitem);
879 else new_obj = place_to_insert->appendChildRepr(newitem);
880 }
881
882 // don't lose top-level defs or style elements
883 else if (child.getRepr()->type() == Inkscape::XML::NodeType::ELEMENT_NODE) {
884 const gchar *tag = child.getRepr()->name();
885 if (!strcmp(tag, "svg:style")) {
886 in_doc->getRoot()->appendChildRepr(child.getRepr()->duplicate(xml_in_doc));
887 }
888 }
889 }
890 in_doc->emitReconstructionFinish();
891 if (newgroup) new_obj = place_to_insert->appendChildRepr(newgroup);
892
893 // release some stuff
894 if (newgroup) Inkscape::GC::release(newgroup);
895 if (style) sp_repr_css_attr_unref(style);
896
897 // select and move the imported item
898 if (auto new_item = cast<SPItem>(new_obj)) {
900 selection->set(new_item);
901
902 // preserve parent and viewBox transformations
903 // c2p is identity matrix at this point unless ensureUpToDate is called
904 doc->ensureUpToDate();
905 Geom::Affine affine = doc->getRoot()->c2p * cast<SPItem>(place_to_insert)->i2doc_affine().inverse();
906 selection->applyAffine(desktop->dt2doc() * affine * desktop->doc2dt(), true, false, false);
907
908 // move to mouse pointer
910 if (auto sel_bbox = selection->visualBounds()) {
911 auto m = pointer_location.round() - sel_bbox->midpoint();
912 selection->moveRelative(m, false);
913 }
914 }
915
916 DocumentUndo::done(in_doc, _("Import"), INKSCAPE_ICON("document-import"));
917 return new_obj;
918 } else if (!cancelled) {
919 gchar *text = g_strdup_printf(_("Failed to load the requested file %s"), path.c_str());
920 sp_ui_error_dialog(text);
921 g_free(text);
922 }
923
924 return nullptr;
925}
926
933void file_import_pages(SPDocument *this_doc, SPDocument *that_doc)
934{
935 auto &this_pm = this_doc->getPageManager();
936 auto &that_pm = that_doc->getPageManager();
937 auto this_root = this_doc->getReprRoot();
938 auto that_root = that_doc->getReprRoot();
939
940 // Make sure objects have visualBounds created for import
941 that_doc->ensureUpToDate();
942 this_pm.enablePages();
943
944 Geom::Affine tr = Geom::Translate(this_pm.nextPageLocation() * this_doc->getDocumentScale());
945 for (auto &that_page : that_pm.getPages()) {
946 auto this_page = this_pm.newDocumentPage(that_page->getDocumentRect() * tr);
947 // Set the margin, bleed, etc
948 this_page->copyFrom(that_page);
949 }
950
951 // Unwind the document scales for the imported objects
952 tr = this_doc->getDocumentScale().inverse() * that_doc->getDocumentScale() * tr;
953 Inkscape::ObjectSet set(this_doc);
954 for (Inkscape::XML::Node *that_repr = that_root->firstChild(); that_repr; that_repr = that_repr->next()) {
955 // Don't copy metadata, defs, named views and internal clipboard contents to the document
956 if (!strcmp(that_repr->name(), "svg:defs") ||
957 !strcmp(that_repr->name(), "svg:metadata") ||
958 !strcmp(that_repr->name(), "sodipodi:namedview")) {
959 continue;
960 }
961
962 auto this_repr = that_repr->duplicate(this_doc->getReprDoc());
963 this_root->addChild(this_repr, this_root->lastChild());
964 Inkscape::GC::release(this_repr);
965 if (auto this_item = this_doc->getObjectByRepr(this_repr)) {
966 set.add(this_item);
967 }
968 }
969 set.applyAffine(tr, true, false, true);
970}
971
972/*######################
973## P R I N T
974######################*/
975
979void
980sp_file_print(Gtk::Window& parentWindow)
981{
982 SPDocument *doc = SP_ACTIVE_DOCUMENT;
983 if (doc) {
984 sp_print_document(parentWindow, doc);
985 }
986}
987
988/*
989 Local Variables:
990 mode:c++
991 c-file-style:"stroustrup"
992 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
993 indent-tabs-mode:nil
994 fill-column:99
995 End:
996*/
997// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
uint64_t desk
Definition canvas.cpp:171
3x3 matrix representing an affine transformation.
Definition affine.h:70
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Scale inverse() const
Definition transforms.h:172
Translation by a vector.
Definition transforms.h:115
Translate inverse() const
Get the inverse translation.
Definition transforms.h:133
static InkscapeApplication * instance()
Singleton instance.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
void rememberFileSave()
Definition event-log.h:91
std::list< Output * > OutputList
Definition db.h:58
OutputList & get_output_list(OutputList &ou_list)
Creates a list of all the Output extensions.
Definition db.cpp:256
Extension * get(const gchar *key) const
This function looks up a Inkscape::Extension::Extension by using its unique id. It then returns a ref...
Definition db.cpp:101
An error class for when a filename already exists, but the user doesn't want to overwrite it.
Definition extension.h:231
The object that is the basis for the Extension system.
Definition extension.h:133
static Extension * find_by_filename(char const *filename)
Get an input extension by filename matching.
Definition input.cpp:257
The existing file can not be opened for writing.
Definition output.h:37
Failed because we couldn't find an extension to match the filename.
Definition output.h:36
Generic failure for an undescribed reason.
Definition output.h:34
gchar const * get_extension() const
Get the filename extension for this extension.
Definition output.cpp:159
static Inkscape::FontLister * get_instance()
SPGroup * currentLayer() const
Returns current top layer.
MessageId flash(MessageType type, char const *message)
Temporarily pushes a message onto the stack.
MessageId flashF(MessageType type, char const *format,...) G_GNUC_PRINTF(3
temporarily pushes a message onto the stack using printf-like formatting
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:255
void setReprList(std::vector< XML::Node * > const &list)
Selects the objects with the same IDs as those in list.
void applyAffine(Geom::Affine const &affine, bool set_i2d=true, bool compensate=true, bool adjust_transf_center=true)
Apply matrix to the selection.
void moveRelative(const Geom::Point &move, bool compensate=true)
void deleteItems(bool skip_undo=false)
XML::Node * topRepr() const
The top-most item, or NULL if the selection is empty.
Geom::OptRect visualBounds() const
SPPage * getSelected() const
Preference storage class.
Definition preferences.h:66
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
static RecentlyUsedFonts * get()
The set of selected SPObjects for a given document and layer model.
Definition selection.h:80
void set(XML::Node *repr)
Set the selection to an XML node's SPObject.
Definition selection.h:118
void discard_delayed_snap_event()
If a delayed snap event has been scheduled, this function will cancel it.
std::string const & str() const
Definition version.cpp:66
Interface for refcounted XML nodes.
Definition node.h:80
virtual Node * parent()=0
Get the parent of this node.
virtual Node * next()=0
Get the next sibling of this node.
virtual void addChild(Node *child, Node *after)=0
Insert another node as a child of this node.
virtual void appendChild(Node *child)=0
Append a node as the last child of this node.
virtual char const * name() const =0
Get the name of the element node.
virtual const AttributeVector & attributeList() const =0
Get a list of the node's attributes.
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:167
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual Node * duplicate(Document *doc) const =0
Create a duplicate of this node.
virtual Node * firstChild()=0
Get the first child of this node.
Geom::Point getAttributePoint(Util::const_char_ptr key, Geom::Point default_value={}) const
Definition node.cpp:146
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
void removeAttribute(Inkscape::Util::const_char_ptr key)
Remove an attribute of this node.
Definition node.h:280
virtual Node * lastChild()=0
Get the last child of this node.
To do: update description of desktop.
Definition desktop.h:149
SPDocument * getDocument() const
Definition desktop.h:189
Inkscape::MessageStack * messageStack() const
Definition desktop.h:160
Geom::Affine const & dt2doc() const
Definition desktop.cpp:1343
Geom::Point point() const
Returns the mouse point in desktop coordinates; if mouse is outside the canvas, returns the center of...
Definition desktop.cpp:378
SPNamedView * getNamedView() const
Definition desktop.h:191
Inkscape::Selection * getSelection() const
Definition desktop.h:188
Inkscape::UI::Tools::ToolBase * getTool() const
Definition desktop.h:187
SPDocument * doc() const
Definition desktop.h:159
Inkscape::LayerManager & layerManager()
Definition desktop.h:287
Geom::Affine const & doc2dt() const
Definition desktop.cpp:1337
bool warnDialog(Glib::ustring const &text)
Definition desktop.cpp:997
Typed SVG document implementation.
Definition document.h:103
void importDefs(SPDocument *source)
Paste SVG defs from the document retrieved from the clipboard or imported document into the active do...
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:202
char const * getDocumentBase() const
Definition document.h:235
char const * getDocumentFilename() const
Definition document.h:231
SPObject * getObjectById(std::string const &id) const
bool isModifiedSinceSave() const
Definition document.h:140
Inkscape::EventLog * get_event_log()
Definition document.h:162
Inkscape::XML::Node * getReprRoot()
Definition document.h:208
unsigned int vacuumDocument()
Remove unused definitions etc.
Inkscape::PageManager & getPageManager()
Definition document.h:164
void emitReconstructionFinish()
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:213
int ensureUpToDate(unsigned int object_modified_tag=0)
Repeatedly works on getting the document updated, since sometimes it takes more than one pass to get ...
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
Geom::Scale getDocumentScale(bool computed=true) const
Returns document scale as defined by width/height (in pixels) and viewBox (real world to user-units).
Definition document.cpp:773
Base class for visual SVG elements.
Definition sp-item.h:109
SnapManager snap_manager
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
char * title() const
Returns the title of this object, or NULL if there is none.
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
ChildrenList children
Definition sp-object.h:907
Geom::Rect getDesktopRect() const
Get the rectangle of the page, in desktop units.
Definition sp-page.cpp:132
struct SPRoot::@40 inkscape
void setup(SPDesktop const *desktop, bool snapindicator=true, SPObject const *item_to_ignore=nullptr, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Convenience shortcut when there is only one item to ignore.
Definition snap.cpp:663
RootCluster root
Glib::ustring msg
Editable view implementation.
TODO: insert short description here.
void sp_file_fix_lpe(SPDocument *doc)
bool sp_file_save_template(Gtk::Window &parentWindow, Glib::ustring name, Glib::ustring author, Glib::ustring description, Glib::ustring keywords, bool isDefault)
Save a copy of a document as template.
Definition file.cpp:501
void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place, bool on_page)
Paste the contents of a document into the active desktop.
Definition file.cpp:611
void sp_file_vacuum(SPDocument *doc)
Remove unreferenced defs from the defs section of the document.
Definition file.cpp:165
SPDesktop * sp_file_new_default()
Definition file.cpp:107
void sp_file_revert_dialog()
Handle prompting user for "do you want to revert"? Revert on "OK".
Definition file.cpp:118
void file_import_pages(SPDocument *this_doc, SPDocument *that_doc)
Import the given document as a set of multiple pages and append to this one.
Definition file.cpp:933
std::string sp_file_default_template_uri()
Definition file.cpp:102
bool sp_file_save_a_copy(Gtk::Window &parentWindow, gpointer, gpointer)
Save a copy of a document, always displaying a sort of SaveAs dialog.
Definition file.cpp:487
bool sp_file_save(Gtk::Window &parentWindow, gpointer, gpointer)
Save a document.
Definition file.cpp:457
SPDesktop * sp_file_new(const std::string &templ)
Create a blank document and add it to the desktop Input: empty string or template file name.
Definition file.cpp:90
SPObject * file_import(SPDocument *in_doc, const std::string &path, Inkscape::Extension::Extension *key)
Import a resource.
Definition file.cpp:771
static bool file_save(Gtk::Window &parentWindow, SPDocument *doc, const Glib::RefPtr< Gio::File > file, Inkscape::Extension::Extension *key, bool checkoverwrite, bool official, Inkscape::Extension::FileSaveMethod save_method)
This 'save' function called by the others below.
Definition file.cpp:197
bool sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, Inkscape::Extension::FileSaveMethod save_method)
Display a SaveAs dialog.
Definition file.cpp:300
void sp_file_print(Gtk::Window &parentWindow)
Print the current document, if any.
Definition file.cpp:980
bool sp_file_save_document(Gtk::Window &parentWindow, SPDocument *doc)
Save a document, displaying a SaveAs dialog if necessary.
Definition file.cpp:409
bool sp_file_save_as(Gtk::Window &parentWindow, gpointer, gpointer)
Save a document, always displaying the SaveAs dialog.
Definition file.cpp:473
Font selection widgets.
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Macro for icon names used in Inkscape.
void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc, bool from_clipboard)
This function resolves ID clashes between the document being imported and the current open document: ...
Definition id-clash.cpp:464
TODO: insert short description here.
SPItem * item
std::string original
Mini static library that contains the version of Inkscape.
Inkscape - An SVG editor.
void sp_ui_error_dialog(char const *message)
Definition interface.cpp:56
bool sp_ui_overwrite_file(std::string const &filename)
If necessary, ask the user if a file may be overwritten.
Definition interface.cpp:74
double offset
Raw stack of active status messages.
DB db
This is the actual database object.
Definition db.cpp:32
Glib::ustring get_file_save_extension(Inkscape::Extension::FileSaveMethod method)
Determine the desired default file extension depending on the given file save method.
Definition system.cpp:479
std::unique_ptr< SPDocument > open(Extension *key, char const *filename, bool is_importing)
This is a generic function to use the open function of a module (including Autodetect)
Definition system.cpp:66
void save(Extension *key, SPDocument *doc, gchar const *filename, bool check_overwrite, bool official, Inkscape::Extension::FileSaveMethod save_method)
This is a generic function to use the save function of a module (including Autodetect)
Definition system.cpp:162
void store_save_path_in_prefs(Glib::ustring path, FileSaveMethod method)
Write the given path back to prefs so that it can be used later on.
Definition system.cpp:576
FileSaveMethod
Used to distinguish between the various invocations of the save dialogs (and thus to determine the fi...
Definition system.h:34
@ FILE_SAVE_METHOD_SAVE_COPY
Definition system.h:36
@ FILE_SAVE_METHOD_INKSCAPE_SVG
Definition system.h:40
Glib::ustring get_file_save_path(SPDocument *doc, FileSaveMethod method)
Determine the desired default save path depending on the given FileSaveMethod.
Definition system.cpp:506
static R & release(R &r)
Decrements the reference count of a anchored object.
std::string get_path_string(Domain domain, Type type, char const *filename, char const *extra)
Definition resource.cpp:148
std::string get_filename(Type type, char const *filename, bool localized, bool silent)
Definition resource.cpp:170
Glib::ustring get_file_extension(Glib::ustring const &path)
Definition sys.cpp:214
bool file_test(char const *utf8name, GFileTest test)
Definition sys.cpp:116
Glib::RefPtr< Gio::ListStore< Gtk::FileFilter > > create_export_filters(bool for_save)
Create a Gtk::FileFilter for all export file types.
void rebase_hrefs(Inkscape::XML::Node *rootxml, gchar const *const old_base, gchar const *const new_base, bool const spns)
Change relative hrefs in current root XML node (faster than full document generation)
@ ELEMENT_NODE
Regular element node, e.g. <group />.
char const * version_string
full version string
@ ERROR_MESSAGE
Definition message.h:29
@ NORMAL_MESSAGE
Definition message.h:26
@ IMMEDIATE_MESSAGE
Definition message.h:27
@ WARNING_MESSAGE
Definition message.h:28
static cairo_user_data_key_t key
TODO: insert short description here.
void sp_print_document(Gtk::Window &parentWindow, SPDocument *doc)
Definition print.cpp:80
Ocnode * child[8]
Definition quantize.cpp:33
unsigned int rdf_set_work_entity(SPDocument *doc, struct rdf_work_entity_t *entity, const gchar *text)
Definition rdf.cpp:914
struct rdf_work_entity_t * rdf_find_entity(gchar const *name)
Retrieves a known RDF/Work entity by name.
Definition rdf.cpp:364
headers for RDF types
TODO: insert short description here.
void sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
Sets an attribute (e.g.
Definition repr-css.cpp:265
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
Definition repr-css.cpp:76
Inkscape::XML::Node const * sp_repr_lookup_name(Inkscape::XML::Node const *repr, gchar const *name, gint maxdepth)
Inkscape::IO::Resource - simple resource API.
SPCSSAttr - interface for CSS Attributes.
void sp_item_group_ungroup(SPGroup *group, std::vector< SPItem * > &children)
void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
void sp_namedview_document_from_window(SPDesktop *desktop)
SPPage – a page object.
SPRoot: SVG <svg> implementation.
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
SPCSSAttr * sp_css_attr_from_object(SPObject *object, guint const flags)
Definition style.cpp:1427
SPStyle - a style object for SPItem objects.
std::string sp_svg_transform_write(Geom::Affine const &transform)
SPDesktop * desktop
Glib::ustring name
Definition toolbars.cpp:55