53
55
#include "libavoid/router.h"
54
56
#include "libnr/nr-rect.h"
55
57
#include "sp-item-group.h"
58
#include "profile-manager.h"
57
61
#include "display/nr-arena-item.h"
59
63
#include "dialogs/rdf.h"
65
#include "transf_mat_3x4.h"
61
67
#define A4_WIDTH_STR "210mm"
62
68
#define A4_HEIGHT_STR "297mm"
92
100
// Initialise instance of connector router.
93
101
router = new Avoid::Router();
102
// Don't use the Consolidate moves optimisation.
103
router->ConsolidateMoves = false;
95
107
p = new SPDocumentPrivate();
109
p->serial = next_serial++;
97
111
p->iddef = g_hash_table_new(g_direct_hash, g_direct_equal);
98
112
p->reprdef = g_hash_table_new(g_direct_hash, g_direct_equal);
104
118
p->history_size = 0;
125
// Once things are set, hook in the manager
126
profileManager = new Inkscape::ProfileManager(this);
128
// XXX only for testing!
129
priv->undoStackObservers.add(p->console_output_undo_observer);
111
132
SPDocument::~SPDocument() {
112
133
collectOrphans();
135
// kill/unhook this first
136
if ( profileManager ) {
137
delete profileManager;
115
inkscape_remove_document(this);
117
142
if (priv->partial) {
118
143
sp_repr_free_log(priv->partial);
119
144
priv->partial = NULL;
178
203
//delete this->_whiteboard_session_manager;
207
void SPDocument::add_persp3d (Persp3D * const persp)
209
SPDefs *defs = SP_ROOT(this->root)->defs;
210
for (SPObject *i = sp_object_first_child(SP_OBJECT(defs)); i != NULL; i = SP_OBJECT_NEXT(i) ) {
211
if (SP_IS_PERSP3D(i)) {
212
g_print ("Encountered a Persp3D in defs\n");
216
g_print ("Adding Persp3D to defs\n");
217
persp3d_create_xml_element (this);
220
void SPDocument::remove_persp3d (Persp3D * const persp)
222
// TODO: Delete the repr, maybe perform a check if any boxes are still linked to the perspective.
224
g_print ("Please implement deletion of perspectives here.\n");
227
unsigned long SPDocument::serial() const {
181
231
void SPDocument::queueForOrphanCollection(SPObject *object) {
272
319
// see if there's a template with id="base" in the preferences
274
321
// if there's none, create an empty element
275
rnew = sp_repr_new("sodipodi:namedview");
322
rnew = rdoc->createElement("sodipodi:namedview");
276
323
rnew->setAttribute("id", "base");
278
325
// otherwise, take from preferences
279
rnew = r->duplicate();
326
rnew = r->duplicate(rroot->document());
281
328
// insert into the document
282
329
rroot->addChild(rnew, NULL);
303
sp_document_set_undo_sensitive(document, TRUE);
350
// Remark: Here, we used to create a "currentpersp3d" element in the document defs.
351
// But this is probably a bad idea since we need to adapt it for every change of selection, which will
352
// completely clutter the undo history. Maybe rather save it to prefs on exit and re-read it on startup?
354
document->current_persp3d = persp3d_document_first_persp(document);
355
if (!document->current_persp3d) {
356
document->current_persp3d = persp3d_create_xml_element (document);
359
sp_document_set_undo_sensitive(document, true);
305
361
// reset undo key when selection changes, so that same-key actions on different objects are not coalesced
306
362
if (!Inkscape::NSApplication::Application::getNewGui()) {
336
391
rdoc = sp_repr_read_file(uri, SP_SVG_NS_URI);
337
392
/* If file cannot be loaded, return NULL without warning */
338
393
if (rdoc == NULL) return NULL;
339
rroot = sp_repr_document_root(rdoc);
394
rroot = rdoc->root();
340
395
/* If xml file is not svg, return NULL without warning */
341
396
/* fixme: destroy document */
342
397
if (strcmp(rroot->name(), "svg:svg") != 0) return NULL;
385
440
/* If it cannot be loaded, return NULL without warning */
386
441
if (rdoc == NULL) return NULL;
388
rroot = sp_repr_document_root(rdoc);
443
rroot = rdoc->root();
389
444
/* If xml file is not svg, return NULL without warning */
390
445
/* fixme: destroy document */
391
446
if (strcmp(rroot->name(), "svg:svg") != 0) return NULL;
486
* Given an NRRect that may, for example, correspond to the bbox of an object
535
* Given an NR::Rect that may, for example, correspond to the bbox of an object,
487
536
* this function fits the canvas to that rect by resizing the canvas
488
537
* and translating the document root into position.
490
void SPDocument::fitToRect(NRRect const & rect)
539
void SPDocument::fitToRect(NR::Rect const &rect)
492
g_return_if_fail(!empty(rect));
494
gdouble w = rect.x1 - rect.x0;
495
gdouble h = rect.y1 - rect.y0;
496
gdouble old_height = sp_document_height(this);
497
SPUnit unit = sp_unit_get_by_id(SP_UNIT_PX);
498
sp_document_set_width(this, w, &unit);
499
sp_document_set_height(this, h, &unit);
501
NR::translate tr = NR::translate::translate(-rect.x0,-(rect.y0 + (h - old_height)));
502
static_cast<SPGroup *>(root)->translateChildItems(tr);
541
g_return_if_fail(!rect.isEmpty());
543
using NR::X; using NR::Y;
544
double const w = rect.extent(X);
545
double const h = rect.extent(Y);
547
double const old_height = sp_document_height(this);
548
SPUnit const &px(sp_unit_get_by_id(SP_UNIT_PX));
549
sp_document_set_width(this, w, &px);
550
sp_document_set_height(this, h, &px);
552
NR::translate const tr(NR::Point(0, (old_height - h))
554
SP_GROUP(root)->translateChildItems(tr);
505
557
void sp_document_set_uri(SPDocument *document, gchar const *uri)
541
593
// Update saveable repr attributes.
542
594
Inkscape::XML::Node *repr = sp_document_repr_root(document);
543
595
// changing uri in the document repr must not be not undoable
544
gboolean saved = sp_document_get_undo_sensitive(document);
545
sp_document_set_undo_sensitive(document, FALSE);
547
repr->setAttribute("sodipodi:docbase", document->base);
596
bool saved = sp_document_get_undo_sensitive(document);
597
sp_document_set_undo_sensitive(document, false);
549
599
repr->setAttribute("sodipodi:docname", document->name);
550
600
sp_document_set_undo_sensitive(document, saved);
738
788
ctx->i2vp = NR::identity();
792
* Tries to update the document state based on the modified and
793
* "update required" flags, and return true if the document has
794
* been brought fully up to date.
797
SPDocument::_updateDocument()
799
/* Process updates */
800
if (this->root->uflags || this->root->mflags) {
801
if (this->root->uflags) {
803
sp_document_setup_viewport (this, &ctx);
805
bool saved = sp_document_get_undo_sensitive(this);
806
sp_document_set_undo_sensitive(this, false);
808
this->root->updateDisplay((SPCtx *)&ctx, 0);
810
sp_document_set_undo_sensitive(this, saved);
812
this->_emitModified();
815
return !(this->root->uflags || this->root->mflags);
820
* Repeatedly works on getting the document updated, since sometimes
821
* it takes more than one pass to get the document updated. But it
822
* usually should not take more than a few loops, and certainly never
823
* more than 32 iterations. So we bail out if we hit 32 iterations,
824
* since this typically indicates we're stuck in an update loop.
742
827
sp_document_ensure_up_to_date(SPDocument *doc)
746
while (doc->root->uflags || doc->root->mflags) {
749
g_warning("More than 32 iterations while updating document '%s'", doc->uri);
750
if (doc->modified_id) {
752
gtk_idle_remove(doc->modified_id);
753
doc->modified_id = 0;
757
/* Process updates */
758
if (doc->root->uflags) {
760
sp_document_setup_viewport (doc, &ctx);
761
doc->root->updateDisplay((SPCtx *)&ctx, 0);
763
doc->_emitModified();
830
while (!doc->_updateDocument()) {
832
g_warning("More than 32 iteration while updating document '%s'", doc->uri);
765
838
if (doc->modified_id) {
766
839
/* Remove handler */
767
840
gtk_idle_remove(doc->modified_id);
768
841
doc->modified_id = 0;
847
* An idle handler to update the document. Returns true if
848
* the document needs further updates.
774
851
sp_document_idle_handler(gpointer data)
779
doc = static_cast<SPDocument *>(data);
781
#ifdef SP_DOCUMENT_DEBUG_IDLE
785
/* Process updates */
786
if (doc->root->uflags) {
788
sp_document_setup_viewport (doc, &ctx);
790
gboolean saved = sp_document_get_undo_sensitive(doc);
791
sp_document_set_undo_sensitive(doc, FALSE);
793
doc->root->updateDisplay((SPCtx *)&ctx, 0);
795
sp_document_set_undo_sensitive(doc, saved);
796
/* if (doc->root->uflags & SP_OBJECT_MODIFIED_FLAG) return TRUE; */
853
SPDocument *doc = static_cast<SPDocument *>(data);
854
if (doc->_updateDocument()) {
855
doc->modified_id = 0;
799
doc->_emitModified();
801
repeat = (doc->root->uflags || doc->root->mflags);
802
if (!repeat) doc->modified_id = 0;
806
862
static bool is_within(NR::Rect const &area, NR::Rect const &box)
826
882
s = find_items_in_area(s, SP_GROUP(o), dkey, area, test);
828
884
SPItem *child = SP_ITEM(o);
829
NR::Rect box = sp_item_bbox_desktop(child);
830
if (test(area, box) && (take_insensitive || child->isVisibleAndUnlocked(dkey))) {
885
NR::Maybe<NR::Rect> box = sp_item_bbox_desktop(child);
886
if ( box && test(area, *box) && (take_insensitive || child->isVisibleAndUnlocked(dkey))) {
831
887
s = g_slist_append(s, child);
993
1049
return find_items_in_area(NULL, SP_GROUP(document->root), dkey, box, overlaps);
1053
sp_document_items_at_points(SPDocument *document, unsigned const key, std::vector<NR::Point> points)
1055
GSList *items = NULL;
1057
// When picking along the path, we don't want small objects close together
1058
// (such as hatching strokes) to obscure each other by their deltas,
1059
// so we temporarily set delta to a small value
1060
gdouble saved_delta = prefs_get_double_attribute ("options.cursortolerance", "value", 1.0);
1061
prefs_set_double_attribute ("options.cursortolerance", "value", 0.25);
1063
for(unsigned int i = 0; i < points.size(); i++) {
1064
SPItem *item = sp_document_item_at_point(document, key, points[i],
1066
if (item && !g_slist_find(items, item))
1067
items = g_slist_prepend (items, item);
1070
// and now we restore it back
1071
prefs_set_double_attribute ("options.cursortolerance", "value", saved_delta);
997
1077
sp_document_item_at_point(SPDocument *document, unsigned const key, NR::Point const p,
998
1078
gboolean const into_groups, SPItem *upto)