X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fdocument.cpp;h=252c9b17379070e296bc2cc7b058400b42b841da;hb=724821145d62dee9f97465c706952582da6e432d;hp=eca4ab2dcae09a1be42a916789ee1fe4eeb0e487;hpb=b79f3338a624d38a58133d70f0baa440f9a9ffd2;p=inkscape.git diff --git a/src/document.cpp b/src/document.cpp index eca4ab2dc..252c9b173 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -70,6 +70,8 @@ gboolean sp_document_resource_list_free(gpointer key, gpointer value, gpointer d static gint doc_count = 0; +static unsigned long next_serial = 0; + SPDocument::SPDocument() { SPDocumentPrivate *p; @@ -91,9 +93,13 @@ SPDocument::SPDocument() { // Initialise instance of connector router. router = new Avoid::Router(); + // Don't use the Consolidate moves optimisation. + router->ConsolidateMoves = false; p = new SPDocumentPrivate(); + p->serial = next_serial++; + p->iddef = g_hash_table_new(g_direct_hash, g_direct_equal); p->reprdef = g_hash_table_new(g_direct_hash, g_direct_equal); @@ -104,16 +110,18 @@ SPDocument::SPDocument() { p->history_size = 0; p->undo = NULL; p->redo = NULL; + p->seeking = false; priv = p; + + // XXX only for testing! + priv->undoStackObservers.add(p->console_output_undo_observer); } SPDocument::~SPDocument() { collectOrphans(); if (priv) { - inkscape_remove_document(this); - if (priv->partial) { sp_repr_free_log(priv->partial); priv->partial = NULL; @@ -123,8 +131,8 @@ SPDocument::~SPDocument() { sp_document_clear_undo(this); if (root) { - sp_object_invoke_release(root); - g_object_unref(G_OBJECT(root)); + root->releaseReferences(); + sp_object_unref(root); root = NULL; } @@ -178,6 +186,10 @@ SPDocument::~SPDocument() { //delete this->_whiteboard_session_manager; } +unsigned long SPDocument::serial() const { + return priv->serial; +} + void SPDocument::queueForOrphanCollection(SPObject *object) { g_return_if_fail(object != NULL); g_return_if_fail(SP_OBJECT_DOCUMENT(object) == this); @@ -204,7 +216,7 @@ void SPDocument::reset_key (void *dummy) actionkey = NULL; } -static SPDocument * +SPDocument * sp_document_create(Inkscape::XML::Document *rdoc, gchar const *uri, gchar const *base, @@ -215,7 +227,7 @@ sp_document_create(Inkscape::XML::Document *rdoc, Inkscape::XML::Node *rroot; Inkscape::Version sodipodi_version; - rroot = sp_repr_document_root(rdoc); + rroot = rdoc->root(); document = new SPDocument(); @@ -256,10 +268,7 @@ sp_document_create(Inkscape::XML::Document *rdoc, /* Quick hack 3 - Set uri attributes */ if (uri) { - /* fixme: Think, what this means for images (Lauris) */ rroot->setAttribute("sodipodi:docname", uri); - if (document->base) - rroot->setAttribute("sodipodi:docbase", document->base); } /* End of quick hack 3 */ @@ -272,11 +281,11 @@ sp_document_create(Inkscape::XML::Document *rdoc, // see if there's a template with id="base" in the preferences if (!r) { // if there's none, create an empty element - rnew = sp_repr_new("sodipodi:namedview"); + rnew = rdoc->createElement("sodipodi:namedview"); rnew->setAttribute("id", "base"); } else { // otherwise, take from preferences - rnew = r->duplicate(); + rnew = r->duplicate(rroot->document()); } // insert into the document rroot->addChild(rnew, NULL); @@ -287,7 +296,7 @@ sp_document_create(Inkscape::XML::Document *rdoc, /* Defs */ if (!SP_ROOT(document->root)->defs) { Inkscape::XML::Node *r; - r = sp_repr_new("svg:defs"); + r = rdoc->createElement("svg:defs"); rroot->addChild(r, NULL); Inkscape::GC::release(r); g_assert(SP_ROOT(document->root)->defs); @@ -300,7 +309,7 @@ sp_document_create(Inkscape::XML::Document *rdoc, inkscape_ref(); } - sp_document_set_undo_sensitive(document, TRUE); + sp_document_set_undo_sensitive(document, true); // reset undo key when selection changes, so that same-key actions on different objects are not coalesced if (!Inkscape::NSApplication::Application::getNewGui()) { @@ -312,7 +321,6 @@ sp_document_create(Inkscape::XML::Document *rdoc, document->_selection_changed_connection = Inkscape::NSApplication::Editor::connectSelectionChanged (sigc::mem_fun (*document, &SPDocument::reset_key)); document->_desktop_activated_connection = Inkscape::NSApplication::Editor::connectDesktopActivated (sigc::mem_fun (*document, &SPDocument::reset_key)); } - inkscape_add_document(document); return document; } @@ -336,7 +344,7 @@ sp_document_new(gchar const *uri, unsigned int keepalive, bool make_new) rdoc = sp_repr_read_file(uri, SP_SVG_NS_URI); /* If file cannot be loaded, return NULL without warning */ if (rdoc == NULL) return NULL; - rroot = sp_repr_document_root(rdoc); + rroot = rdoc->root(); /* If xml file is not svg, return NULL without warning */ /* fixme: destroy document */ if (strcmp(rroot->name(), "svg:svg") != 0) return NULL; @@ -385,7 +393,7 @@ sp_document_new_from_mem(gchar const *buffer, gint length, unsigned int keepaliv /* If it cannot be loaded, return NULL without warning */ if (rdoc == NULL) return NULL; - rroot = sp_repr_document_root(rdoc); + rroot = rdoc->root(); /* If xml file is not svg, return NULL without warning */ /* fixme: destroy document */ if (strcmp(rroot->name(), "svg:svg") != 0) return NULL; @@ -397,12 +405,6 @@ sp_document_new_from_mem(gchar const *buffer, gint length, unsigned int keepaliv return doc; } -SPDocument *sp_document_new_dummy() { - SPDocument *document = new SPDocument(); - inkscape_add_document(document); - return document; -} - SPDocument * sp_document_ref(SPDocument *doc) { @@ -483,23 +485,26 @@ gdouble sp_document_height(SPDocument *document) } /** - * Given an NRRect that may, for example, correspond to the bbox of an object + * Given an NR::Rect that may, for example, correspond to the bbox of an object, * this function fits the canvas to that rect by resizing the canvas * and translating the document root into position. */ -void SPDocument::fitToRect(NRRect const & rect) +void SPDocument::fitToRect(NR::Rect const &rect) { - g_return_if_fail(!empty(rect)); - - gdouble w = rect.x1 - rect.x0; - gdouble h = rect.y1 - rect.y0; - gdouble old_height = sp_document_height(this); - SPUnit unit = sp_unit_get_by_id(SP_UNIT_PX); - sp_document_set_width(this, w, &unit); - sp_document_set_height(this, h, &unit); - - NR::translate tr = NR::translate::translate(-rect.x0,-(rect.y0 + (h - old_height))); - static_cast(root)->translateChildItems(tr); + g_return_if_fail(!rect.isEmpty()); + + using NR::X; using NR::Y; + double const w = rect.extent(X); + double const h = rect.extent(Y); + + double const old_height = sp_document_height(this); + SPUnit const &px(sp_unit_get_by_id(SP_UNIT_PX)); + sp_document_set_width(this, w, &px); + sp_document_set_height(this, h, &px); + + NR::translate const tr(NR::Point(0, (old_height - h)) + - rect.min()); + SP_GROUP(root)->translateChildItems(tr); } void sp_document_set_uri(SPDocument *document, gchar const *uri) @@ -541,10 +546,8 @@ void sp_document_set_uri(SPDocument *document, gchar const *uri) // Update saveable repr attributes. Inkscape::XML::Node *repr = sp_document_repr_root(document); // changing uri in the document repr must not be not undoable - gboolean saved = sp_document_get_undo_sensitive(document); - sp_document_set_undo_sensitive(document, FALSE); - if (document->base) - repr->setAttribute("sodipodi:docbase", document->base); + bool saved = sp_document_get_undo_sensitive(document); + sp_document_set_undo_sensitive(document, false); repr->setAttribute("sodipodi:docname", document->name); sp_document_set_undo_sensitive(document, saved); @@ -603,6 +606,12 @@ SPDocument::emitReconstructionFinish(void) return; } +sigc::connection SPDocument::connectCommit(SPDocument::CommitSignal::slot_type slot) +{ + return priv->commit_signal.connect(slot); +} + + void SPDocument::_emitModified() { static guint const flags = SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG; @@ -732,69 +741,75 @@ sp_document_setup_viewport (SPDocument *doc, SPItemCtx *ctx) ctx->i2vp = NR::identity(); } +/** + * Tries to update the document state based on the modified and + * "update required" flags, and return true if the document has + * been brought fully up to date. + */ +bool +SPDocument::_updateDocument() +{ + /* Process updates */ + if (this->root->uflags || this->root->mflags) { + if (this->root->uflags) { + SPItemCtx ctx; + sp_document_setup_viewport (this, &ctx); + + bool saved = sp_document_get_undo_sensitive(this); + sp_document_set_undo_sensitive(this, false); + + this->root->updateDisplay((SPCtx *)&ctx, 0); + + sp_document_set_undo_sensitive(this, saved); + } + this->_emitModified(); + } + + return !(this->root->uflags || this->root->mflags); +} + + +/** + * Repeatedly works on getting the document updated, since sometimes + * it takes more than one pass to get the document updated. But it + * usually should not take more than a few loops, and certainly never + * more than 32 iterations. So we bail out if we hit 32 iterations, + * since this typically indicates we're stuck in an update loop. + */ gint sp_document_ensure_up_to_date(SPDocument *doc) { - int lc; - lc = 32; - while (doc->root->uflags || doc->root->mflags) { - lc -= 1; - if (lc < 0) { - g_warning("More than 32 iterations while updating document '%s'", doc->uri); - if (doc->modified_id) { - /* Remove handler */ - gtk_idle_remove(doc->modified_id); - doc->modified_id = 0; - } - return FALSE; - } - /* Process updates */ - if (doc->root->uflags) { - SPItemCtx ctx; - sp_document_setup_viewport (doc, &ctx); - doc->root->updateDisplay((SPCtx *)&ctx, 0); + int counter = 32; + while (!doc->_updateDocument()) { + if (counter == 0) { + g_warning("More than 32 iteration while updating document '%s'", doc->uri); + break; } - doc->_emitModified(); + counter--; } + if (doc->modified_id) { /* Remove handler */ gtk_idle_remove(doc->modified_id); doc->modified_id = 0; } - return TRUE; + return counter>0; } +/** + * An idle handler to update the document. Returns true if + * the document needs further updates. + */ static gint sp_document_idle_handler(gpointer data) { - SPDocument *doc; - int repeat; - - doc = static_cast(data); - -#ifdef SP_DOCUMENT_DEBUG_IDLE - g_print("->\n"); -#endif - - /* Process updates */ - if (doc->root->uflags) { - SPItemCtx ctx; - sp_document_setup_viewport (doc, &ctx); - - gboolean saved = sp_document_get_undo_sensitive(doc); - sp_document_set_undo_sensitive(doc, FALSE); - - doc->root->updateDisplay((SPCtx *)&ctx, 0); - - sp_document_set_undo_sensitive(doc, saved); - /* if (doc->root->uflags & SP_OBJECT_MODIFIED_FLAG) return TRUE; */ + SPDocument *doc = static_cast(data); + if (doc->_updateDocument()) { + doc->modified_id = 0; + return false; + } else { + return true; } - - doc->_emitModified(); - - repeat = (doc->root->uflags || doc->root->mflags); - if (!repeat) doc->modified_id = 0; - return repeat; } static bool is_within(NR::Rect const &area, NR::Rect const &box) @@ -820,8 +835,8 @@ static GSList *find_items_in_area(GSList *s, SPGroup *group, unsigned int dkey, s = find_items_in_area(s, SP_GROUP(o), dkey, area, test); } else { SPItem *child = SP_ITEM(o); - NR::Rect box = sp_item_bbox_desktop(child); - if (test(area, box) && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { + NR::Maybe box = sp_item_bbox_desktop(child); + if ( box && test(area, *box) && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { s = g_slist_append(s, child); } } @@ -987,6 +1002,30 @@ GSList *sp_document_partial_items_in_box(SPDocument *document, unsigned int dkey return find_items_in_area(NULL, SP_GROUP(document->root), dkey, box, overlaps); } +GSList * +sp_document_items_at_points(SPDocument *document, unsigned const key, std::vector points) +{ + GSList *items = NULL; + + // When picking along the path, we don't want small objects close together + // (such as hatching strokes) to obscure each other by their deltas, + // so we temporarily set delta to a small value + gdouble saved_delta = prefs_get_double_attribute ("options.cursortolerance", "value", 1.0); + prefs_set_double_attribute ("options.cursortolerance", "value", 0.25); + + for(unsigned int i = 0; i < points.size(); i++) { + SPItem *item = sp_document_item_at_point(document, key, points[i], + false, NULL); + if (item && !g_slist_find(items, item)) + items = g_slist_prepend (items, item); + } + + // and now we restore it back + prefs_set_double_attribute ("options.cursortolerance", "value", saved_delta); + + return items; +} + SPItem * sp_document_item_at_point(SPDocument *document, unsigned const key, NR::Point const p, gboolean const into_groups, SPItem *upto) @@ -1143,6 +1182,10 @@ vacuum_document(SPDocument *document) return start - newend; } +bool SPDocument::isSeeking() const { + return priv->seeking; +} + /* Local Variables: