Envision
A visual programming IDE for object-oriented languages
List of all members | Signals | Public Member Functions | Static Private Member Functions | Private Attributes
Model::TreeManager Class Reference

The TreeManager class is a management and access entity for a program tree. More...

Inheritance diagram for Model::TreeManager:

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...
 
NodemodificationTarget () const
 
QString name ()
 Returns the name of the manged tree. More...
 
NodeIdMapnodeIdMap ()
 
const NodeIdMapnodeIdMap () const
 
NodeIdMapnodeIdMapForUndoStack ()
 
const NodeIdMapnodeIdMapForUndoStack () 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...
 
Noderoot ()
 Returns the root node for this manager. More...
 
NodeReadWriteLockrootLock ()
 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...
 
PersistentStorestore ()
 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...
 
NodeReadWriteLockcurrentModificationLock {}
 The lock of the access unit that is responsible for the current modification target node. More...
 
NodecurrentModificationTarget {}
 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...
 
Noderoot_ {}
 The root node for this manager's tree. More...
 
NodeReadWriteLock rootLock_
 The lock corresponding to the root access unit. More...
 
PersistentStorestore_ {}
 The persistent store where the manager's tree is currently stored. More...
 

Detailed Description

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:

Constructor & Destructor Documentation

◆ TreeManager() [1/2]

Model::TreeManager::TreeManager ( Node root = nullptr)

Constructs a new TreeManager with the given root.

The undo history limit is set to 100 operations.

◆ TreeManager() [2/2]

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.

◆ ~TreeManager()

Model::TreeManager::~TreeManager ( )
virtual

Deletes the root node corresponding to the TreeManager.

Deleting a node normally causes the corresponding subtree to be deleted.

Member Function Documentation

◆ beginExclusiveRead()

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.

◆ beginModification()

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()

Parameters
modificationTargetthe top-most ancestor node of all nodes that will be modified.
textthe 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.

◆ canBeModified()

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:

  • The manager is in a modification session, started with TreeManager::beginModification().
  • It is, or has as a parent, the current modification target.
  • It belongs to the same access unit as the current modification target.

This method returns true if all conditions are met and false otherwise.

Parameters
nodeThe node to check.

◆ changeModificationTarget()

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.

Parameters
modificationTargetThe 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
Exceptions
ModelExceptionif this method is called without calling TreeManager::beginModification() first.

◆ cleanupDestroyedNode()

void Model::TreeManager::cleanupDestroyedNode ( Node node)

◆ emitNameModified()

void Model::TreeManager::emitNameModified ( NameText node,
const QString &  oldName 
)

Causes a nameModified signal to be emitted.

Parameters
nodeThe node that represents the name that has changed
oldNameWhat was the old name of the node

◆ endExclusiveRead()

void Model::TreeManager::endExclusiveRead ( )

Ends an exclusive read.

This function must always be called after a call to TreeManager::beginExclusiveRead()

◆ endModification()

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.

◆ isBeingModified()

bool Model::TreeManager::isBeingModified ( ) const
inline

◆ isOwnedByCommand()

bool Model::TreeManager::isOwnedByCommand ( const Node node,
const UndoCommand cmd,
const NodeOwningCommand excludeCommand 
)
staticprivate

Returns whether node is transitively owned by cmd.

If node is only owned by excludeCommand this method returns false.

◆ isOwnedByUndoStack()

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.

◆ isPartiallyLoaded()

bool Model::TreeManager::isPartiallyLoaded ( ) const
inline

Returns whether this tree has been partially loaded (as a library).

◆ load()

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.

Parameters
storeThe persistent store where the manager's tree should be loaded from.
nameThe tree name in the persistent store.
loadPartiallyWhether 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.

◆ modificationTarget()

Node * Model::TreeManager::modificationTarget ( ) const
inline

◆ name()

QString Model::TreeManager::name ( )
inline

Returns the name of the manged tree.

This is the name under which this tree can be found in the persistent store.

◆ nameModified

void Model::TreeManager::nameModified ( Node node,
const QString &  oldName 
)
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.

Parameters
nodeThe node that has a new name
oldNameThe old name of the node

◆ nodeIdMap() [1/2]

NodeIdMap & Model::TreeManager::nodeIdMap ( )
inline

◆ nodeIdMap() [2/2]

const NodeIdMap & Model::TreeManager::nodeIdMap ( ) const
inline

◆ nodeIdMapForUndoStack() [1/2]

NodeIdMap & Model::TreeManager::nodeIdMapForUndoStack ( )
inline

◆ nodeIdMapForUndoStack() [2/2]

