Context for the "About" label
[inkscape.git] / src / document.h
blobec65ea5f0636df407afe88cfa260299334cd4253
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #ifndef SEEN_SP_DOCUMENT_H
3 #define SEEN_SP_DOCUMENT_H
5 /** \file
6 * SPDocument: Typed SVG document implementation
7 */
8 /* Authors:
9 * Lauris Kaplinski <lauris@kaplinski.com>
10 * MenTaLguY <mental@rydia.net>
11 * Jon A. Cruz <jon@joncruz.org>
12 * Abhishek Sharma
14 * Copyright (C) 2004-2005 MenTaLguY
15 * Copyright (C) 1999-2002 Lauris Kaplinski
16 * Copyright (C) 2000-2001 Ximian, Inc.
18 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
21 #include <cstddef> // for size_t
22 #include <deque> // for deque
23 #include <map> // for map
24 #include <memory> // for unique_ptr, default_de...
25 #include <queue> // for queue
26 #include <span>
27 #include <string> // for string
28 #include <vector> // for vector
30 #include <boost/ptr_container/ptr_list.hpp> // for ptr_list
32 #include <giomm/simpleactiongroup.h> // for SimpleActionGroup
33 #include <glib.h> // for GQuark, gboolean, gchar
34 #include <glibmm/refptr.h> // for RefPtr
35 #include <glibmm/ustring.h> // for ustring
36 #include <sigc++/connection.h> // for connection
37 #include <sigc++/signal.h> // for signal
39 #include <2geom/affine.h> // for Affine
40 #include <2geom/rect.h> // for Rect, OptRect
41 #include <2geom/transforms.h> // for Scale
43 #include "3rdparty/libcroco/src/cr-cascade.h" // for CRCascade
45 #include "composite-undo-stack-observer.h"
46 // XXX only for testing!
47 #include "console-output-undo-observer.h"
49 // This variable is introduced with 0.92.1
50 // with the introduction of automatic fix
51 // for files detected to have been created
52 // with previous versions to have a similar
53 // look in 0.92+.
54 extern bool sp_no_convert_text_baseline_spacing;
57 // This variable is introduced with 0.92.1
58 // with the introduction of automatic fix
59 // for files detected to have been created
60 // with previous versions to have a similar
61 // look in 0.92+.
62 extern bool sp_do_not_fix_pre_92;
65 namespace Avoid {
66 class Router;
69 class Persp3D;
70 class Persp3DImpl;
71 class SPDefs;
72 class SPGroup;
73 class SPItem;
74 class SPItemCtx;
75 class SPNamedView;
76 class SPObject;
77 class SPRoot;
79 namespace Inkscape {
80 class DocumentUndo;
81 class Event;
82 class EventLog;
83 class PageManager;
84 namespace Colors {
85 class DocumentCMS;
87 class Selection;
88 class UndoStackObserver;
89 namespace XML {
90 struct Document;
91 class Event;
92 class Node;
93 } // namespace XML
94 namespace Util {
95 class Unit;
96 class Quantity;
97 } // namespace Util
98 } // namespace Inkscape
100 /// Typed SVG document implementation.
101 class SPDocument
103 public:
104 /// For sanity check in SPObject::requestDisplayUpdate
105 unsigned update_in_progress = 0;
107 SPDocument();
108 ~SPDocument();
109 SPDocument(SPDocument const &) = delete;
110 SPDocument &operator=(SPDocument const &) = delete;
112 static int get_new_doc_number();
114 // Document creation ------------------
115 static std::unique_ptr<SPDocument> createDoc(Inkscape::XML::Document *rdoc, char const *filename,
116 char const *base, char const *name, bool keepalive, SPDocument *parent = nullptr);
117 static std::unique_ptr<SPDocument> createNewDoc(char const *filename, bool keepalive,
118 bool make_new = false, SPDocument *parent = nullptr);
119 static std::unique_ptr<SPDocument> createNewDocFromMem(std::span<char const> buffer, bool keepalive,
120 std::string const &filename = "");
121 SPDocument *createChildDoc(std::string const &filename);
123 void setPages(bool enabled);
124 void prunePages(const std::string &page_nums, bool invert = false);
126 // Make a deep copy.
127 std::unique_ptr<SPDocument> copy() const;
128 // Substitute doc root
129 void rebase(Inkscape::XML::Document * new_xmldoc, bool keep_namedview = true);
130 // Substitute doc root with a file
131 void rebase(const gchar * file, bool keep_namedview = true);
132 // Substitute doc root with file in disk
133 void rebase(bool keep_namedview = true);
134 // Document status --------------------
135 void setVirgin(bool Virgin) { virgin = Virgin; }
136 bool getVirgin() { return virgin; }
137 const SPDocument *getOriginalDocument() const { return _original_document; }
139 bool isModifiedSinceSave() const { return modified_since_save; }
140 bool isModifiedSinceAutoSave() const { return modified_since_autosave; }
141 void setModifiedSinceSave(bool const modified = true);
142 void setModifiedSinceAutoSaveFalse() { modified_since_autosave = false; };
144 bool idle_handler();
145 bool rerouting_handler();
147 void requestModified();
148 bool _updateDocument(int flags, unsigned int object_modified_tag = 0); // Used by stand-alone sp_document_idle_handler
149 int ensureUpToDate(unsigned int object_modified_tag = 0);
151 bool addResource(char const *key, SPObject *object);
152 bool removeResource(char const *key, SPObject *object);
153 std::vector<SPObject *> const getResourceList(char const *key);
154 void process_pending_resource_changes();
156 void do_change_filename(char const *const filename, bool const rebase);
157 void changeFilenameAndHrefs(char const *filename);
158 void setXMLDialogSelectedObject(SPObject *activexmltree) { _activexmltree = activexmltree; }
159 SPObject *getXMLDialogSelectedObject() { return _activexmltree; }
161 Inkscape::EventLog *get_event_log() { return _event_log.get(); }
163 Inkscape::PageManager& getPageManager() { return *_page_manager; }
164 const Inkscape::PageManager& getPageManager() const { return *_page_manager; }
166 Inkscape::Colors::DocumentCMS &getDocumentCMS() { return *_cms_manager; }
167 const Inkscape::Colors::DocumentCMS &getDocumentCMS() const { return *_cms_manager; }
169 private:
170 void _importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, Inkscape::XML::Node *target_defs);
171 SPObject *_activexmltree;
173 std::unique_ptr<Inkscape::PageManager> _page_manager;
174 std::unique_ptr<Inkscape::Colors::DocumentCMS> _cms_manager;
176 std::queue<GQuark> pending_resource_changes;
178 // Find items by geometry --------------------
179 std::deque<SPItem*> const &get_flat_item_list(unsigned int dkey, bool into_groups, bool active_only) const;
181 SPDocument *_searchForChild(std::string const &filename, SPDocument const *avoid = nullptr);
182 /** Detect Y-axis orientation change.
183 * \return true if change has been detected */
184 bool has_yaxis_orientation_changed();
185 /** Update desktop transform after Y-axis orientation change.
186 * \return shift to apply to display to keep content from scrolling */
187 double update_desktop_affine();
189 public:
190 void clearNodeCache() { _node_cache.clear(); }
191 void importDefs(SPDocument *source);
193 unsigned int vacuumDocument();
195 /******** Getters and Setters **********/
197 // Document structure -----------------
198 Avoid::Router* getRouter() const { return _router.get(); }
200 /** Returns our SPRoot */
201 SPRoot *getRoot() { return root; }
202 SPRoot const *getRoot() const { return root; }
204 /** Return the main defs object for the document. */
205 SPDefs *getDefs();
207 Inkscape::XML::Node *getReprRoot() { return rroot; }
208 Inkscape::XML::Node *getReprNamedView();
209 SPNamedView *getNamedView();
211 /** Our Inkscape::XML::Document. */
212 Inkscape::XML::Document *getReprDoc() { return rdoc; }
213 Inkscape::XML::Document const *getReprDoc() const { return rdoc; }
216 std::vector<Glib::ustring> getLanguages() const;
218 SPDocument *getParent() { return _parent_document; }
219 SPDocument const *getParent() const { return _parent_document; }
221 Inkscape::Selection *getSelection() { return _selection.get(); }
223 // Styling
224 CRCascade *getStyleCascade() { return style_cascade; }
226 // File information --------------------
228 /** A filename, or NULL */
229 void setDocumentFilename(char const *filename);
230 char const *getDocumentFilename() const { return document_filename; }
232 /** To be used for resolving relative hrefs. */
233 void setDocumentBase( char const* document_base );
234 char const *getDocumentBase() const { return document_base; };
236 /** basename or other human-readable label for the document. */
237 char const* getDocumentName() const { return document_name; }
240 // Document geometry ------------------------
241 Inkscape::Util::Unit const* getDisplayUnit();
243 void setDocumentScale( const double scaleX, const double scaleY );
244 void setDocumentScale( const double scale );
245 Geom::Scale getDocumentScale(bool computed = true) const;
246 void scaleContentBy(Geom::Scale const &delta);
248 void setWidthAndHeight(const Inkscape::Util::Quantity &width, const Inkscape::Util::Quantity &height, bool changeSize=true);
249 Geom::Point getDimensions() const;
251 void setWidth(const Inkscape::Util::Quantity &width, bool changeSize=true);
252 void setHeight(const Inkscape::Util::Quantity &height, bool changeSize=true);
253 Inkscape::Util::Quantity getWidth() const;
254 Inkscape::Util::Quantity getHeight() const;
256 void setViewBox();
257 void setViewBox(const Geom::Rect &viewBox);
258 Geom::Rect getViewBox() const;
260 Geom::OptRect preferredBounds() const;
261 Geom::OptRect pageBounds();
262 void fitToRect(Geom::Rect const &rect, bool with_margins = false);
263 void setupViewport(SPItemCtx *ctx);
265 // Desktop geometry ------------------------
266 /// Document to desktop coordinate transformation.
267 const Geom::Affine &doc2dt() const;
268 /// Desktop to document coordinate transformation.
269 const Geom::Affine &dt2doc() const
271 // Note: doc2dt().inverse() happens to be identical to doc2dt()
272 return doc2dt();
274 /// True if the desktop Y-axis points down, false if it points up.
275 bool is_yaxisdown() const { return yaxisdir() > 0; }
276 /// "1" if the desktop Y-axis points down, "-1" if it points up.
277 double yaxisdir() const { return _doc2dt[3]; }
278 // return true if coordinate system origin needs to move to current page
279 bool get_origin_follows_page();
280 void set_origin_follows_page(bool on);
281 // signal emitted when Y-axis orientation gets flipped
282 sigc::signal<void (double)> get_y_axis_flipped() { return _y_axis_flipped; }
284 // Find items -----------------------------
285 void bindObjectToId(char const *id, SPObject *object);
286 SPObject *getObjectById(std::string const &id) const;
287 SPObject *getObjectById(char const *id) const;
288 SPObject *getObjectByHref(std::string const &href) const;
289 SPObject *getObjectByHref(char const *href) const;
291 void bindObjectToRepr(Inkscape::XML::Node *repr, SPObject *object);
292 SPObject *getObjectByRepr(Inkscape::XML::Node *repr) const;
294 std::vector<SPObject *> getObjectsByClass(Glib::ustring const &klass) const;
295 std::vector<SPObject *> getObjectsByElement(Glib::ustring const &element, bool custom = false) const;
296 std::vector<SPObject *> getObjectsBySelector(Glib::ustring const &selector) const;
299 * @brief Generate a document-wide unique id.
301 * Generates an id string not in use by any object in the document.
302 * The generated string is based on the given prefix by appending a number.
304 std::string generate_unique_id(char const *prefix);
307 * @brief Set the reference document object.
308 * Use this function to extend functionality of getObjectById() - it will search in reference document.
309 * This is useful when rendering objects that have been copied from this document into a sandbox document.
310 * Setting reference will allow sandbox document to find gradients, or linked objects that may have been
311 * referenced by copied object.
312 * @param document
314 void set_reference_document(SPDocument* document);
315 SPDocument* get_reference_document();
318 * @brief Object used to temporarily set and then automatically clear reference document.
320 struct install_reference_document {
321 install_reference_document(SPDocument* inject_into, SPDocument* reference);
322 ~install_reference_document();
323 private:
324 SPDocument* _parent;
327 std::vector<SPItem*> getItemsInBox (unsigned int dkey, Geom::Rect const &box, bool take_hidden = false, bool take_insensitive = false, bool take_groups = true, bool enter_groups = false, bool enter_layers = true) const;
328 std::vector<SPItem*> getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool take_hidden = false, bool take_insensitive = false, bool take_groups = true, bool enter_groups = false, bool enter_layers = true) const;
329 SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = nullptr) const;
330 std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers = true, bool topmost_only = true, size_t limit = 0, bool active_only = true) const;
331 SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const;
334 * Returns the bottommost item from the list which is at the point, or NULL if none.
336 static SPItem *getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, const std::vector<SPItem*> &list, Geom::Point const &p, bool take_insensitive = false);
339 // Box tool -------------------------------
340 void setCurrentPersp3D(Persp3D * const persp);
342 * getCurrentPersp3D returns current_persp3d (if non-NULL) or the first
343 * perspective in the defs. If no perspective exists, returns NULL.
345 Persp3D * getCurrentPersp3D();
346 void update_lpobjs();
347 void setCurrentPersp3DImpl(Persp3DImpl * const persp_impl) { current_persp3d_impl = persp_impl; }
348 Persp3DImpl * getCurrentPersp3DImpl() { return current_persp3d_impl; }
350 void getPerspectivesInDefs(std::vector<Persp3D*> &list) const;
351 unsigned int numPerspectivesInDefs() const {
352 std::vector<Persp3D*> list;
353 getPerspectivesInDefs(list);
354 return list.size();
358 // Document undo/redo ----------------------
359 unsigned long serial() const { return _serial; } // Returns document's unique number.
360 bool isSeeking() const {return seeking;} // In a transition between two "good" states of document?
361 bool isPartial() const {return partial != nullptr;} // In partianl undo/redo transaction
362 void reset_key(void *dummy) { actionkey.clear(); }
363 bool isSensitive() const { return sensitive; }
365 // Garbage collecting ----------------------
366 void queueForOrphanCollection(SPObject *object);
367 void collectOrphans();
370 // Actions ---------------------------------
371 Glib::RefPtr<Gio::SimpleActionGroup> getActionGroup() { return action_group; }
373 /************* Data ***************/
374 private:
376 // Document ------------------------------
377 std::unique_ptr<Avoid::Router> _router; // Instance of the connector router
378 std::unique_ptr<Inkscape::Selection> _selection;
380 // Document status -----------------------
382 bool keepalive; ///< false if temporary document (e.g. to generate a PNG for display in a dialog).
383 bool virgin ; ///< Has the document never been touched?
384 bool modified_since_save = false;
385 bool modified_since_autosave = false;
386 sigc::connection modified_connection;
387 sigc::connection rerouting_connection;
389 // Document structure --------------------
390 Inkscape::XML::Document *rdoc; ///< Our Inkscape::XML::Document
391 Inkscape::XML::Node *rroot; ///< Root element of Inkscape::XML::Document
393 SPRoot *root; ///< Our SPRoot
395 // A list of svg documents being used or shown within this document
396 std::vector<std::unique_ptr<SPDocument>> _child_documents;
397 // Conversely this is a parent document because this is a child.
398 SPDocument *_parent_document = nullptr;
399 // When copying documents, this can refer to its original
400 SPDocument const *_original_document = nullptr;
401 // Reference document to fall back to when getObjectById cannot find element in '*this' document
402 SPDocument *_ref_document = nullptr;
404 // Styling
405 CRCascade *style_cascade;
407 // Desktop geometry
408 mutable Geom::Affine _doc2dt;
410 // File information ----------------------
411 char *document_filename; ///< A filename, or NULL
412 char *document_base; ///< To be used for resolving relative hrefs.
413 char *document_name; ///< basename or other human-readable label for the document.
415 // Find items ----------------------------
416 std::map<std::string, SPObject *> iddef;
417 std::map<Inkscape::XML::Node *, SPObject *> reprdef;
419 // Find items by geometry --------------------
420 mutable std::map<unsigned long, std::deque<SPItem*>> _node_cache; // Used to speed up search.
422 // Box tool ----------------------------
423 Persp3D *current_persp3d; /**< Currently 'active' perspective (to which, e.g., newly created boxes are attached) */
424 Persp3DImpl *current_persp3d_impl;
426 // Document undo/redo ----------------------
427 friend Inkscape::DocumentUndo;
428 std::unique_ptr<Inkscape::EventLog> _event_log;
430 /* Undo/Redo state */
431 bool sensitive; /* If we save actions to undo stack */
432 Inkscape::XML::Event * partial; /* partial undo log when interrupted */
433 std::deque<Inkscape::Event *> undo; /* Undo stack of reprs */
434 std::deque<Inkscape::Event *> redo; /* Redo stack of reprs */
435 /* Undo listener */
436 Inkscape::CompositeUndoStackObserver undoStackObservers;
438 // XXX only for testing!
439 Inkscape::ConsoleOutputUndoObserver console_output_undo_observer;
441 bool seeking; // Related to undo/redo/unique id
442 unsigned long _serial; // Unique document number (used by undo/redo).
443 Glib::ustring actionkey; // Last action key, used to combine actions in undo.
444 unsigned long object_id_counter; // Steadily-incrementing counter used to assign unique ids to objects.
446 // Garbage collecting ----------------------
448 std::vector<SPObject *> _collection_queue; ///< Orphans
450 // Actions ---------------------------------
451 Glib::RefPtr<Gio::SimpleActionGroup> action_group;
453 /*********** Signals **************/
455 typedef sigc::signal<void (SPObject *)> IDChangedSignal;
456 typedef sigc::signal<void ()> ResourcesChangedSignal;
457 typedef sigc::signal<void (unsigned)> ModifiedSignal;
458 typedef sigc::signal<void (char const *)> FilenameSetSignal;
459 typedef sigc::signal<void (double, double)> ResizedSignal;
460 typedef sigc::signal<void ()> ReconstructionStart;
461 typedef sigc::signal<void ()> ReconstructionFinish;
462 typedef sigc::signal<void ()> CommitSignal;
463 typedef sigc::signal<void ()> BeforeCommitSignal; // allow to add actions berfore commit to include in undo
465 typedef std::map<GQuark, SPDocument::IDChangedSignal> IDChangedSignalMap;
466 typedef std::map<GQuark, SPDocument::ResourcesChangedSignal> ResourcesChangedSignalMap;
468 /** Dictionary of signals for id changes */
469 IDChangedSignalMap id_changed_signals;
471 SPDocument::ModifiedSignal modified_signal;
472 SPDocument::FilenameSetSignal filename_set_signal;
473 SPDocument::ReconstructionStart _reconstruction_start_signal;
474 SPDocument::ReconstructionFinish _reconstruction_finish_signal;
475 SPDocument::CommitSignal commit_signal; // Used by friend Inkscape::DocumentUndo
476 SPDocument::BeforeCommitSignal before_commit_signal; // Used by friend Inkscape::DocumentUndo
478 sigc::connection _desktop_activated_connection;
480 sigc::signal<void ()> destroySignal;
481 sigc::signal<void ()> _saved_or_modified_signal;
482 sigc::signal<void (double)> _y_axis_flipped;
484 public:
486 * @brief Add the observer to the document's undo listener
487 * The caller is in charge of freeing any memory allocated to the observer
488 * @param observer
490 void addUndoObserver(Inkscape::UndoStackObserver& observer);
491 void removeUndoObserver(Inkscape::UndoStackObserver& observer);
493 sigc::connection connectDestroy(sigc::signal<void ()>::slot_type slot);
494 sigc::connection connectModified(ModifiedSignal::slot_type slot);
495 sigc::connection connectFilenameSet(FilenameSetSignal::slot_type slot);
496 sigc::connection connectCommit(CommitSignal::slot_type slot);
497 sigc::connection connectBeforeCommit(BeforeCommitSignal::slot_type slot);
498 sigc::connection connectIdChanged(const char *id, IDChangedSignal::slot_type slot);
499 sigc::connection connectResourcesChanged(char const *key, SPDocument::ResourcesChangedSignal::slot_type slot);
500 sigc::connection connectReconstructionStart(ReconstructionStart::slot_type slot);
501 sigc::connection connectReconstructionFinish(ReconstructionFinish::slot_type slot);
502 sigc::connection connectSavedOrModified(sigc::slot<void ()> &&slot);
504 /* Resources */
505 std::map<std::string, std::vector<SPObject *> > resources;
506 ResourcesChangedSignalMap resources_changed_signals; // Used by Extension::Internal::Filter
508 void _emitModified(unsigned int object_modified_tag = 0); // Used by SPItem
509 void emitReconstructionStart();
510 void emitReconstructionFinish();
514 * Ideas: How to overcome style invalidation nightmare
516 * 1. There is reference request dictionary, that contains
517 * objects (styles) needing certain id. Object::build checks
518 * final id against it, and invokes necessary methods
520 * 2. Removing referenced object is simply prohibited -
521 * needs analyse, how we can deal with situations, where
522 * we simply want to ungroup etc. - probably we need
523 * Repr::reparent method :( [Or was it ;)]
527 #endif // SEEN_SP_DOCUMENT_H
530 Local Variables:
531 mode:c++
532 c-file-style:"stroustrup"
533 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
534 indent-tabs-mode:nil
535 fill-column:99
536 End:
538 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :