Envision
A visual programming IDE for object-oriented languages
List of all members | Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | Static Private Attributes
Model::Node Class Referenceabstract

The Node class is the foundation element in the tree in Envision. More...

Public Types

enum  FindSymbolDirection { SEARCH_HERE , SEARCH_DOWN , SEARCH_UP , SEARCH_UP_ORDERED }
 
using NodeConstructor = Node *(*)(Node *parent)
 This function pointer type is used to register a constructor for nodes. More...
 
using NodePersistenceConstructor = Node *(*)(Node *parent, PersistentStore &store, bool partialLoadHint)
 This function pointer type is used to register the constructor for nodes that are being loaded from a persistent store. More...
 
enum  SymbolType { UNSPECIFIED = 0x0 , METHOD = 0x1 , CONTAINER = 0x2 , VARIABLE = 0x4 , ANY_SYMBOL = 0xffffffff }
 
using SymbolTypes = QFlags< SymbolType >
 

Public Member Functions

 Node (const Node &other)
 Copy constructor. More...
 
 Node (Node *parent=nullptr)
 Constructs a new node with the specified parent. More...
 
virtual ~Node ()
 
virtual NodeReadWriteLockaccessLock () const
 Returns the lock used to control access to this node. More...
 
void addToRevision (int valueToAdd)
 Increments the revision of this node by the specified amount. More...
 
void beginModification (const QString &text={})
 Begins a modification session with the current node as a modification target. More...
 
virtual QList< Node * > children () const
 Returns a list of all child nodes. More...
 
virtual QList< Node * > childrenInScope () const
 Returns all child nodes that may define symbols that form the scope of this node. More...
 
NodechildToSubnode (const Node *other) const
 Returns the direct child node that is equal to other or is an ancestor of other. More...
 
virtual Nodeclone () const =0
 
virtual bool definesSymbol () const
 Returns true if this node defines a symbol and false otherwise. More...
 
void endModification ()
 Ends a modification session. More...
 
void execute (UndoCommand *command)
 Executes the specified command and pushes it on the undo stack. More...
 
virtual bool findSymbols (std::unique_ptr< ResolutionRequest > request) const
 Performs a search for a symbol according to the given request and returns whether a symbol was found. More...
 
template<typename NodeType >
NodeType * firstAncestorOfType ()
 Returns the first Ancestor which has the type NodeType if there is one, otherwise null. More...
 
NodefirstAncestorOfType (const SymbolMatcher &typeMatch) const
 Returns the first Ancestor for which typeName() matches with typeMatch, if there is one, otherwise null. More...
 
bool hasPartiallyLoadedChildren () const
 Returns true if this node is partially loaded or has partially loaded children. More...
 
void incrementRevision ()
 Increments the revision of this node by 1. More...
 
bool isAncestorOf (const Node *other) const
 Returns true of this node is an Ancestor of other and false otherwise. More...
 
bool isModifyable () const
 Returns true is the this node can be modified or false otherwise. More...
 
virtual bool isNewPersistenceUnit () const
 Returns true if this node should be persisted in a new persistence unit. More...
 
bool isPartiallyLoaded () const
 Returns true if this node is only partially loaded. More...
 
bool isSameOrAncestorOf (const Node *other) const
 
virtual bool isTransparentForNameResolution () const
 Returns true if this node should propagate name resolution requests through it, as if were not there. More...
 
virtual void load (PersistentStore &store)=0
 Reloads this node from a persistent store. More...
 
NodelowestCommonAncestor (Node *other, Node **thisParent=nullptr, Node **otherParent=nullptr)
 Returns the lowest common ancestor of this node and other. More...
 
TreeManagermanager () const
 Returns the tree manager of the current Node. More...
 
Nodeparent () const
 Returns the parent of this Node or NULL if this is the root. More...
 
NodepersistentUnitNode () const
 Returns the node that defines the persistence unit for this node. More...
 
virtual bool replaceChild (Node *child, Node *replacement)
 Replaces the child item child with the item replacement and returns true on success. More...
 
int revision () const
 Returns the revision of this node. More...
 
Noderoot () const
 Returns the root node of tree where of this node. More...
 
virtual void save (PersistentStore &store) const =0
 Saves the current node to a persistent store. More...
 
void setParent (Node *parent)
 Sets the parent of this Node. More...
 
void setRootManager (TreeManager *manager)
 Sets the manager of this root node to manager. More...
 
