diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/object-hierarchy.cpp | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/object-hierarchy.cpp')
| -rw-r--r-- | src/object-hierarchy.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/object-hierarchy.cpp b/src/object-hierarchy.cpp new file mode 100644 index 000000000..30f13e49a --- /dev/null +++ b/src/object-hierarchy.cpp @@ -0,0 +1,213 @@ +/** \file + * Object hierarchy implementation. + * + * Authors: + * MenTaLguY <mental@rydia.net> + * + * Copyright (C) 2004 MenTaLguY + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "sp-object.h" +#include "object-hierarchy.h" + +namespace Inkscape { + +/** + * Create new object hierarchy. + * \param top The first entry if non-NULL. + */ +ObjectHierarchy::ObjectHierarchy(SPObject *top) { + if (top) { + _addBottom(top); + } +} + +ObjectHierarchy::~ObjectHierarchy() { + _clear(); +} + +/** + * Remove all entries. + */ +void ObjectHierarchy::clear() { + _clear(); + _changed_signal.emit(NULL, NULL); +} + +/** + * Trim or expand hierarchy on top such that object becomes top entry. + */ +void ObjectHierarchy::setTop(SPObject *object) { + g_return_if_fail(object != NULL); + + if ( top() == object ) { + return; + } + + if (!top()) { + _addTop(object); + } else if (object->isAncestorOf(top())) { + _addTop(object, top()); + } else if ( object == bottom() || object->isAncestorOf(bottom()) ) { + _trimAbove(object); + } else { + _clear(); + _addTop(object); + } + + _changed_signal.emit(top(), bottom()); +} + +/** + * Add hierarchy from junior's parent to senior to this + * hierarchy's top. + */ +void ObjectHierarchy::_addTop(SPObject *senior, SPObject *junior) { + g_assert(junior != NULL); + g_assert(senior != NULL); + + SPObject *object=SP_OBJECT_PARENT(junior); + do { + _addTop(object); + object = SP_OBJECT_PARENT(object); + } while ( object != senior ); +} + +/** + * Add object to top of hierarchy. + * \pre object!=NULL + */ +void ObjectHierarchy::_addTop(SPObject *object) { + g_assert(object != NULL); + _hierarchy.push_back(_attach(object)); + _added_signal.emit(object); +} + +/** + * Remove all objects above limit from hierarchy. + */ +void ObjectHierarchy::_trimAbove(SPObject *limit) { + while ( !_hierarchy.empty() && _hierarchy.back().object != limit ) { + SPObject *object=_hierarchy.back().object; + + sp_object_ref(object, NULL); + _detach(_hierarchy.back()); + _hierarchy.pop_back(); + _removed_signal.emit(object); + sp_object_unref(object, NULL); + } +} + +/** + * Trim or expand hierarchy at bottom such that object becomes bottom entry. + */ +void ObjectHierarchy::setBottom(SPObject *object) { + g_return_if_fail(object != NULL); + + if ( bottom() == object ) { + return; + } + + if (!top()) { + _addBottom(object); + } else if (bottom()->isAncestorOf(object)) { + _addBottom(bottom(), object); + } else if ( top() == object ) { + _trimBelow(top()); + } else if (top()->isAncestorOf(object)) { + if (object->isAncestorOf(bottom())) { + _trimBelow(object); + } else { // object is a sibling or cousin of bottom() + SPObject *saved_top=top(); + sp_object_ref(saved_top, NULL); + _clear(); + _addBottom(saved_top); + _addBottom(saved_top, object); + sp_object_unref(saved_top, NULL); + } + } else { + _clear(); + _addBottom(object); + } + + _changed_signal.emit(top(), bottom()); +} + +/** + * Remove all objects under given object. + * \param limit If NULL, remove all. + */ +void ObjectHierarchy::_trimBelow(SPObject *limit) { + while ( !_hierarchy.empty() && _hierarchy.front().object != limit ) { + SPObject *object=_hierarchy.front().object; + sp_object_ref(object, NULL); + _detach(_hierarchy.front()); + _hierarchy.pop_front(); + _removed_signal.emit(object); + sp_object_unref(object, NULL); + } +} + +/** + * Add hierarchy from senior to junior to this hierarchy's bottom. + */ +void ObjectHierarchy::_addBottom(SPObject *senior, SPObject *junior) { + g_assert(junior != NULL); + g_assert(senior != NULL); + + if ( junior != senior ) { + _addBottom(senior, SP_OBJECT_PARENT(junior)); + _addBottom(junior); + } +} + +/** + * Add object at bottom of hierarchy. + * \pre object!=NULL + */ +void ObjectHierarchy::_addBottom(SPObject *object) { + g_assert(object != NULL); + _hierarchy.push_front(_attach(object)); + _added_signal.emit(object); +} + +void ObjectHierarchy::_trim_for_release(SPObject *object, ObjectHierarchy *hier) +{ + hier->_trimBelow(object); + g_assert(!hier->_hierarchy.empty()); + g_assert(hier->_hierarchy.front().object == object); + + sp_object_ref(object, NULL); + hier->_detach(hier->_hierarchy.front()); + hier->_hierarchy.pop_front(); + hier->_removed_signal.emit(object); + sp_object_unref(object, NULL); + + hier->_changed_signal.emit(hier->top(), hier->bottom()); +} + +ObjectHierarchy::Record ObjectHierarchy::_attach(SPObject *object) { + sp_object_ref(object, NULL); + gulong id = g_signal_connect(G_OBJECT(object), "release", GCallback(&ObjectHierarchy::_trim_for_release), this); + return Record(object, id); +} + +void ObjectHierarchy::_detach(ObjectHierarchy::Record const &rec) { + g_signal_handler_disconnect(G_OBJECT(rec.object), rec.handler_id); + sp_object_unref(rec.object, NULL); +} + +} + +/* + 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 : |
