Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
titleInitialize Tree - ViewStyle
oTree:ViewStyle = Infragistics.Win.UltraWinTree.ViewStyle:Grid.

 

In addition the ColumnHeader can wrap the text which can be important when resizing the columns. This setting can be turned on and off as follows.

...

The UltraTreeColumnResizeHelper can be used in two ways.

1. All the NodeLevels have the same layout.

This setup is useful for fully recursive structures like property viewers where the same set of columns is supposed to be used for all nodes in all levels. This behavior can be seen in the Object Properties Dialog accessible from the Consultingwerk Error Message Dialog (available from OpenEdge 11.6 on). The tree view rendered by the Consultingwerk.Windows.Util.Controls.ProgressLangObjectPropertyControl displays properties of the Error objects and all referenced objects in a nested tree view:

...

Code Block
titleUltraTreeColumnResizeHelper - Definition
DEFINE PRIVATE VARIABLE oUltraTreeColumnResizeHelper AS UltraTreeColumnResizeHelper NO-UNDO.

...

 

Directly in the constructor of the Form class the class wide instance of the UltraTreeColumnResizeHelper is created. This needs to be done after the call to InitializeComponent as that is where the initial layout of the UltraTree will be defined.

Code Block
titleUltraTreeColumnResizeHelper - Initialization
/* Initialize resizing for NodeColumnSets */
oUltraTreeColumnResizeHelper = NEW UltraTreeColumnResizeHelper (THIS-OBJECT:ultraTree1,
																175,
																"PropertyLabel":U).

 

...

The Parameters are:

Parameter name

Description
poTreeThe UltraTree to be used for resizing
piPreferredCellSizeThe prefered cell size to be applied
pcFirstColumnKeyThe reference to the first column of the tree 

 

 

 

For each node that is added the InitializeColumnResizing method needs to be called. This method checks if there is an existing NodelLevel layout for this level. If not, then the layout of level 0 is cloned and automatically registered for synchronization by the UltraTreeColumnResizeHelper instance.

Code Block
titleUltraTreeColumnResizeHelper - Definition
/*------------------------------------------------------------------------------
	Purpose: Displays the properties of the passed in object in the property grid
	Notes:
	@param poObject The object to visualize
	@param poTreeNodes The parent nodes collection to add the object properties to
------------------------------------------------------------------------------*/
METHOD PROTECTED VOID DisplayObjectProperties (poObject AS Progress.Lang.Object,
											   poTreeNodes AS TreeNodesCollection):
	&IF DEFINED (AblReflection) NE 0 &THEN
	DEFINE VARIABLE oProperty AS Progress.Reflect.Property NO-UNDO .
	DEFINE VARIABLE oProperties AS Progress.Reflect.Property NO-UNDO EXTENT .
	DEFINE VARIABLE i AS INTEGER NO-UNDO .
	DEFINE VARIABLE cType AS CHARACTER NO-UNDO .
	DEFINE VARIABLE cValue AS CHARACTER NO-UNDO .
	DEFINE VARIABLE cName AS CHARACTER NO-UNDO .
	DEFINE VARIABLE oValue AS Progress.Lang.Object NO-UNDO .
	DEFINE VARIABLE oNode AS UltraTreeNode NO-UNDO .
	DEFINE VARIABLE iIndex AS INTEGER NO-UNDO .
	DEFINE VARIABLE oItemNode AS UltraTreeNode NO-UNDO .
	
	IF VALID-OBJECT (poTreeNodes:ParentNode) THEN
		oUltraTreeColumnResizeHelper:InitializeColumnResizing (poTreeNodes:ParentNode:Level + 1).
	
	oProperties = poObject:GetClass ():GetProperties(Progress.Reflect.Flags:Public:SetFlag (Progress.Reflect.Flags:Instance)) .
	
	DO i = 1 TO EXTENT (oProperties):


		ASSIGN oProperty = oProperties [i]
			   cValue = ?
			   cName = oProperty:Name
				   oValue = ?.


		/* Skip Next-Sibling and Prev-Sibling */
		IF oProperty:Name = "Next-Sibling":U OR oProperty:Name = "Prev-Sibling":U THEN
			NEXT .


		IF VALID-OBJECT (oProperty:DataType) AND oProperty:DataType <> Progress.Reflect.DataType:Object THEN
			ASSIGN cType = STRING (oProperty:DataType) .
		ELSE
			ASSIGN cType = oProperty:DataTypeName .


		CASE oProperty:DataType:
			WHEN Progress.Reflect.DataType:Object THEN DO ON ERROR UNDO, THROW:


				oValue = oProperty:Get (poObject) .


				IF VALID-OBJECT (oValue) THEN
					ASSIGN cName = SUBSTITUTE ("&1 : &2":U, cName, oValue:GetClass():TypeName)
						   cValue = oValue:ToString () .
				ELSE
					cValue = "<invalid object reference>":U .


				CATCH err AS Progress.Lang.Error :
					cValue = SUBSTITUTE ("Error: &1":U, err:GetMessage (1)) .
				END CATCH.
			END .
			OTHERWISE DO ON ERROR UNDO, THROW:


				cValue = STRING (oProperty:Get (poObject)) .


				CATCH err AS Progress.Lang.Error :
					cValue = SUBSTITUTE ("Error: &1":U, err:GetMessage (1)) .
				END CATCH.
			END.
		END CASE .


		oNode = poTreeNodes:Add (GUID) .
		oNode:Cells ["PropertyLabel":U]:Value = cName .
		oNode:Cells ["PropertyValue":U]:Value = cValue .


		IF oProperty:DataTypeName > "":U AND VALID-OBJECT (oValue) THEN
			THIS-OBJECT:DisplayObjectProperties (oValue, oNode:Nodes) .


		/* Iterate IEnumerable, but not TableModel as that would dump all records */
		IF VALID-OBJECT (oValue) AND TYPE-OF (oValue, IEnumerable) AND NOT TYPE-OF (oValue, TableModel) THEN DO:
			ASSIGN iIndex = 1 .


			{Consultingwerk/foreachABL.i Progress.Lang.Object oItem in oValue}


				oItemNode = oNode:Nodes:Add (GUID) .


				IF NOT VALID-OBJECT (oItem) THEN DO:


					oItemNode:Cells ["PropertyLabel":U]:Value = STRING (iIndex) .


					oItemNode:Cells ["PropertyValue":U]:Value = "<invalid object reference>":U .
				END.
				ELSE DO:
					DO ON ERROR UNDO, THROW:


						ASSIGN cValue = oItem:ToString () .


						CATCH err AS Progress.Lang.Error :
							cValue = err:GetMessage (1) .
						END CATCH.
					END.


					oUltraTreeColumnResizeHelper:InitializeColumnResizing (oNode:Level + 1).


					oItemNode:Cells ["PropertyLabel":U]:Value = SUBSTITUTE ("&1 : &2":U, iIndex, oItem:GetClass():TypeName) .


					oItemNode:Cells ["PropertyValue":U]:Value = cValue .


					/* Avoid infinite recursion caused by objects referencing themselves (circular references) */
					IF oNode:Level < 25 THEN
 						THIS-OBJECT:DisplayObjectProperties (oItem, oItemNode:Nodes) .
				END.
			END.
		END.
	END.
	&ENDIF
