The DataView Tree helper adds support for working with tree data structures to a DataView. This is done by adding a new behavior to the DataView that is a parent behavior of the standard DataView behavior. The new behavior adds an API for setting a tree structure containing nodes, accessing properties of the nodes and associated rows, toggling the expanded state of nodes.
The helper does not provide support for creating UI elements such as an expand/contract widget. It only provides an API that your UI elements can call.
Note that this helper requires the DataView helper.
The DataView Demo application includes an example of using this helper:
https://github.com/trevordevore/dataview_demo
If your LiveCode application uses the Levure framework then the DataView Tree can be added as a helper.
- Download the latest release of Source Code.zip|tar.gz from https://github.com/trevordevore/levurehelper-dataview_tree/releases
- Unzip the contents and add the resulting folder to the ./app/helpers folder in your application folder.
If your LiveCode application is not using the Levure framework then you can use the dataview_tree_loader.livecodescript file to load the necessary stacks into memory.
- Download the latest release of Source Code.zip|tar.gz from https://github.com/trevordevore/levurehelper-dataview_tree/releases
- Unzip the contents, rename the resulting folder to dataview_tree, and add the folder to your application folder.
- Using the property inspector your application stack, Add all of the stack files in the dataview_tree folder to the
mainstacksproperty of your application stack. - In your application code start using the DataView Tree Assets Loader stack and then remove it from memory.
start using stack "DataView Tree Assets Loader"
delete stack "DataView Tree Assets Loader"
In order to use the DataView Tree helper you must do two things:
- Assign the behavior of your DataView control to
stack "DataView Tree Behavior". If you are already using a custom behavior with your DataView then assign the behavior of your custom behavior tostack "DataView Tree Behavior" - Create an array in the specified format and assign it to the
dvTreeproperty of the DataView. - Create one or more templates to display types of nodes in the tree.
- Implement the
DataForNodemessage in order to feed the tree data as needed.
The DataView helper includes a command which can create DataView Tree group controls in the LiveCode IDE:
dvtIdecreateDataViewTreeControlUsingDialog pTargetCard
dvtIdecreateDataViewTreeControlUsingDialog will call dvIdeCreateDataViewControlUsingDialog (see [DataView](https://github.com/trevordevore/levurehelper-dataview readme)) with some options customized for the DataView Tree.
The DataView Tree uses an array that represents a tree. This array has the least amount of data needed in order for the DataView Tree to work. The data you want to display in the tree can be added to the tree array or be provided from another array (or other data source). This data will supplied to the DataView Tree by way of the DataForNode message.
The array assigned to the dvTree property is a numerically indexed array of node arrays (arrays nested within an array). Each node array has the following keys:
id: Uniquely identifies the node in the tree. This also links the node to a record in your data source.type: Identifies the type of the node. This property can help you choose which row template to use for a given node.expanded: Boolean value specifying whether or not the node is expanded. Default isfalse.children: A numerically indexed array of child nodes.is leaf: Boolean value specifying whether or not the node can have children. Iftruethen the node cannot have children.
pTreeA[1]["type"]
pTreeA[1]["id"]
pTreeA[1]["expanded"]
pTreeA[1]["is leaf"]
pTreeA[1]["children"]
pTreeA[1]["children"][1]["type"]
pTreeA[1]["children"][1]["id"]
pTreeA[1]["children"][1]["expanded"]
pTreeA[1]["children"][1]["is leaf"]
pTreeA[1]["children"][1]["children"]
pTreeA[1]["children"][1]["children"][1]["type"]
pTreeA[1]["children"][1]["children"][1]["id"]
pTreeA[1]["children"][1]["children"][1]["expanded"]
pTreeA[1]["children"][1]["children"][1]["is leaf"]
pTreeA[1]["children"][1]["children"][1]["children"]
pTreeA[2]["type"]
pTreeA[2]["id"]
pTreeA[2]["expanded"]
pTreeA[2]["is leaf"]
pTreeA[2]["children"]
...
A standard DataView sends the DataForRow message. Usually there is a 1-1 mapping of data from your data source to the rows displayed in the DataView. In a tree the 1-1 mapping doesn't usually exist as a node can be collapsed which hides it's children in the UI.
Instead, a DataView Tree sends the DataForNode message. Your code must handle the DataForNode message in order to feed data to the DataView Tree for display. It looks very similar to the DataForRow message that a standard DataView receives but has one additional parameter – pNodeA. pNodeA contains the following keys:
idtypeexpandedis leaflevelchild count
command DataForNode pNodeA, pRow, @rDataA, @rTemplateStyle
# Use pNodeA["id"] to locate additional data in your data source to feed to rData...
# Move any values from pNodeA into rDataA that your row template may require
# For example:
put pNodeA["id"] into rDataA["id"]
put pNodeA["expanded"] into rDataA["expanded"]
put pNodeA["level"] into rDataA["level"]
put pNodeA["child count"] into rDataA["child count"]
# Specify the row template style to use in rTemplateStyle
put "my style" into rTemplateStyle
end DataForNode
You can use the pNodeA["id"] value to locate the data in your data source that should be displayed for the node.
You do not need to worry about defining NumberOfRows() or CacheKeyForRow(). Both of these functions are defined in the DataView Tree behavior. The behavior returns the node id property in the CacheKeyForRow() function.
The DataView Tree widget can draw tree lines which connect the nodes visually. The following tree line styles are used to describe how the tree lines can look at each level of the tree:
- empty: do not display any line at that level.
relative: The node at this level has children that appear after this row. Display a vertical line at that level.child: The node at this level is a child. Display a vertical line with a hash mark coming out of right.last child: The node at this level is the last child. Display a vertical line that originates at the top of the rowl, is half the height of the row, and has a hash mark coming out of the right.parent: This level is a parent node with children. Displaya horizontal line as well as a vertical line that originates in the middle of the row and extends to the bottom of the row.collapsed parent: This level is a parent node with children but it is collapsed. There is a horizontal line present but not vertical line leading to the children.
The DataView Tree stores the tree lines styles for each row when the tree is generated. You can display the tree lines using the included TreeLines widget.
The TreeLines widget is the default way to display tree lines as it is supported in LiveCode 8 and 9. The widget id is community.livecode.trevordevore.treelines and is automatically loaded along with the rest of the helper files.
If your row template does not have the "TreeLines" widget in it then follow these instructions for adding it. The templates in the ide folder included with this Helper include the widget.
To use the widget to display tree lines in your tree perform the following steps:
- Add the widget to your row template(s).
create widget "TreeLines" as "community.livecode.trevordevore.treelines". Disable the new widget and layer it behind everything except for the "Background" graphic. Set the coordinates to the topleft of the row template group. The width and height do not matter at this point. - Configure the
lineColor,lineInsetandlineSpacingproperties of the widget.lineInsetandlineSpacingare integers.lineInsetadjusts the offset from the left of the widget that lineslineSpacingrepresents how wide each level is in your tree. You can set thelineStylesof the widget to a list of values to see what each style looks like For example,relative,relative,empty,child,last child,parent. - In the
FillInDatahandler of your row template set thelineStylesproperty:set the lineStyles of widget "TreeLines" of me to the dvNodeTreeLineStyles[pDataA["id"]] of me. Important: Make sure that you copy theidkey frompNodeAtorDataAin theDataForNodehandler. - In the
LayoutControlmessage set the width and height to fill the entire row control.
The API includes a number of properties for accessing node or row properties. Most properties have both a row and node version. For example, to check if a row or node is a leaf you can check the dvRowIsLeaf[pRow] or dvNodeIsLeaf[pNodeId] property.
A DataView Tree has some additional commands that can be used to manipulate the tree. For example, there is a command for toggling the expanded state of a row (ToggleRowIsExpanded) or one for showing a particular node (ShowNode).
For example, to toggle the state of the tree you can dispatch ToggleRowIsExpanded to a DataView:
put 4 into tRow
dispatch "ToggleRowIsExpanded" to group "MyDataView" with tRow
The DataView Tree has a built in API for drag reordering. The API is an extension of the API built into the DataView. Drag reordering will be turned on by default. If you want to turn it off then set the viewProp["allow drag reordering"] of the DataView Tree group to false.
If you plan on using drag reordering it is a good idea to set the viewProp["drop operation identifier"] property of the DataView Tree. This will uniquely identify the drag operation for that specific tree. For example, you might set the property to categories if your tree displays categories. If no value is set then dataview tree nodes is used. This value will be assigned to line 1 of the dragData["private"] when the user starts dragging a node in the tree. Note that if two trees share the same drop operation identifier you can drag rows between them.
The DataView Tree will process the ValidateRowDrop message sent by the DataView behavior. You should not handle this message. Instead, the DataView Tree dispatches the ValidateNodeDrop message with the following parameters:
- pDraggingInfoA: Array with
action(thedragAction),mouseH, andmouseVids,root ids,drop level,source control id, andsource stackkeys. ThemouseHandmouseVkeys are the same parameters passed todragMove. Theidsis a comma delimited list of node ids that are being dragged. If the user clicked on a parent node all descendant node ids will be included in this list as well.root idsare the ids which can be moved without affecting any of the parent/child relationships in the dragged nodes. Thedrop levelis the level that the drop is will occur at.source control idis the long id of the DataView that started the drag operation.source stackis the short name of the stack the control - pProposedParentNodeId: The proposed id of the parent that the ids being dragged will be associated with.
- pProposedChildPosition: The proposed child position within the parent that the first id in the ids being dragged should be assigned to.
If no drop should occur then return false. You can also define any of the parameters as being passed by reference (using the @ symbol) and modify them. This means you can change the proposed parent id or child position based on your needs.
When the AcceptRowDrop message is sent from the DataView behavior the DataView Tree will process it and dispatch the AcceptNodeDrop message. It is passed the same parameters as ValidateNodeDrop.
This handler is where you can modify the tree and your data source if needed. Here is an example that moves all of the nodes being dragged under the new parent while maintaining any parent/child relationships in the nodes being dragged.
command AcceptNodeDrop pDraggingInfoA, pParentNodeId, pChildPosition
local tId
set the wholematches to true
# Only move nodes at the root of the nodes being dragged.
# This will maintain parent/child hierarchy.
repeat for each item tId in pDraggingInfoA["root ids"]
MoveNode tId, pParentNodeId, pChildPosition, false
add 1 to pChildPosition
end repeat
RefreshView
end AcceptNodeDrop
- dvNodeChildCount[pNodeId]
- dvNodeChildren[pNodeId]
- dvNodeDescendantNodes[pNodeId]
- dvNodeIsExpanded[pNodeId]
- dvNodeIsLeaf[pNodeId]
- dvNodeLevel[pNodeId]
- dvNodeOfId[pNodeId]
- dvNodeParentNode[pNodeId]
- dvNodeType[pNodeId]
- dvRowAncestorNodes[pRow]
- dvRowChildCount[pRow]
- dvRowChildren[pRow]
- dvRowChildRows[pRow]
- dvRowDescendantNodes[pRow]
- dvRowId[pRow]
- ScrollRowDescendantsIntoView
- SetNodeIsExpanded
- SetRowIsExpanded
- SetValueForKeyInNode
- SetValueForKeyInRow
Type: command
Syntax: CollapseAllNodes
Summary: Contracts all rows in the tree.
Returns: nothing
Description:
Call RefreshView to redraw the view.
Type: getProp
Syntax: dvHilitedData
Summary: Returns the id property of the selected row(s).
Returns: Comma-delimited list of integers
Description:
If not rows are selected then empty is returned.
Type: getProp
Syntax: dvHilitedIds
Summary: Returns the id property of the selected row(s).
Returns: Comma-delimited list of integers
Description:
If not rows are selected then empty is returned.
Type: setProp
Syntax: dvHilitedIds[pForceScroll] <pIds>
Summary: Sets the selected row based on the id property of a row(s).
Parameters:
| Name | Description |
|---|---|
pIds |
Comma-delimited list of ids to hilite. |
Description:
If any ids in pIds is not currently associated with a row then the tree
will be expanded to show it.
Note that if your ids have a "," in them then this property won't work correctly.
Type: getProp
Syntax: dvNodeAncestorNodes[pNodeId]
Summary: Returns index arrays pointing to ancestors of a node.
Returns: Numerically indexed array of index arrays
Type: getProp
Syntax: dvNodeChildCount[pNodeId]
Summary: Returns the number of children that a node has.
Returns: Integer
Type: getProp
Syntax: dvNodeChildren[pNodeId]
Summary: Returns a numerically indexed array of the index arrays of the child nodes of a node.
Returns: Array
Type: getProp
Syntax: dvNodeDescendantNodes[pNodeId]
Summary: Returns index arrays that point to the descendants of a node.
Returns: Numerically indexed array of index arrays
Type: setProp
Syntax: dvNodeIsExpanded[pNodeId] <pIsExpanded>
Summary: Expands the target node.
Parameters:
| Name | Description |
|---|---|
pIsExpanded |
Boolean value. |
Description:
Setting this property will not refresh the DataView.
For more options when expanding a row see SetNodeIsExpanded.
Type: getProp
Syntax: dvNodeIsLeaf[pNodeId]
Summary: Returns the is leaf property of the node.
Returns: Boolean
Type: getProp
Syntax: dvNodeLevel[pNodeId]
Summary: Returns the tree level of a node.
Returns: Integer
Type: getProp
Syntax: dvNodeOfId[pNodeId]
Summary: Finds a node by id and returns the index array pointing to a node in the tree.
Returns: Index array
Description:
The index array that is returned by this function can be used in other DataView Tree handlers. Index array can be used by the LiveCode engine to find nested keys in a LiveCode array.
An index array is a numerically indexed array that represents the keys pointing to a specific key in a nested array. For a key that is not nested the index array would have a single key. For a key that is nested three levels deep the index array would have three keys.
Assume the following array:
tPersonA["name"]
tPersonA["children"]
tPersonA["children"][1]["name"]
tPersonA["children"][2]["name"]
tPersonA["children"][3]["name"]
The index array for the third child would be as follows:
put "children" into tIndexA[1]
put 3 into tIndexA[2]
To get the name of the third child you would use the following syntax:
put tPersonA[tIndexA]["name"] into tChildName
Type: getProp
Syntax: dvNodeParentNode[pNodeId]
Summary: Returns a node's parent node id.
Returns: Integer
Description:
If the node does not have a parent then empty is returned.
Type: getProp
Syntax: dvNodeType[pNodeId]
Summary: Returns the type of the node.
Returns: Value
Type: getProp
Syntax: dvRowAncestorNodes[pRow]
Summary: Returns index arrays pointing to ancestors of a row.
Returns: Numerically indexed array of index arrays
Type: getProp
Syntax: dvRowChildCount[pRow]
Summary: Returns the number of children that a row has.
Returns: Integer
Type: getProp
Syntax: dvRowChildren[pRow]
Summary: Returns a numerically indexed array of the index arrays of the child nodes of a row.
Returns: Array
Type: getProp
Syntax: dvRowChildRows[pRow]
Summary: Returns the row numbers of a row's children.
Returns: List
Type: getProp
Syntax: dvRowDescendantNodes[pRow]
Summary: Returns the node keys of the descendants of a row.
Returns: Numerically indexed array of index arrays
Type: getProp
Syntax: dvRowId[pRow]
Summary: Returns the id of the row's node.
Returns: Mixed
Type: setProp
Syntax: dvRowIsExpanded[pRow] <pIsExpanded>
Summary: Expands the target row.
Parameters:
| Name | Description |
|---|---|
pIsExpanded |
Boolean value. |
Description:
For more options when expanding a row see SetRowIsExpanded.
Type: getProp
Syntax: dvRowIsLeaf[pRow]
Summary: Returns the is leaf property of the row's node.
Returns: Boolean
Type: getProp
Syntax: dvRowLevel[pRow]
Summary: Returns the tree level of a row.
Returns: Integer
Type: getProp
Syntax: dvRowNode[pRow]
Summary: Returns the node index array of the node associated with a row.
Returns: Array
Type: getProp
Syntax: dvRowOfId[pNodeId]
Summary: Returns the row assigned to a node.
Returns: Integer
Description:
If no row is associated with the id passed in then 0 is returned. A valid id will not have a row if it is the descendant of an ancestor that is not expanded.
Type: getProp
Syntax: dvRowParentRow[pRow]
Summary: Returns the row number of a rows parent.
Returns: Integer
Description:
If the row does not have a parent then 0 is returned.
Type: getProp
Syntax: dvRowPositionAmongSiblings[pRow]
Summary: Returns an integer representing the position of pRow amongst it's siblings.
Returns: Integer
Description:
If pRow is the third child of it's parent then this property would return 3.
Type: getProp
Syntax: dvRowType[pRow]
Summary: Returns the type of the row's node.
Returns: Mixed
Type: getProp
Syntax: dvTree
Summary: Returns the internal tree array.
Returns: Array
Type: command
Syntax: ExpandAllNodes
Summary: Expands all rows in the tree.
Returns: nothing
Description:
Call RefreshView to redraw the view.
Type: function
Syntax: GetValueForKeyInNode(<pNodeId>,<pKey>)
Summary: Returns the key value for a node array.
Returns: Mixed
Parameters:
| Name | Description |
|---|---|
pNodeId |
The node id or index array. |
pKey |
The key. |
Description:
See GetValueForKeyInRow.
Type: function
Syntax: GetValueForKeyInRow(<pRow>,<pKey>)
Summary: Returns the value for a key stored in a row's node array.
Returns: Mixed
Parameters:
| Name | Description |
|---|---|
pRow |
The target row. |
pKey |
The key. |
Description:
This function allow you to get the value of a key in the node array that doesn't have a built-in getProp handler.
Type: command
Syntax: RefreshView
Summary: Refreshes the view after toggling or showing nodes.
Returns: nothing
Description:
When calling handlers that toggle the expanded state of a node(s) the UI is not updated. This allows you to update multiple nodes and redraw all at once. Call this handler when you are ready to redraw the view.
Type: command
Syntax: RenderView
Summary: Build lookup tables so that NumberOfRows can return correct value.
Returns: nothing
Type: command
Syntax: ScrollNodeDescendantsIntoView <pNode>
Summary: See ScrollRowDescendantsIntoView/
Returns: nothing
Type: command
Syntax: ScrollRowDescendantsIntoView <pRow>
Summary: Scrolls a row and it's descendants into view.
Returns: nothing
Parameters:
| Name | Description |
|---|---|
pRow |
The target row. |
Description:
When expanding a row it may be desirable to scroll the newly exposed children into view. This handler will scroll the descendants into view without pushing pRow off the top.
Type: command
Syntax: SetNodeIsExpanded <pNode>,<pLevelsDown>,<pExpandedState>,<pRefreshView>
Summary: Sets the expanded state of a node.
Returns: empty
Parameters:
| Name | Description |
|---|---|
pNode |
The node id or the node index array. |
pLevelsDown |
How many levels to toggle. Empty or 0 only toggles pRow. -1 toggles all. Positive number affects that many levels down. |
pExpandedState |
Pass in a true/false to force a setting. |
pRefreshView |
Pass in false to keep the view from being refreshed. |
Description:
Expands the target node, expanding ancestors if need be in order to show the target node.
See SetRowIsExpanded for more information.
Type: command
Syntax: SetRowIsExpanded <pRow>,<pLevelsDown>,<pExpandedState>,<pRefreshView>
Summary: Sets the expanded state of a row.
Returns: Nothing
Parameters:
| Name | Description |
|---|---|
pRow |
The row to toggle. |
pLevelsDown |
How many levels to toggle. Empty or 0 only toggles pRow. -1 toggles all. Positive number affects that many levels down. |
pExpandedState |
Pass in a true/false to force a setting. |
pRefreshView |
Pass in false to keep the view from being refreshed. |
Description:
By default the DataView will be redrawn after calling this handler and the newly displayed
children nodes will be scrolled into view. If you pass in false for pRefreshView
then call RefreshView to redraw the view.
Type: command
Syntax: SetValueForKeyInNode <pNodeId>,<pKey>,<pValue>
Summary: Sets the value of a custom key stored in a rows node array.
Returns: nothing
Parameters:
| Name | Description |
|---|---|
pNodeId |
The node id or index array. |
pKey |
The custom key. |
pValue |
The value to assign to the key. |
Description:
See SetValueForKeyInRow.
Type: command
Syntax: SetValueForKeyInRow <pRow>,<pKey>,<pValue>
Summary: Sets the value of a custom key stored in a row's node array.
Returns: nothing
Parameters:
| Name | Description |
|---|---|
pRow |
The target row. |
pKey |
The custom key. |
pValue |
The value to assign to the key. |
Description:
This function allow you to set the value of a key in the node array that is
not one of the built-in properties id, type, expanded, is leaf, children,
level, and child count.
Type: command
Syntax: ShowNode <pNode>,<pRefreshView>
Summary: Expands any tree nodes necessary so that the node can be seen.
Returns: empty
Parameters:
| Name | Description |
|---|---|
pNode |
The node id or the node index array. |
pRefreshView |
Pass in false to keep the view from being refreshed. |
Description:
By default the DataView will be redrawn after calling this handler and the node will
be scrolled into view. If you pass in false for pRefreshView
then call RefreshView to redraw the view and ScrollRowIntoView to scroll
the row into view.
Type: command
Syntax: ToggleNodeIsExpanded <pNode>,<pLevelsDown>,<pRefreshView>
Summary: Toggles the expanded state of a node.
Returns: empty
Parameters:
| Name | Description |
|---|---|
pNode |
The node id or the node index array. |
pLevelsDown |
How many levels to toggle. Empty or 0 only toggles pRow. -1 toggles all. Positive number affects that many levels down. |
pRefreshView |
Pass in false to keep the view from being refreshed. |
Description:
See SetRowIsExpanded.
Type: command
Syntax: ToggleRowIsExpanded <pRow>,<pLevelsDown>,<pRefreshView>
Summary: Toggles the expanded state of a row.
Returns: Nothing
Parameters:
| Name | Description |
|---|---|
pRow |
The row to toggle. |
pLevelsDown |
How many levels to toggle. Empty or 0 only toggles pRow. -1 toggles all. Positive number affects that many levels down. |
pRefreshView |
Pass in false to keep the view from being refreshed. |
Description:
See SetRowIsExpanded.