Envision
A visual programming IDE for object-oriented languages
|
The TreeManager class is a management and access entity for a program tree. More...
Signals | |
void | nameModified (Node *node, const QString &oldName) |
Emitted when the name of a node has changed. More... | |
void | nodesModified (QSet< Node * > modifiedNodes, QSet< Node * > removedNodes) |
Emitted at the end of a modification block. More... | |
void | rootNodeSet (Node *root) |
Emitted when a new root node was set. More... | |
Public Member Functions | |
TreeManager (const QString &name, Node *root=nullptr) | |
Constructs a new TreeManager with the given name and root. More... | |
TreeManager (Node *root=nullptr) | |
Constructs a new TreeManager with the given root. More... | |
virtual | ~TreeManager () |
Deletes the root node corresponding to the TreeManager. More... | |
void | beginExclusiveRead () |
Begins an exclusive read. More... | |
void | beginModification (Node *modificationTarget, const QString &text={}) |
Begins a modification session. More... | |
bool | canBeModified (const Node *node) const |
Checks if a node can be modified. More... | |
void | changeModificationTarget (Node *modificationTarget) |
Changes the modification target and possibly the access unit that the current writer is allowed to access. More... | |
void | cleanupDestroyedNode (Node *node) |
void | emitNameModified (NameText *node, const QString &oldName) |
Causes a nameModified signal to be emitted. More... | |
void | endExclusiveRead () |
Ends an exclusive read. More... | |
void | endModification (bool tryResolvingReferences=true) |
Ends a modification session. More... | |
bool | isBeingModified () const |
bool | isOwnedByUndoStack (const Node *node, const NodeOwningCommand *excludeCommand) const |
Returns whether node is owned by a command in the undo stack. More... | |
bool | isPartiallyLoaded () const |
Returns whether this tree has been partially loaded (as a library). More... | |
void | load (PersistentStore *store, const QString &name, bool loadPartially) |
Loads the manager's tree from the specified persistent store. More... | |
Node * | modificationTarget () const |
QString | name () |
Returns the name of the manged tree. More... | |
NodeIdMap & | nodeIdMap () |
const NodeIdMap & | nodeIdMap () const |
NodeIdMap & | nodeIdMapForUndoStack () |
const NodeIdMap & | nodeIdMapForUndoStack () const |
void | notifyNodeChange (Node *node) |
Adds node to the list of modified nodes during an edit operation or immediately emits a nodesModified signal with the specified node if no modification to the tree is ongoing. More... | |
void | pushCommandOnUndoStack (UndoCommand *command) |
Pushes the specified command on the undo stack and executes it. More... | |
void | redo () |
Redoes the commands executed in the next modification block. More... | |
QString | revisionName () |
Returns the name of the revision. More... | |
Node * | root () |
Returns the root node for this manager. More... | |
NodeReadWriteLock * | rootLock () |
Returns the lock corresponding to the top-most (root) access unit. More... | |
void | save (PersistentStore *store=nullptr) |
Saves the tree in persistent store of the tree manager. More... | |
void | setName (const QString &name) |
Sets the name of the tree. More... | |
void | setRevisionName (const QString &revisionName) |
Sets the name of the revision. More... | |
void | setRoot (Node *node) |
Sets the root node of this manager to node. More... | |
PersistentStore * | store () |
Returns the current store for this manager. More... | |
void | undo () |
Undoes the commands executed in the previous modification block. More... | |
Static Private Member Functions | |
static bool | isOwnedByCommand (const Node *node, const UndoCommand *cmd, const NodeOwningCommand *excludeCommand) |
Returns whether node is transitively owned by cmd. More... | |
Private Attributes | |
QUndoStack | commands |
The command stack that holds the undo history. More... | |
NodeReadWriteLock * | currentModificationLock {} |
The lock of the access unit that is responsible for the current modification target node. More... | |
Node * | currentModificationTarget {} |
The node that is the top-most ancestor of all other nodes that are currently being modification. More... | |
QReadWriteLock | exclusiveAccess |
A ReadWrite lock used for exclusive writer or reader access. More... | |
bool | modificationInProgress {} |
This flag indicates if a modification is currently in progress. More... | |
QString | modificationText |
The test message associated with the current modification operation. More... | |
QSet< Node * > | modifiedTargets |
A set of all nodes which might have been modified as part of the last modification operation. More... | |
QString | name_ |
The name of this manager's tree. More... | |
NodeIdMap | nodeIdMap_ |
NodeIdMap | nodeIdMapForUndoStack_ |
We need a separate map for the undo stack in order to support cut and move operations. More... | |
bool | partiallyLoaded_ {} |
Indicates whether this tree has been partially loaded (as a library) from a store. More... | |
bool | performedUndoRedo {} |
Indicates if undo() or redo() were called during the last modification operation. More... | |
bool | pushedNewCommandsOnTheStack {} |
Indicates if the last modification operation pushed commands on stack. More... | |
QSet< Node * > | removedTargets_ |
A set of all nodes which have been removed from the tree as part of the last modification operation. More... | |
QString | revisionName_ |
Can be used to name the revision the manager handles. More... | |
Node * | root_ {} |
The root node for this manager's tree. More... | |
NodeReadWriteLock | rootLock_ |
The lock corresponding to the root access unit. More... | |
PersistentStore * | store_ {} |
The persistent store where the manager's tree is currently stored. More... | |
The TreeManager class is a management and access entity for a program tree.
Each program or project in Envision is represented as a tree of nodes. To manage this tree each project has an associated TreeManager object.
The life cycle of a project begins with the creation of a new TreeManager object. This object can then be populated with program nodes by loading an existing tree from a persistent store or by creating a new tree structure.
Further access and operations on the tree are performed through the TreeManager object. Here is a list of the functionality of a TreeManager:
Model::TreeManager::TreeManager | ( | Node * | root = nullptr | ) |
Constructs a new TreeManager with the given root.
The undo history limit is set to 100 operations.
Model::TreeManager::TreeManager | ( | const QString & | name, |
Node * | root = nullptr |
||
) |
Constructs a new TreeManager with the given name and root.
The undo history limit is set to 100 operations.
|
virtual |
Deletes the root node corresponding to the TreeManager.
Deleting a node normally causes the corresponding subtree to be deleted.
void Model::TreeManager::beginExclusiveRead | ( | ) |
Begins an exclusive read.
During an exclusive read, the tree can not be modified by any other thread. Other readers, including exclusive readers will be allowed to access the tree.
Call TreeManager::endExclusiveRead() to end the exclusive reading block.
void Model::TreeManager::beginModification | ( | Node * | modificationTarget, |
const QString & | text = {} |
||
) |
Begins a modification session.
Before calling a method on a tree node that modifies the node, a writer thread must first begin a modification session. Write access to the underlying tree must always occur in a modification block. Call TreeManager::beginModification() to begin this block and TreeManager::endModification() to end the block:
TreeManager m; ... Node* someNode; ... m.beginModification(someNode, "modification description"); ... Code that makes modification to the subtree rooted at someNode, and within the access unit corresponding ... to someNode m.endModification(); ... Other exclusive readers or other writers can now be granted access
Only one thread can be in a modification session at a time. Furthermore this thread can only modify nodes which fall within the current access unit.
Each node has a unique access unit associated with it. An access unit is simply identified by a lock. The Node::getAccessLock() method can be used to get the access lock associated with a node. By default this is the lock of the parent node, or if there is no parent node (this is the root node), the lock of the TreeManager. The user can reimplement the Node::getAccessLock() method to return a new access lock therby defining a new access unit.
If there is a reader that has requested exclusive access via TreeManager::beginExclusiveRead() this method will block until the reader calls TreeManager::endExclusiveRead()
modificationTarget | the top-most ancestor node of all nodes that will be modified. |
text | the text that will be associated with this modification and put on the undo stack. This parameter has no effect if this modification is used to call undo/redo and not to execute new commands. |
bool Model::TreeManager::canBeModified | ( | const Node * | node | ) | const |
Checks if a node can be modified.
A node can be modified if the following three conditions are met:
This method returns true if all conditions are met and false otherwise.
node | The node to check. |
void Model::TreeManager::changeModificationTarget | ( | Node * | modificationTarget | ) |
Changes the modification target and possibly the access unit that the current writer is allowed to access.
This method can be used within a modification block in order to change the current modification target. This will release the access lock of the current target and acquire the lock of the new target.
modificationTarget | The target that should become the current modification target. The writer thread will be allowed to modify all nodes belonging to the subtree of this target and falling within the same access unit |
ModelException | if this method is called without calling TreeManager::beginModification() first. |
void Model::TreeManager::cleanupDestroyedNode | ( | Node * | node | ) |
void Model::TreeManager::emitNameModified | ( | NameText * | node, |
const QString & | oldName | ||
) |
Causes a nameModified signal to be emitted.
node | The node that represents the name that has changed |
oldName | What was the old name of the node |
void Model::TreeManager::endExclusiveRead | ( | ) |
Ends an exclusive read.
This function must always be called after a call to TreeManager::beginExclusiveRead()
void Model::TreeManager::endModification | ( | bool | tryResolvingReferences = true | ) |
Ends a modification session.
This method must always be called after a call TreeManager::beginModification(). It concludes the modification session by releasing all acquired locks and emits the Mode::nodesModified signal to notify listeners about the changes.
This method must be called before the any other thread can gain exclusive access to the tree.
If tryResolvingReferences is true, then an attempt will be made to resolve all unresolved references.
|
inline |
|
staticprivate |
Returns whether node is transitively owned by cmd.
If node is only owned by excludeCommand this method returns false.
bool Model::TreeManager::isOwnedByUndoStack | ( | const Node * | node, |
const NodeOwningCommand * | excludeCommand | ||
) | const |
Returns whether node is owned by a command in the undo stack.
If node is only owned by excludeCommand this method returns false.
|
inline |
Returns whether this tree has been partially loaded (as a library).
void Model::TreeManager::load | ( | PersistentStore * | store, |
const QString & | name, | ||
bool | loadPartially | ||
) |
Loads the manager's tree from the specified persistent store.
The provided store will become the current store of the manager.
If this manager already has a root node, this method does nothing.
store | The persistent store where the manager's tree should be loaded from. |
name | The tree name in the persistent store. |
loadPartially | Whether the tree should only be partially loaded. The intention is that a partially loaded tree is read only and should only contain the publicly visible part of the tree. Typically this means excluding method bodies from loading. |
|
inline |
|
inline |
Returns the name of the manged tree.
This is the name under which this tree can be found in the persistent store.
|
signal |
Emitted when the name of a node has changed.
This signal can be used to trigger symbolic reference updates, so that references are kept consistent when the name of a symbol changes.
node | The node that has a new name |
oldName | The old name of the node |
|
inline |
|
inline |
|
inline |
|
inline |
|
signal |
Emitted at the end of a modification block.
modifiedNodes | A set of all nodes modified within this block. These nodes might include nodes in removedNodes |
removedNodes | A set of all nodes that have been removed within this block. These nodes might include nodes in modifiedNodes. The set of reported nodes is all nodes that have been removed, including children of removed nodes. |
void Model::TreeManager::notifyNodeChange | ( | Node * | node | ) |
Adds node to the list of modified nodes during an edit operation or immediately emits a nodesModified signal with the specified node if no modification to the tree is ongoing.
For usual edit operations that alter the tree, you do not need to explicitly call this method. It is useful for cases where only a caching property of a node has changed which might lead to changes in its visualization.
For example this method can be used when resolving references to notify visualizations of changes to the reference targets.
void Model::TreeManager::pushCommandOnUndoStack | ( | UndoCommand * | command | ) |
Pushes the specified command on the undo stack and executes it.
This method can only be called inside a modification block initiated with TreeManager::beginModification(). Furthermore no calls to TreeManager::undo or TreeManager::redo can be made in the current modification block.
command | The command to add to the stack. |
ModelException | if called without calling TreeManager::beginModification() first or if calls to TreeManager::undo() or TreeManager::redo() have already been made. |
void Model::TreeManager::redo | ( | ) |
Redoes the commands executed in the next modification block.
ModelException | if called without calling TreeManager::beginModification() first or if a call to TreeManager::pushCommandOnUndoStack() has already been made within this modification block. |
|
inline |
Returns the name of the revision.
|
inline |
Returns the root node for this manager.
|
inline |
Returns the lock corresponding to the top-most (root) access unit.
|
signal |
Emitted when a new root node was set.
root | A pointer to the new root node |
void Model::TreeManager::save | ( | PersistentStore * | store = nullptr | ) |
Saves the tree in persistent store of the tree manager.
If this manager does not have a current store, the store argument must not be NULL. In that case the provided store will become the current store of the manager.
store | The persistent store where the tree should be saved. If this is NULL the current store will be used. The current store is the one from which the tree was loaded. If this is not NULL it will be used instead of the current store. |
|
inline |
Sets the name of the tree.
This is the name under which this tree will be save in the persistent store.
|
inline |
Sets the name of the revision.
void Model::TreeManager::setRoot | ( | Node * | node | ) |
Sets the root node of this manager to node.
The TreeManager should not have a root node set. This method must be called outside of a modification block. This action can not be undone.
|
inline |
Returns the current store for this manager.
The current store is the store used to load the manager's tree. If the tree was created rather than loaded and has not been saved to a persistent store yet this method will return NULL.
void Model::TreeManager::undo | ( | ) |
Undoes the commands executed in the previous modification block.
ModelException | if called without calling Model::beginModification() first or if a call to Model::pushCommandOnUndoStack() has already been made within this modification block. |
|
private |
The command stack that holds the undo history.
|
private |
The lock of the access unit that is responsible for the current modification target node.
Each node has exactly one access unit corresponding to it. A writer must acquire this lock before any modification can occur. The currently acquired lock is stored here so that each write operation can be checked to assure that no write occurs outside of the access unit.
|
private |
The node that is the top-most ancestor of all other nodes that are currently being modification.
Only nodes in the same access unit and below this node (including the node itself) may be modified.
|
private |
A ReadWrite lock used for exclusive writer or reader access.
Writers always acquire this lock first and then proceed to acquire exactly one other lock corresponding to the access unit they want to write to.
A reader that requires exclusive access (other readers can still read, but writers can not) can also acquire this lock. Typically however readers do not acquire this lock.
|
private |
This flag indicates if a modification is currently in progress.
Commands can be pushed on the undo stack and executed only if this is true.
|
private |
The test message associated with the current modification operation.
This text is only used to describe the undo operation that is currently performed.
|
private |
A set of all nodes which might have been modified as part of the last modification operation.
This is only used to signal to anyone who is interested in monitoring changes.
|
private |
The name of this manager's tree.
This name will be used to save the tree in the persistent store.
|
private |
|
private |
We need a separate map for the undo stack in order to support cut and move operations.
|
private |
Indicates whether this tree has been partially loaded (as a library) from a store.
|
private |
|
private |
Indicates if the last modification operation pushed commands on stack.
A modification operation can do two things:
The two can not be mixed in the same operation and this flag is used to control this.
|
private |
A set of all nodes which have been removed from the tree as part of the last modification operation.
This is only used to signal to anyone who is interested in monitoring changes.
|
private |
Can be used to name the revision the manager handles.
This name will be used in the diff to differentiate between the old and new version managers;
|
private |
The root node for this manager's tree.
|
private |
The lock corresponding to the root access unit.
This is used by synchronized readers and by writers to control access to the root unit.
|
private |
The persistent store where the manager's tree is currently stored.
This is used in calls to Node::loadFully when a partially loaded node needs to load its entire contents. It can also be used by other stores when the tree needs to be saved to a different location.