summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: e8d5b41)
raw | patch | inline | side by side (parent: e8d5b41)
author | mental <mental@users.sourceforge.net> | |
Sun, 5 Mar 2006 21:28:27 +0000 (21:28 +0000) | ||
committer | mental <mental@users.sourceforge.net> | |
Sun, 5 Mar 2006 21:28:27 +0000 (21:28 +0000) |
ChangeLog | patch | blob | history | |
src/Makefile_insert | patch | blob | history | |
src/document-subset.cpp | [new file with mode: 0644] | patch | blob |
src/document-subset.h | [new file with mode: 0644] | patch | blob |
diff --git a/ChangeLog b/ChangeLog
index aef3dcd009a7f8c138bd4848781abee9ed2a29a6..622e817e536072dc8d39362ea12008be943099c9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+2006-03-05 MenTaLguY <mental@rydia.net>
+
+ * src/Makefile_insert, src/document-subset.cpp, src/document-subset.h:
+
+ Add DocumentSubset as groundwork for layers.
+
2006-03-04 Jon A. Cruz <jon@joncruz.org>
* src/ui/widget/selected-style.h, src/ui/widget/selected-style.cpp:
diff --git a/src/Makefile_insert b/src/Makefile_insert
index 302bd8089f3071e75acf2d4bd584d4aca11759f7..d42c2fa3bd208eaa0c95556d3271e87b0bd584ef 100644 (file)
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
desktop.cpp desktop.h \
document-undo.cpp \
document.cpp document.h document-private.h \
+ document-subset.cpp document-subset.h \
doxygen-main.cpp \
draw-anchor.cpp \
draw-anchor.h \
diff --git a/src/document-subset.cpp b/src/document-subset.cpp
--- /dev/null
+++ b/src/document-subset.cpp
@@ -0,0 +1,362 @@
+/*
+ * Inkscape::DocumentSubset - view of a document including only a subset
+ * of nodes
+ *
+ * Copyright 2006 MenTaLguY <mental@rydia.net>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "gc-finalized.h"
+#include "document-subset.h"
+#include "document.h"
+#include "sp-object.h"
+
+#include <glib/gmessages.h>
+
+#include <sigc++/signal.h>
+
+#include "util/list.h"
+#include "util/reverse-list.h"
+
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <iterator>
+
+namespace Inkscape {
+
+struct DocumentSubset::Relations : public GC::Managed<GC::ATOMIC>,
+ public GC::Finalized
+{
+ typedef std::vector<SPObject *> Siblings;
+
+ struct Record {
+ SPObject *parent;
+ Siblings children;
+
+ gulong release_connection;
+
+ Record() : parent(NULL), release_connection(0) {}
+
+ unsigned childIndex(SPObject *obj) {
+ Siblings::iterator found;
+ found = std::find(children.begin(), children.end(), obj);
+ if ( found != children.end() ) {
+ return found - children.begin();
+ } else {
+ return 0;
+ }
+ }
+
+ unsigned findInsertIndex(SPObject *obj) const {
+ if (children.empty()) {
+ return 0;
+ } else {
+ Siblings::const_iterator first=children.begin();
+ Siblings::const_iterator last=children.end() - 1;
+ while ( first != last ) {
+ Siblings::const_iterator mid=first + ( last - first + 1 ) / 2;
+ int pos=sp_object_compare_position(*mid, obj);
+ if ( pos < 0 ) {
+ first = mid;
+ } else if ( pos > 0 ) {
+ last = mid;
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ return last - children.begin();
+ }
+ }
+
+ void addChild(SPObject *obj) {
+ unsigned index=findInsertIndex(obj);
+ children.insert(children.begin()+index, obj);
+ }
+
+ template <typename OutputIterator>
+ void extractDescendants(OutputIterator descendants,
+ SPObject *obj)
+ {
+ Siblings new_children;
+ bool found_one=false;
+ for ( Siblings::iterator iter=children.begin()
+ ; iter != children.end() ; iter++ )
+ {
+ if (obj->isAncestorOf(*iter)) {
+ if (!found_one) {
+ found_one = true;
+ new_children.insert(new_children.end(),
+ children.begin(), iter);
+ }
+ *descendants++ = *iter;
+ } else if (found_one) {
+ new_children.push_back(*iter);
+ }
+ }
+ if (found_one) {
+ children.swap(new_children);
+ }
+ }
+
+ unsigned removeChild(SPObject *obj) {
+ Siblings::iterator found;
+ found = std::find(children.begin(), children.end(), obj);
+ unsigned index = found - children.begin();
+ if ( found != children.end() ) {
+ children.erase(found);
+ }
+ return index;
+ }
+ };
+
+ typedef std::map<SPObject *, Record> Map;
+ Map records;
+
+ sigc::signal<void> changed_signal;
+ sigc::signal<void, SPObject *> added_signal;
+ sigc::signal<void, SPObject *> removed_signal;
+
+ Relations() { records[NULL]; }
+
+ ~Relations() {
+ for ( Map::iterator iter=records.begin()
+ ; iter != records.end() ; ++iter )
+ {
+ sp_object_unref((*iter).first);
+ }
+ }
+
+ Record *get(SPObject *obj) {
+ Map::iterator found=records.find(obj);
+ if ( found != records.end() ) {
+ return &(*found).second;
+ } else {
+ return NULL;
+ }
+ }
+
+ void addOne(SPObject *obj);
+ void remove(SPObject *obj, bool subtree);
+ void reorder(SPObject *obj);
+
+private:
+ Record &_doAdd(SPObject *obj) {
+ sp_object_ref(obj);
+ Record &record=records[obj];
+ record.release_connection
+ = g_signal_connect(obj, "release",
+ (GCallback)&Relations::_release_object, this);
+ return record;
+ }
+
+ void _notifyAdded(SPObject *obj) {
+ added_signal.emit(obj);
+ }
+
+ void _doRemove(SPObject *obj) {
+ Record &record=records[obj];
+ if (record.release_connection) {
+ g_signal_handler_disconnect(obj, record.release_connection);
+ record.release_connection = 0;
+ }
+ records.erase(obj);
+ removed_signal.emit(obj);
+ sp_object_unref(obj);
+ }
+
+ void _doRemoveSubtree(SPObject *obj) {
+ Record *record=get(obj);
+ if (record) {
+ Siblings &children=record->children;
+ for ( Siblings::iterator iter=children.begin()
+ ; iter != children.end() ; ++iter )
+ {
+ _doRemoveSubtree(*iter);
+ }
+ _doRemove(obj);
+ }
+ }
+
+ static void _release_object(SPObject *obj, void *relations_p) {
+ Relations &relations=*static_cast<Relations *>(relations_p);
+ if (relations.get(obj)) {
+ relations.remove(obj, true);
+ }
+ }
+};
+
+DocumentSubset::DocumentSubset(SPDocument *document)
+: _document(document), _relations(new DocumentSubset::Relations())
+{
+}
+
+void DocumentSubset::Relations::addOne(SPObject *obj) {
+ g_return_if_fail( obj != NULL );
+ g_return_if_fail( get(obj) != NULL );
+
+ Record &record=_doAdd(obj);
+
+ /* find the nearest ancestor in the subset */
+ Record *parent_record=NULL;
+ for ( SPObject::ParentIterator parent_iter=obj->parent
+ ; !parent_record && parent_iter ; ++parent_iter )
+ {
+ parent_record = get(parent_iter);
+ if (parent_record) {
+ record.parent = parent_iter;
+ }
+ }
+ if (!parent_record) {
+ parent_record = get(NULL);
+ g_assert( parent_record != NULL );
+ }
+
+ Siblings &children=record.children;
+
+ /* reparent descendants of obj to obj */
+ parent_record->extractDescendants(
+ std::back_insert_iterator<Siblings>(children),
+ obj
+ );
+ for ( Siblings::iterator iter=children.begin()
+ ; iter != children.end() ; ++iter )
+ {
+ Record *child_record=get(*iter);
+ g_assert( child_record != NULL );
+ child_record->parent = obj;
+ }
+
+ /* add obj to the child list */
+ parent_record->addChild(obj);
+
+ _notifyAdded(obj);
+ changed_signal.emit();
+}
+
+void DocumentSubset::Relations::remove(SPObject *obj, bool subtree) {
+ g_return_if_fail( obj != NULL );
+
+ Record *record=get(obj);
+ g_return_if_fail( record != NULL );
+
+ Record *parent_record=get(record->parent);
+ g_assert( parent_record != NULL );
+
+ unsigned index=parent_record->removeChild(obj);
+
+ if (subtree) {
+ _doRemoveSubtree(obj);
+ } else {
+ /* reparent obj's orphaned children to their grandparent */
+ Siblings &siblings=parent_record->children;
+ Siblings &children=record->children;
+ siblings.insert(siblings.begin()+index,
+ children.begin(), children.end());
+
+ for ( Siblings::iterator iter=children.begin()
+ ; iter != children.end() ; iter++ )
+ {
+ Record *child_record=get(*iter);
+ g_assert( child_record != NULL );
+ child_record->parent = record->parent;
+ }
+
+ /* remove obj's record */
+ _doRemove(obj);
+ }
+
+ changed_signal.emit();
+}
+
+void DocumentSubset::Relations::reorder(SPObject *obj) {
+ SPObject::ParentIterator parent=obj;
+
+ /* find nearest ancestor in the subset */
+ Record *parent_record=NULL;
+ while (!parent_record) {
+ parent_record = get(++parent);
+ }
+
+ if (get(obj)) {
+ /* move the object if it's in the subset */
+ parent_record->removeChild(obj);
+ parent_record->addChild(obj);
+ changed_signal.emit();
+ } else {
+ /* otherwise, move any top-level descendants */
+ Siblings descendants;
+ parent_record->extractDescendants(
+ std::back_insert_iterator<Siblings>(descendants),
+ obj
+ );
+ if (!descendants.empty()) {
+ unsigned index=parent_record->findInsertIndex(obj);
+ Siblings &family=parent_record->children;
+ family.insert(family.begin()+index,
+ descendants.begin(), descendants.end());
+ changed_signal.emit();
+ }
+ }
+}
+
+void DocumentSubset::_addOne(SPObject *obj) {
+ _relations->addOne(obj);
+}
+
+void DocumentSubset::_remove(SPObject *obj, bool subtree) {
+ _relations->remove(obj, subtree);
+}
+
+bool DocumentSubset::includes(SPObject *obj) const {
+ return _relations->get(obj);
+}
+
+SPObject *DocumentSubset::parentOf(SPObject *obj) const {
+ Relations::Record *record=_relations->get(obj);
+ return ( record ? record->parent : NULL );
+}
+
+unsigned DocumentSubset::childCount(SPObject *obj) const {
+ Relations::Record *record=_relations->get(obj);
+ return ( record ? record->children.size() : 0 );
+}
+
+unsigned DocumentSubset::indexOf(SPObject *obj) const {
+ SPObject *parent=parentOf(obj);
+ Relations::Record *record=_relations->get(parent);
+ return ( record ? record->childIndex(obj) : 0 );
+}
+
+SPObject *DocumentSubset::nthChildOf(SPObject *obj, unsigned n) const {
+ Relations::Record *record=_relations->get(obj);
+ return ( record ? record->children[n] : NULL );
+}
+
+sigc::connection DocumentSubset::connectChanged(sigc::slot<void> slot) const {
+ return _relations->changed_signal.connect(slot);
+}
+
+sigc::connection
+DocumentSubset::connectAdded(sigc::slot<void, SPObject *> slot) const {
+ return _relations->added_signal.connect(slot);
+}
+
+sigc::connection
+DocumentSubset::connectRemoved(sigc::slot<void, SPObject *> slot) const {
+ return _relations->removed_signal.connect(slot);
+}
+
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/document-subset.h b/src/document-subset.h
--- /dev/null
+++ b/src/document-subset.h
@@ -0,0 +1,70 @@
+/*
+ * Inkscape::DocumentSubset - view of a document including only a subset
+ * of nodes
+ *
+ * Copyright 2006 MenTaLguY <mental@rydia.net>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DOCUMENT_SUBSET_H
+#define SEEN_INKSCAPE_DOCUMENT_SUBSET_H
+
+#include <sigc++/connection.h>
+#include <sigc++/functors/slot.h>
+
+#include "gc-managed.h"
+#include "gc-anchored.h"
+
+class SPObject;
+class SPDocument;
+
+namespace Inkscape {
+
+class DocumentSubset : public GC::Managed<>,
+ public GC::Anchored
+{
+public:
+ bool includes(SPObject *obj) const;
+
+ SPObject *parentOf(SPObject *obj) const;
+ unsigned childCount(SPObject *obj) const;
+ unsigned indexOf(SPObject *obj) const;
+ SPObject *nthChildOf(SPObject *obj, unsigned n) const;
+
+ sigc::connection connectChanged(sigc::slot<void> slot) const;
+ sigc::connection connectAdded(sigc::slot<void, SPObject *> slot) const;
+ sigc::connection connectRemoved(sigc::slot<void, SPObject *> slot) const;
+
+protected:
+ explicit DocumentSubset(SPDocument *document);
+
+ void _addOne(SPObject *obj);
+ void _removeOne(SPObject *obj) { _remove(obj, false); }
+ void _removeSubtree(SPObject *obj) { _remove(obj, true); }
+
+private:
+ DocumentSubset(DocumentSubset const &); // no copy
+ void operator=(DocumentSubset const &); // no assign
+
+ void _remove(SPObject *obj, bool subtree);
+
+ class Relations;
+
+ SPDocument *_document;
+ Relations *_relations;
+};
+
+}
+
+#endif
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :