Envision
A visual programming IDE for object-oriented languages
|
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 NodeReadWriteLock * | accessLock () 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... | |
Node * | childToSubnode (const Node *other) const |
Returns the direct child node that is equal to other or is an ancestor of other. More... | |
virtual Node * | clone () 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... | |
Node * | firstAncestorOfType (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... | |
Node * | lowestCommonAncestor (Node *other, Node **thisParent=nullptr, Node **otherParent=nullptr) |
Returns the lowest common ancestor of this node and other. More... | |
TreeManager * | manager () const |
Returns the tree manager of the current Node. More... | |
Node * | parent () const |
Returns the parent of this Node or NULL if this is the root. More... | |
Node * | persistentUnitNode () 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... | |
Node * | root () 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 Node * | createDefaultInstance (Node *parent) |
As Node is an abstract class this method always returns nullptr. More... | |
static Node * | createNewNode (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 Node * | createNewNode (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 | |
TreeManager * | manager_ {} |
Node * | parent_ {} |
int | revision_ {} |
Static Private Attributes | |
static QHash< QString, NodeConstructor > | nodeConstructorRegister |
static QHash< QString, NodePersistenceConstructor > | nodePersistenceConstructorRegister |
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:
using Model::Node::NodeConstructor = Node* (*)(Node* parent) |
This function pointer type is used to register a constructor for nodes.
parent | The parent node of the newly created node. This may be 'nullptr'. |
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.
parent | The 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. |
id | The id of the node from the persistent store. |
store | The store that is contains this node and its subtree. This will be used to load the children of the node. |
partialLoadHint | A flag that hints whether this node should be fully or partially loaded. The constructor of the node is allowed to ignore this flag. |
using Model::Node::SymbolTypes = QFlags<SymbolType> |
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. |
Model::Node::Node | ( | Node * | parent = nullptr | ) |
Constructs a new node with the specified parent.
parent | The 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.
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.
|
virtual |
|
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.
void Model::Node::addToRevision | ( | int | valueToAdd | ) |
Increments the revision of this node by the specified amount.
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.
|
virtual |
Returns a list of all child nodes.
Reimplement this method in derived classes that have children. The default implementation returns an empty list.
|
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.
|
inlinestatic |
Returns all children including the node from, which have type NodeType.
|
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
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.
|
pure virtual |
As Node is an abstract class this method always returns nullptr.
|
static |
Creates a new node of the specified type by loading it from a persistent store.
type | The type of the node to create. This must be a type that has been registered before by calling registerNodeType. |
parent | The parent of the node. This can be NULL if this is the root node. |
store | The persistent store to use to load the subtree of this node. |
partialLoadHint | Whether this node should only be partially loaded. This is only a hint and a node implementation can ignore this flag. |
Creates a new node of the specified type.
type | The type of the node to create. This must be a type that has been registered before by calling registerNodeType. |
parent | The parent of the node. This may be 'nullptr'. |
|
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.
void Model::Node::endModification | ( | ) |
Ends a modification session.
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.
|
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
|
inline |
Returns the first Ancestor which has the type NodeType if there is one, otherwise null.
Node * Model::Node::firstAncestorOfType | ( | const SymbolMatcher & | typeMatch | ) | const |
Returns the first Ancestor for which typeName() matches with typeMatch, if there is one, otherwise null.
bool Model::Node::hasPartiallyLoadedChildren | ( | ) | const |
Returns true if this node is partially loaded or has partially loaded children.
void Model::Node::incrementRevision | ( | ) |
Increments the revision of this node by 1.
bool Model::Node::isAncestorOf | ( | const Node * | other | ) | const |
Returns true of this node is an Ancestor of other and false otherwise.
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.
|
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.
|
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.
bool Model::Node::isSameOrAncestorOf | ( | const Node * | other | ) | 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.
|
static |
Returns true if there are already registered constructs for a type with the specified name and false otherwise.
|
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.
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.
|
inline |
|
inline |
Returns the parent of this Node or NULL if this is the root.
|
staticprivate |
Node * Model::Node::persistentUnitNode | ( | ) | const |
Returns the node that defines the persistence unit for this node.
|
private |
|
static |
Registers the constructors of a class derived from Node.
Each class derived from Node must be registered before it can be used.
type | The string name of the class. |
constructor | A function that can construct a new instance of the class at run-time. |
persistenceconstructor | A function that can construct a new instance of the class from a persistent store. |
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.
int Model::Node::revision | ( | ) | const |
Returns the revision of this node.
|
inline |
Returns the root node of tree where of this node.
|
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.
store | The persistent store to use |
|
inlineprotected |
void Model::Node::setRootManager | ( | TreeManager * | manager | ) |
Sets the manager of this root node to manager.
This node must not have a parent.
|
inline |
Returns true if this node defines a symbol that has a name matching matcher and types common with symbolTypes.
|
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.
|
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.
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.
|
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.
|
private |
|
staticprivate |
|
staticprivate |
|
private |
|
private |