bool symbolMatches (const SymbolMatcher &matcher, SymbolTypes symbolTypes) const
 Returns true if this node defines a symbol that has a name matching matcher and types common with symbolTypes. More...
 
virtual const QString & symbolName () const
 Returns the name of the symbol defined by this node. More...
 
virtual SymbolTypes symbolType () const
 Returns the type of the symbol defined by this node. More...
 
QString toDebugString ()
 Converts this node to a string for use in debug purposes only. More...
 
virtual QList< const UsedLibrary * > usedLibraries () const
 Returns a list of all libraries that are used by this node and its subnodes. More...
 

Static Public Member Functions

template<typename NodeType >
static QList< NodeType * > childrenOfType (Node *from)
 Returns all children including the node from, which have type NodeType. More...
 
template<typename Predicate >
static QList< Node * > childrenWhich (Node *from, Predicate p, bool onlyTopLevel=false)
 Returns all children including the node from, which fullfill the Predicate p, i.e. More...
 
static NodecreateDefaultInstance (Node *parent)
 As Node is an abstract class this method always returns nullptr. More...
 
static NodecreateNewNode (const QString &type, Node *parent, PersistentStore &store, bool partialLoadHint)
 Creates a new node of the specified type by loading it from a persistent store. More...
 
static NodecreateNewNode (const QString &type, Node *parent=nullptr)
 Creates a new node of the specified type. More...
 
static bool isTypeRegistered (const QString &type)
 Returns true if there are already registered constructs for a type with the specified name and false otherwise. More...
 
static void registerNodeType (const QString &type, const NodeConstructor constructor, const NodePersistenceConstructor persistenceconstructor)
 Registers the constructors of a class derived from Node. More...
 

Protected Member Functions

void setPartiallyLoaded ()
 

Private Member Functions

void propagateManagerToChildren ()
 

Static Private Member Functions

static QSet< const Node * > & partiallyLoadedNodes ()
 

Private Attributes

TreeManagermanager_ {}
 
Nodeparent_ {}
 
int revision_ {}
 

Static Private Attributes

static QHash< QString, NodeConstructornodeConstructorRegister
 
static QHash< QString, NodePersistenceConstructornodePersistenceConstructorRegister
 

Detailed Description

The Node class is the foundation element in the tree in Envision.

An application in Envision is a collection of objects of type Node (and derived) that are managed by a single TreeManager object. Nodes are combined together in a tree structure. This class defines the minimal interface of each node and implements some service functions.

Each class that derives from Node must have at least two constructors which need to be registered before that class can be used. This is achieved using the static method 'registerNodeType()'.

Derived classes must implement the 'save()' and 'load()' methods that specify how the node is stored in a persistent store.

A new class that derives from Node must define many standard methods and constructors. Many macros have been defined that greatly simplify this task. See 'nodeMacros.h' for more details.

A node in the tree has a revision number. Each time a node is created or loaded from a persistent store this number is reset to 0. Any modification to the node causes the revision to be incremented. This can be then used by visualizations or other plug-ins to track the evolution of node and update it necessary. A node's revision number will also increase when any of its descendants is modified, added or removed.

A node that supports partial loading, should reimplement the 'loadFully()' method to enable this functionality.

The functionality offered by the Node class includes:

Member Typedef Documentation

◆ NodeConstructor

This function pointer type is used to register a constructor for nodes.

Parameters
parentThe parent node of the newly created node. This may be 'nullptr'.

◆ NodePersistenceConstructor

using Model::Node::NodePersistenceConstructor = Node* (*)(Node* parent, PersistentStore& store, bool partialLoadHint)

This function pointer type is used to register the constructor for nodes that are being loaded from a persistent store.

Parameters
parentThe parent node of the newly created node. This can be NULL to indicate that this node is the root node for the TreeManager. Otherwise it should be non-NULL.
idThe id of the node from the persistent store.
storeThe store that is contains this node and its subtree. This will be used to load the children of the node.
partialLoadHintA flag that hints whether this node should be fully or partially loaded. The constructor of the node is allowed to ignore this flag.

◆ SymbolTypes

Member Enumeration Documentation

◆ FindSymbolDirection

Enumerator
SEARCH_HERE 

Looks for symbols defined by the current node.

This happens when findSymbols has been called on the parent with SEARCH_DOWN and the parent must therefore find a precise match in its scope. findSymbols() will be called for each potential match from the parents children with the SEACH_HERE flag

SEARCH_DOWN 

Looks for symbols inside the specified scope or subscopes.

This is used for symbols that are requested in a specific context (typically after a '.') e.g. "list.sort()"