END METHOD .

 

2. There are multiple slightly different layouts having the same columns at the end of the line.

This scenario may be used, when displaying time-related information like stock flow per item and item category. There is different information displayed in the first columns but the last couple of columns of a NodeLevel layout will all be related to time or dates and be the same as in the other levels. The layout needs to be defined manually for each level on the current tree instance. Typically the maximum depth of the tree view is known upfront and each node (row) in the tree view can be created knowing the node level layout to be used here – based on the type of data shown. The UltraTreeColumnResizeHelper will not duplicate node level definitions, it will only ensure proper column separation for the common columns (rightmost columns).

...

Code Block
titleUltraTreeColumnResizeHelper - NodeLevel based resizing
/*------------------------------------------------------------------------------
	Purpose: Populates the Tree with all Items and where they are stored
	Notes:
	@param poNodesCollection The NodesCollection of the Tree to be populated
------------------------------------------------------------------------------*/
METHOD PUBLIC VOID PopulateTree (poNodesCollection AS TreeNodesCollection):
	
	DEFINE VARIABLE oNode AS UltraTreeNode NO-UNDO.
	DEFINE VARIABLE oParentNode AS UltraTreeNode NO-UNDO.
	DEFINE VARIABLE pcKey AS CHARACTER NO-UNDO.
	DEFINE VARIABLE oUltraTreeColumnResizeHelper AS UltraTreeColumnResizeHelper NO-UNDO.


	FOR EACH Item NO-LOCK:


		oParentNode = NEW UltraTreeNode (Item.ItemNumber, Item.ItemLabel).


		poNodesCollection:ADD (oParentNode).


		FOR EACH Warehouse NO-LOCK:


			pcKey = SUBSTITUTE ("&1_&2":U, Item.ItemNumber, Warehouse.WarehouseNumber).


			oNode = NEW UltraTreeNode (pcKey, Warehouse.WarehouseName).


			oParentNode:Nodes:Add (oNode).


			oUltraTreeColumnResizeHelper:RegisterNodeLevelsForSyncronization (oNode:Level, 1, 1).


		END.


	END.


END METHOD.

The first parameters is the current NodeLevel to be synchronized with its parent. The second and third parameter define in which column the synchronization will start for each of the levels.