123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- /*
- Copyright (C) 2001-2006, William Joseph.
- All Rights Reserved.
- This file is part of GtkRadiant.
- GtkRadiant is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- GtkRadiant is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GtkRadiant; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #if !defined (INCLUDED_TRAVERSELIB_H)
- #define INCLUDED_TRAVERSELIB_H
- #include "debugging/debugging.h"
- #include "scenelib.h"
- #include "undolib.h"
- #include "container/container.h"
- #include <list>
- #include <vector>
- #include <algorithm>
- class TraversableObserverInsertOutputIterator
- {
- protected:
- scene::Traversable::Observer* m_observer;
- public:
- typedef std::output_iterator_tag iterator_category;
- typedef void difference_type;
- typedef void value_type;
- typedef void pointer;
- typedef void reference;
- TraversableObserverInsertOutputIterator(scene::Traversable::Observer* observer)
- : m_observer(observer)
- {
- }
- TraversableObserverInsertOutputIterator& operator=(const NodeReference& node)
- {
- m_observer->insert(node);
- return *this;
- }
- TraversableObserverInsertOutputIterator& operator*() { return *this; }
- TraversableObserverInsertOutputIterator& operator++() { return *this; }
- TraversableObserverInsertOutputIterator& operator++(int) { return *this; }
- };
- class TraversableObserverEraseOutputIterator
- {
- protected:
- scene::Traversable::Observer* m_observer;
- public:
- typedef std::output_iterator_tag iterator_category;
- typedef void difference_type;
- typedef void value_type;
- typedef void pointer;
- typedef void reference;
- TraversableObserverEraseOutputIterator(scene::Traversable::Observer* observer)
- : m_observer(observer)
- {
- }
- TraversableObserverEraseOutputIterator& operator=(const NodeReference& node)
- {
- m_observer->erase(node);
- return *this;
- }
- TraversableObserverEraseOutputIterator& operator*() { return *this; }
- TraversableObserverEraseOutputIterator& operator++() { return *this; }
- TraversableObserverEraseOutputIterator& operator++(int) { return *this; }
- };
- typedef UnsortedSet<NodeSmartReference> UnsortedNodeSet;
- /// \brief Calls \p observer->\c insert for each node that exists only in \p other and \p observer->\c erase for each node that exists only in \p self
- inline void nodeset_diff(const UnsortedNodeSet& self, const UnsortedNodeSet& other, scene::Traversable::Observer* observer)
- {
- std::vector<NodeReference> sorted(self.begin(), self.end());
- std::vector<NodeReference> other_sorted(other.begin(), other.end());
- std::sort(sorted.begin(), sorted.end());
- std::sort(other_sorted.begin(), other_sorted.end());
- std::set_difference(sorted.begin(), sorted.end(), other_sorted.begin(), other_sorted.end(), TraversableObserverEraseOutputIterator(observer));
- std::set_difference(other_sorted.begin(), other_sorted.end(), sorted.begin(), sorted.end(), TraversableObserverInsertOutputIterator(observer));
- }
- /// \brief A sequence of node references which notifies an observer of inserts and deletions, and uses the global undo system to provide undo for modifications.
- class TraversableNodeSet : public scene::Traversable
- {
- UnsortedNodeSet m_children;
- UndoableObject<TraversableNodeSet> m_undo;
- Observer* m_observer;
- void copy(const TraversableNodeSet& other)
- {
- m_children = other.m_children;
- }
- void notifyInsertAll()
- {
- if(m_observer)
- {
- for(UnsortedNodeSet::iterator i = m_children.begin(); i != m_children.end(); ++i)
- {
- m_observer->insert(*i);
- }
- }
- }
- void notifyEraseAll()
- {
- if(m_observer)
- {
- for(UnsortedNodeSet::iterator i = m_children.begin(); i != m_children.end(); ++i)
- {
- m_observer->erase(*i);
- }
- }
- }
- public:
- TraversableNodeSet()
- : m_undo(*this), m_observer(0)
- {
- }
- TraversableNodeSet(const TraversableNodeSet& other)
- : scene::Traversable(other), m_undo(*this), m_observer(0)
- {
- copy(other);
- notifyInsertAll();
- }
- ~TraversableNodeSet()
- {
- notifyEraseAll();
- }
- TraversableNodeSet& operator=(const TraversableNodeSet& other)
- {
- #if 1 // optimised change-tracking using diff algorithm
- if(m_observer)
- {
- nodeset_diff(m_children, other.m_children, m_observer);
- }
- copy(other);
- #else
- TraversableNodeSet tmp(other);
- tmp.swap(*this);
- #endif
- return *this;
- }
- void swap(TraversableNodeSet& other)
- {
- std::swap(m_children, other.m_children);
- std::swap(m_observer, other.m_observer);
- }
- void attach(Observer* observer)
- {
- ASSERT_MESSAGE(m_observer == 0, "TraversableNodeSet::attach: observer cannot be attached");
- m_observer = observer;
- notifyInsertAll();
- }
- void detach(Observer* observer)
- {
- ASSERT_MESSAGE(m_observer == observer, "TraversableNodeSet::detach: observer cannot be detached");
- notifyEraseAll();
- m_observer = 0;
- }
- /// \brief \copydoc scene::Traversable::insert()
- void insert(scene::Node& node)
- {
- ASSERT_MESSAGE(&node != 0, "TraversableNodeSet::insert: sanity check failed");
- m_undo.save();
- ASSERT_MESSAGE(m_children.find(NodeSmartReference(node)) == m_children.end(), "TraversableNodeSet::insert - element already exists");
- m_children.insert(NodeSmartReference(node));
- if(m_observer)
- {
- m_observer->insert(node);
- }
- }
- /// \brief \copydoc scene::Traversable::erase()
- void erase(scene::Node& node)
- {
- ASSERT_MESSAGE(&node != 0, "TraversableNodeSet::erase: sanity check failed");
- m_undo.save();
- ASSERT_MESSAGE(m_children.find(NodeSmartReference(node)) != m_children.end(), "TraversableNodeSet::erase - failed to find element");
- if(m_observer)
- {
- m_observer->erase(node);
- }
- m_children.erase(NodeSmartReference(node));
- }
- /// \brief \copydoc scene::Traversable::traverse()
- void traverse(const Walker& walker)
- {
- UnsortedNodeSet::iterator i = m_children.begin();
- while(i != m_children.end())
- {
- // post-increment the iterator
- Node_traverseSubgraph(*i++, walker);
- // the Walker can safely remove the current node from
- // this container without invalidating the iterator
- }
- }
- /// \brief \copydoc scene::Traversable::empty()
- bool empty() const
- {
- return m_children.empty();
- }
- void instanceAttach(MapFile* map)
- {
- m_undo.instanceAttach(map);
- }
- void instanceDetach(MapFile* map)
- {
- m_undo.instanceDetach(map);
- }
- };
- namespace std
- {
- /// \brief Swaps the values of \p self and \p other.
- /// Overloads std::swap.
- inline void swap(TraversableNodeSet& self, TraversableNodeSet& other)
- {
- self.swap(other);
- }
- }
- class TraversableNode : public scene::Traversable
- {
- public:
- TraversableNode() : m_node(0), m_observer(0)
- {
- }
- // traverse
- void attach(Observer* observer)
- {
- ASSERT_MESSAGE(m_observer == 0, "TraversableNode::attach - cannot attach observer");
- m_observer = observer;
- if(m_node != 0)
- {
- m_observer->insert(*m_node);
- }
- }
- void detach(Observer* observer)
- {
- ASSERT_MESSAGE(m_observer == observer, "TraversableNode::detach - cannot detach observer");
- if(m_node != 0)
- {
- m_observer->erase(*m_node);
- }
- m_observer = 0;
- }
- void insert(scene::Node& node)
- {
- ASSERT_MESSAGE(m_node == 0, "TraversableNode::insert - element already exists");
- m_node = &node;
- node.IncRef();
- if(m_observer != 0)
- {
- m_observer->insert(node);
- }
- }
- void erase(scene::Node& node)
- {
- ASSERT_MESSAGE(m_node == &node, "TraversableNode::erase - failed to find element");
- if(m_observer != 0)
- {
- m_observer->erase(node);
- }
- m_node = 0;
- node.DecRef();
- }
- void traverse(const scene::Traversable::Walker& walker)
- {
- if(m_node != 0)
- {
- Node_traverseSubgraph(*m_node, walker);
- }
- }
- bool empty() const
- {
- return m_node != 0;
- }
- scene::Node& get()
- {
- return *m_node;
- }
- private:
- scene::Node* m_node;
- Observer* m_observer;
- };
- class TraversableObserverInsert
- {
- scene::Node& node;
- public:
- TraversableObserverInsert(scene::Node& node) : node(node)
- {
- }
- void operator()(scene::Traversable::Observer& observer) const
- {
- observer.insert(node);
- }
- };
- class TraversableObserverErase
- {
- scene::Node& node;
- public:
- TraversableObserverErase(scene::Node& node) : node(node)
- {
- }
- void operator()(scene::Traversable::Observer& observer) const
- {
- observer.erase(node);
- }
- };
- class TraversableObserverPairRelay : public ReferencePair<scene::Traversable::Observer>, public scene::Traversable::Observer
- {
- public:
- void insert(scene::Node& node)
- {
- forEach(TraversableObserverInsert(node));
- }
- void erase(scene::Node& node)
- {
- forEach(TraversableObserverErase(node));
- }
- };
- #endif
|