SEARCH_UP 

Looks for symbols within the specified scope and enclosing scopes.

Unless explicitly overriden, this mode assumes no ordering of the children within the scope and will searc within all children except for the source child. Some scopes override this behavior and only search for symbols that come before the source child. This is the case e.g. with searches for local variable declarations in a method: only variables before the source node should be considered.

SEARCH_UP_ORDERED 

This is similar to SEARCH_UP but enforces that the search within the immediate scope is ordered.

While a particular scope node (typically a list type) can choose how to perform a SEARCH_UP operation, any scope (list) should respect SEARCH_UP_ORDERED and do an ordered search requested from a child element. This is useful for example in case where a list contains both ordered and unordered elements, e.g. a list of declarations, where classes are unordered but type aliases or name imports are ordered.

◆ SymbolType

Enumerator
UNSPECIFIED 

The default type of a node.

METHOD 

Used for nodes which define methods.

CONTAINER 

Used for nodes which contain other symbol defining nodes, accessible by '.

' .

VARIABLE 

Used for global, local variables, arguments and fields.

ANY_SYMBOL 

Constructor & Destructor Documentation

◆ Node() [1/2]

Model::Node::Node ( Node parent = nullptr)

Constructs a new node with the specified parent.

Parameters
parentThe parent of this node. This may be 'nullptr'.

If the parent is not null, then the manager associated with the parent will also be the manager for this node. If the parent is nullptr, then this node will not be associated with a manager initially. It can later be added to an existing manager.

◆ Node() [2/2]

Model::Node::Node ( const Node other)

Copy constructor.

Note that other is ignored and a copy will have no parent or manager and will have a revision of 0.

◆ ~Node()

Model::Node::~Node ( )
virtual

Member Function Documentation

◆ accessLock()

NodeReadWriteLock * Model::Node::accessLock ( ) const
virtual

Returns the lock used to control access to this node.

If a node should represent a new access unit, this method should be overriden to return a lock associated with the node.

The default implementation just asks for the lock of the parent, or if the parent is NULL for the root lock of the manager.

◆ addToRevision()

void Model::Node::addToRevision ( int  valueToAdd)

Increments the revision of this node by the specified amount.

◆ beginModification()

void Model::Node::beginModification ( const QString &  text = {})

Begins a modification session with the current node as a modification target.

text is the description that will be associated with this modification.

See also
Model::beginModification()

◆ children()

QList< Node * > Model::Node::children ( ) const
virtual

Returns a list of all child nodes.

Reimplement this method in derived classes that have children. The default implementation returns an empty list.

◆ childrenInScope()

QList< Node * > Model::Node::childrenInScope ( ) const
virtual

Returns all child nodes that may define symbols that form the scope of this node.

The default implementation returns all direct children of this node.

Reimplement this method to customize while nodes form the scope of this node.

◆ childrenOfType()

template<typename NodeType >
QList< NodeType * > Model::Node::childrenOfType ( Node from)
inlinestatic

Returns all children including the node from, which have type NodeType.

◆ childrenWhich()

template<typename Predicate >
QList< Node * > Model::Node::childrenWhich ( Node from,
Predicate  p,
bool  onlyTopLevel = false 
)
inlinestatic

Returns all children including the node from, which fullfill the Predicate p, i.e.

p(node) returns true.

If onlyTopLevel is set only the first matches are returned

◆ childToSubnode()

Node * Model::Node::childToSubnode ( const Node other) const

Returns the direct child node that is equal to other or is an ancestor of other.

Returns null if this node is not an ancestor of other.

◆ clone()

virtual Node* Model::Node::clone ( ) const
pure virtual

◆ createDefaultInstance()

Node * Model::Node::createDefaultInstance ( Node parent)
static

As Node is an abstract class this method always returns nullptr.

◆ createNewNode() [1/2]

Node * Model::Node::createNewNode ( const QString &  type,
Node parent,
PersistentStore store,
bool  partialLoadHint 
)
static

Creates a new node of the specified type by loading it from a persistent store.

Parameters
typeThe type of the node to create. This must be a type that has been registered before by calling registerNodeType.
parentThe parent of the node. This can be NULL if this is the root node.
storeThe persistent store to use to load the subtree of this node.
partialLoadHintWhether this node should only be partially loaded. This is only a hint and a node implementation can ignore this flag.

◆ createNewNode() [2/2]

Node * Model::Node::createNewNode ( const QString &  type,
Node parent = nullptr 
)
static

Creates a new node of the specified type.