const NodeIdMap & Model::TreeManager::nodeIdMapForUndoStack ( ) const
inline

◆ nodesModified

void Model::TreeManager::nodesModified ( QSet< Node * >  modifiedNodes,
QSet< Node * >  removedNodes 
)
signal

Emitted at the end of a modification block.

Parameters
modifiedNodesA set of all nodes modified within this block. These nodes might include nodes in removedNodes
removedNodesA 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.

◆ notifyNodeChange()

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.

◆ pushCommandOnUndoStack()

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.

Parameters
commandThe command to add to the stack.
Exceptions
ModelExceptionif called without calling TreeManager::beginModification() first or if calls to TreeManager::undo() or TreeManager::redo() have already been made.

◆ redo()

void Model::TreeManager::redo ( )

Redoes the commands executed in the next modification block.

Exceptions
ModelExceptionif called without calling TreeManager::beginModification() first or if a call to TreeManager::pushCommandOnUndoStack() has already been made within this modification block.

◆ revisionName()

QString Model::TreeManager::revisionName ( )
inline

Returns the name of the revision.

◆ root()

Node * Model::TreeManager::root ( )
inline

Returns the root node for this manager.

◆ rootLock()

NodeReadWriteLock * Model::TreeManager::rootLock ( )
inline

Returns the lock corresponding to the top-most (root) access unit.

◆ rootNodeSet

void Model::TreeManager::rootNodeSet ( Node root)
signal

Emitted when a new root node was set.

Parameters
rootA pointer to the new root node

◆ save()

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.

Parameters
storeThe 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.

◆ setName()

void Model::TreeManager::setName ( const QString &  name)
inline

Sets the name of the tree.

This is the name under which this tree will be save in the persistent store.

◆ setRevisionName()

void Model::TreeManager::setRevisionName ( const QString &  revisionName)
inline

Sets the name of the revision.

◆ setRoot()

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.

◆ store()

PersistentStore * Model::TreeManager::store ( )
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.

◆ undo()

void Model::TreeManager::undo ( )

Undoes the commands executed in the previous modification block.

Exceptions
ModelExceptionif called without calling Model::beginModification() first or if a call to Model::pushCommandOnUndoStack() has already been made within this modification block.

Member Data Documentation

◆ commands

QUndoStack Model::TreeManager::commands
private

The command stack that holds the undo history.

◆ currentModificationLock

NodeReadWriteLock* Model::TreeManager::currentModificationLock {}
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.

◆ currentModificationTarget

Node* Model::TreeManager::currentModificationTarget {}
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.

◆ exclusiveAccess

QReadWriteLock Model::TreeManager::exclusiveAccess
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.

◆ modificationInProgress

bool Model::TreeManager::modificationInProgress {}
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.

◆ modificationText

QString Model::TreeManager::modificationText
private

The test message associated with the current modification operation.

This text is only used to describe the undo operation that is currently performed.

◆ modifiedTargets

QSet<Node*> Model::TreeManager::modifiedTargets
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.

◆ name_

QString Model::TreeManager::name_
private

The name of this manager's tree.

This name will be used to save the tree in the persistent store.

◆ nodeIdMap_

NodeIdMap Model::TreeManager::nodeIdMap_
private

◆ nodeIdMapForUndoStack_

NodeIdMap Model::TreeManager::nodeIdMapForUndoStack_
private

We need a separate map for the undo stack in order to support cut and move operations.

◆ partiallyLoaded_

bool Model::TreeManager::partiallyLoaded_ {}
private

Indicates whether this tree has been partially loaded (as a library) from a store.

◆ performedUndoRedo

bool Model::TreeManager::performedUndoRedo {}
private

Indicates if undo() or redo() were called during the last modification operation.

A modification operation can do two things:

  • Add new commands on the stack
  • Call undo/redo

The two can not be mixed in the same operation and this flag is used to control this.

◆ pushedNewCommandsOnTheStack

bool Model::TreeManager::pushedNewCommandsOnTheStack {}
private

Indicates if the last modification operation pushed commands on stack.

A modification operation can do two things:

  • Add new commands on the stack
  • Call undo/redo

The two can not be mixed in the same operation and this flag is used to control this.

◆ removedTargets_

QSet<Node*> Model::TreeManager::removedTargets_
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.

◆ revisionName_

QString Model::TreeManager::revisionName_
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;

◆ root_

Node* Model::TreeManager::root_ {}
private

The root node for this manager's tree.

◆ rootLock_

NodeReadWriteLock Model::TreeManager::rootLock_
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.

◆ store_

PersistentStore* Model::TreeManager::store_ {}
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.