Parameters
typeThe type of the node to create. This must be a type that has been registered before by calling registerNodeType.
parentThe parent of the node. This may be 'nullptr'.

◆ definesSymbol()

bool Model::Node::definesSymbol ( ) const
virtual

Returns true if this node defines a symbol and false otherwise.

The default implementaion returns false. Reimplement this method, symbolName(), and symbolType() in derived classes that define symbols.

◆ endModification()

void Model::Node::endModification ( )

Ends a modification session.

See also
Model::endModification()

◆ execute()

void Model::Node::execute ( UndoCommand command)

Executes the specified command and pushes it on the undo stack.

This method will fail with an exception if the current thread does not hold the lock for this node's access unit.

This method also increments the revision of the node by 1.

◆ findSymbols()

bool Model::Node::findSymbols ( std::unique_ptr< ResolutionRequest request) const
virtual

Performs a search for a symbol according to the given request and returns whether a symbol was found.

The symbols which were found are inserted in the set refernced by the result of the request.

The default implementation returns a set with only the current node in it, in case the node defines the requested symbol. Otherwise if mode is FindSymbolMode::SEARCH_UP, the implementation of the parent node is called.

Reimplement this method in derived classes to specify fine grained behavior and operation for search modes other than FindSymbolMode::SEARCH_UP

◆ firstAncestorOfType() [1/2]

template<typename NodeType >
NodeType * Model::Node::firstAncestorOfType
inline

Returns the first Ancestor which has the type NodeType if there is one, otherwise null.

◆ firstAncestorOfType() [2/2]

Node * Model::Node::firstAncestorOfType ( const SymbolMatcher typeMatch) const

Returns the first Ancestor for which typeName() matches with typeMatch, if there is one, otherwise null.

◆ hasPartiallyLoadedChildren()

bool Model::Node::hasPartiallyLoadedChildren ( ) const

Returns true if this node is partially loaded or has partially loaded children.

◆ incrementRevision()

void Model::Node::incrementRevision ( )

Increments the revision of this node by 1.

◆ isAncestorOf()

bool Model::Node::isAncestorOf ( const Node other) const

Returns true of this node is an Ancestor of other and false otherwise.

◆ isModifyable()

bool Model::Node::isModifyable ( ) const

Returns true is the this node can be modified or false otherwise.

A node is modifiable if it is part of an access unit which is currently acquired by a writer thread. This is managed by the TreeManager associated with the node.

If a node does not have an associated manager it is always modifiable.

◆ isNewPersistenceUnit()

bool Model::Node::isNewPersistenceUnit ( ) const
virtual

Returns true if this node should be persisted in a new persistence unit.

This is typically a per class value.

When the user saves the project normally the entire corresponding application tree is saved. To optimize the amount of data written to disk, it is possible to indicate new persistence units. Whenever a node in the application is modified only the persistent unit it belongs to, together with all persistence units of its parents are saved.

For example, to simulate the typical scenario of saving classes in different files, a node which represents a class should return true as the result of this method.

NOTE: The persistence engine will save the ID and last revision of all objects that which are marked as a new persistence unit. Therefore this option should be used with care. Only node types closer to the root are suitable for being new persistence units. Nodes closer to the leafs, such as expressions and text values should not be new persistence units, as this will greatly increase the memory required by the persistence engine.

TODO In the comment above the part that explains things about the revision is incorrect. The persistence store does not care about this currently. Either change the comment or fix this.

◆ isPartiallyLoaded()

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

Returns true if this node is only partially loaded.

In order for this method to work as expected, the constructors of nodes which are only partially loaded should call the setPartiallyLoaded() method.

◆ isSameOrAncestorOf()

bool Model::Node::isSameOrAncestorOf ( const Node other) const

◆ isTransparentForNameResolution()

bool Model::Node::isTransparentForNameResolution ( ) const
virtual

Returns true if this node should propagate name resolution requests through it, as if were not there.

The default implementaion returns false. Reimplement this method in sub classes that are not part of name resolution, but are involved in the process (e.g. lists or projects). By default, a non-transparent object will prevent name resolution from propagating past it, if it does not match the name being searched for.

◆ isTypeRegistered()

bool Model::Node::isTypeRegistered ( const QString &  type)
static

Returns true if there are already registered constructs for a type with the specified name and false otherwise.

◆ load()

virtual void Model::Node::load ( PersistentStore store)
pure virtual

Reloads this node from a persistent store.

This method is called at any point after this node has been created in order to reinitialize its contents from the persistent store. Any existing subtree should be gracefully detached. This means that subtrees should not be deleted, but simply detached from the current node in a reversible way using commands that can be undone.

◆ lowestCommonAncestor()

Node * Model::Node::lowestCommonAncestor ( Node other,
Node **  thisParent = nullptr,
Node **  otherParent = nullptr 
)

Returns the lowest common ancestor of this node and other.

If thisParent and otherParent are provided, they will be set to the last ancestors of this and other which are different from each other and have the common ancestor as parent. If there is no common parent, these will be set to the roots of the corresponding trees. If this == other, thisParent and otherParent are set to nullptr.

◆ manager()

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

Returns the tree manager of the current Node.

Calling this method during the creation of the root Node will return a nullptr.

◆ parent()

Node * Model::Node::parent ( ) const
inline

Returns the parent of this Node or NULL if this is the root.

◆ partiallyLoadedNodes()

QSet< const Node * > & Model::Node::partiallyLoadedNodes ( )
staticprivate

◆ persistentUnitNode()

Node * Model::Node::persistentUnitNode ( ) const

Returns the node that defines the persistence unit for this node.

◆ propagateManagerToChildren()

void Model::Node::propagateManagerToChildren ( )
private

◆ registerNodeType()

void Model::Node::registerNodeType ( const QString &  type,
const NodeConstructor  constructor,
const NodePersistenceConstructor  persistenceconstructor 
)
static

Registers the constructors of a class derived from Node.

Each class derived from Node must be registered before it can be used.

Parameters
typeThe string name of the class.
constructorA function that can construct a new instance of the class at run-time.
persistenceconstructorA function that can construct a new instance of the class from a persistent store.

◆ replaceChild()

bool Model::Node::replaceChild ( Node child,
Node replacement 
)
virtual

Replaces the child item child with the item replacement and returns true on success.

The default implementation always returns false and is suitable for nodes without children. Reimplement this method if you are implementing a composite node that has replaceable child nodes.

◆ revision()

int Model::Node::revision ( ) const

Returns the revision of this node.

◆ root()

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

Returns the root node of tree where of this node.

◆ save()

virtual void Model::Node::save ( PersistentStore store) const
pure virtual

Saves the current node to a persistent store.

This method should contain calls to the store object that persist the subtree of this node.

Parameters
storeThe persistent store to use

◆ setParent()

void Model::Node::setParent ( Node parent)

Sets the parent of this Node.

◆ setPartiallyLoaded()

void Model::Node::setPartiallyLoaded ( )
inlineprotected

◆ setRootManager()

void Model::Node::setRootManager ( TreeManager manager)

Sets the manager of this root node to manager.

This node must not have a parent.

◆ symbolMatches()

bool Model::Node::symbolMatches ( const SymbolMatcher matcher,
SymbolTypes  symbolTypes 
) const
inline

Returns true if this node defines a symbol that has a name matching matcher and types common with symbolTypes.

◆ symbolName()

const QString & Model::Node::symbolName ( ) const
virtual

Returns the name of the symbol defined by this node.

The default implementaion returns a null QString value. Reimplement this method, definesSymbol(), and symbolType() in derived classes that define symbols.

◆ symbolType()

Node::SymbolTypes Model::Node::symbolType ( ) const
virtual

Returns the type of the symbol defined by this node.

The default implementaion returns UNSPECIFIED. Reimplement this method, symbolName(), and definesSymbol() in derived classes that define symbols.

◆ toDebugString()

QString Model::Node::toDebugString ( )

Converts this node to a string for use in debug purposes only.

This method uses the adapter framework and tries to convert this node to a QString.

◆ usedLibraries()

QList< const UsedLibrary * > Model::Node::usedLibraries ( ) const
virtual

Returns a list of all libraries that are used by this node and its subnodes.

This method should be called on root nodes, as once a node specifies a used library, its children no longer need to specify it.

The default implementation simply recursively calls the same method for all children and returns a combined list. This implementation is sufficient for correct operation, but derived classes can nevertheless override this method in order to prune the search tree.

Member Data Documentation

◆ manager_

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

◆ nodeConstructorRegister

QHash< QString, Node::NodeConstructor > Model::Node::nodeConstructorRegister
staticprivate

◆ nodePersistenceConstructorRegister

QHash< QString, Node::NodePersistenceConstructor > Model::Node::nodePersistenceConstructorRegister
staticprivate

◆ parent_

Node* Model::Node::parent_ {}
private

◆ revision_

int Model::Node::revision_ {}
private