Jump to content

Macros/ScriptForge/TreeControlExample-bis

From The Document Foundation Wiki


How to display data in a tree control

(The less easy way)

Authored by Jean-Pierre Ledure.

Navigate through hierarchical data by means of a tree control. Why the less easy way?

When the number of sublevels is undefined and/or when the number of sub-nodes can be huge, the data is better grabbed each time any expand icon is pressed. The technique is illustrated with a customized file picker.

A file picker dialog.
A file picker dialog.

How to run it in BASIC

Create a new document.

  1. Open the Basic IDE
  2. Select the first available blank module
  3. Copy and paste the Basic code
  4. Verify lines 12-13
  5. Configure in line 18 the top folder of the file picker in the usual system notation
  6. Run Main()

How to run it in Python

Create a new document.

  1. Run APSO
  2. Create a new module, call it 'Module1'
  3. Copy and paste the Python code below
  4. Verify lines 15-16
  5. Set in line 21 the top folder of the file picker in the usual system notation
  6. Save and run the Main() method

Code

REM  SCRIPTFORGE WIKI EXAMPLE
REM 	How to animate a tree control like a file picker ?
REM		Minimal required version: LibreOffice 7.6
REM 	Used services
REM 		SFDialogs.Dialog, SFDialogs.DialogControl, ScriptForge.FileSystem, ScriptForge.Array

Option Explicit

'*******************************************************************
'***	Adjust module name if not "Module1"
'*******************************************************************
Const onnodeselected = "vnd.sun.star.script:Standard.Module1.TreeSelected?language=Basic&location=document"
Const onnodeexpanded = "vnd.sun.star.script:Standard.Module1.TreeExpanded?language=Basic&location=document"

'*******************************************************************
'***	Set the starting folder of the file picker
'*******************************************************************
Const startfolder = "/opt/libreoffice24.2"

'*******************************************************************
'* Run the demo below
'*******************************************************************
Sub Main(Optional event As Object)
Dim dialog			As Object		'	The SFDialogs.Dialog object
	GlobalScope.BasicLibraries.loadLibrary("ScriptForge")
	Set dialog = SetupDialog()
	InitTree(dialog)
	dialog.Execute()
	dialog.Terminate()
End Sub

'*******************************************************************
'* Specific demo code
'*******************************************************************
Sub InitTree(ByRef dialog As Object)
'	Initialize the tree with the root node, i.e. an arbitrary folder

Dim treecontrol		As Object		'	A SFDialogs.DialogControl service instance
Dim rootnode		As Object		'	com.sun.star.awt.tree.XTreeNode

	treecontrol = dialog.Controls("FilePicker")
	'	Each node will contain	- a DisplayValue = last path component
	'							- a DataValue = the full path
	Set rootnode = treecontrol.CreateRoot(displayvalue := startfolder, datavalue := startfolder)
	SetSubtree(treecontrol, rootnode)

	'	Activate the node selection and expansion triggers
	treecontrol.OnNodeSelected = onnodeselected
	treecontrol.OnNodeExpanded = onnodeexpanded

End Sub

'*******************************************************************
'* Fired when an item in the tree control is selected
'*******************************************************************
Sub TreeSelected(Optional event As Variant)
'	Triggered by the OnNodeSelected event

Dim dialog			As Object		'	The SFDialogs.Dialog object
Dim treecontrol		As Object		'	A SFDialogs.DialogControl service instance
Dim node			As Object		'	com.sun.star.awt.tree.XTreeNode
Dim textbox			As Object		'	A SFDialogs.DialogControl service instance
Dim fullpath		As String		'	A file or folder name
Dim fso				As Object		'	The ScriptForge.FileSystem service unique instance

	If IsNull(event) Then Exit Sub

	Set treecontrol = CreateScriptService("DialogEvent", event)
	Set dialog = treecontrol.Parent
	'	Display the content of the selected node when it is not expandable
	Set node = treecontrol.CurrentNode

	fullpath = node.DataValue
	Set textbox = dialog.Controls("FileDetails")

	Set fso = CreateScriptService("FileSystem")
	fso.FileNaming = "SYS"		'	Only use the system file notation
	If fso.FolderExists(fullpath) Then
		textbox.Value = "FOLDER: " & fullpath
	ElseIf fso.FileExists(fullpath) Then
		textbox.Value = "FILE: " & fullpath _
							& Chr(10) & "Length: " & Split(fso.GetFileLen(fullpath), ".")(0) & " bytes" _
							& Chr(10) & "Modified on: " & fso.GetFileModified(fullpath)
	End If

End Sub

'*******************************************************************
'* Fired when an item in the tree control is expanded
'*******************************************************************
Sub TreeExpanded(Optional event As Variant)
'	Triggered by the OnNodeExpanded event

Dim treecontrol		As Object		'	A SFDialogs.DialogControl service instance
Dim node			As Object		'	com.sun.star.awt.tree.XTreeNode

	If IsNull(event) Then Exit Sub

	Set treecontrol = CreateScriptService("DialogEvent", event)
	Set node = event.Node

	If node.ChildCount > 0 Then Exit Sub			'	The node was expanded previously, do nothing

	SetSubtree(treecontrol, node)
	
End Sub

'*******************************************************************
'* Subfolders and subfiles
'* Called when root is created or when a folder is expanded
'*******************************************************************
Sub SetSubtree(treecontrol As Object, node As Object)
'	Find all folders and files depending on the given node of the given treecontrol
'	Sort them, folders first
'	Add as subnodes all folders and files to the given node

Dim folder			As String		'	The folder represented by the fiven node
Dim subfiles		As Variant		'	Array of files in the current folder
Dim subfolders		As Variant		'	Array of subfolders in the current folder
Dim subitems		As Variant		'	Array aggregating subfolders and subitems
Dim fso				As Object		'	The ScriptForge.FileSystem service unique instance
Dim arr				As Object		'	The ScriptForge.Array service unique instance
Dim s				As String		'	Loop variable

	Set fso = CreateScriptService("FileSystem")
	fso.FileNaming = "SYS"		'	Only use the system file notation
	Set arr = CreateScriptService("Array")

	folder = node.DataValue
	If Not fso.FolderExists(folder) Then Exit Sub	'	The node is not a folder, exit

	'	Collect all subfolders and files contained below the node argument
	subitems = fso.SubFolders(folder)
	If UBound(subitems) < 0 Then subfolders = Array() Else subfolders = arr.Sort(subitems, CaseSensitive := False)
	subitems = fso.Files(folder)
	If UBound(subitems) < 0 Then subfiles = Array() Else subfiles = arr.Sort(subitems, CaseSensitive := False)
	subitems = arr.Flatten(arr.Append(subfolders, subfiles))

	'	Build the next level of the tree under the current node
	For Each s In subitems
		treecontrol.AddSubNode(node, displayvalue := fso.GetName(s), datavalue := s)
	Next s

End Sub

'*******************************************************************
'* May be defined with the Basic IDE
'*******************************************************************
Function SetupDialog()
'	Build from scratch the example dialog and its controls

Dim dialog			As Object		'	The SFDialogs.Dialog object
Dim control			As Object		'	A SFDialogs.DialogControl object

	Set dialog = CreateScriptService("NewDialog", "Tree", Array(115, 65, 260, 217))
 	dialog.Caption = "File picker"
 
 	With dialog
		'	The close button
		Set control = .CreateButton("CloseButton", place := Array(230, 207, 30, 12), push := "OK")
		control.Caption = "Close"
		'	The tree control
		Set control = .CreateTreeControl("FilePicker", place := Array(10, 6, 245, 160))
		'	The textbox with the details
		Set control = .CreateTextField("FileDetails", place := Array(10, 170, 245, 33), multiline := True)
	End With

	Set SetupDialog = dialog

End Function
# coding: utf-8
from __future__ import unicode_literals

#	SCRIPTFORGE WIKI EXAMPLE
#		How to animate a tree control like a file picker ?
#		Minimal required version: LibreOffice 7.6
#		Used services
#			SFDialogs.Dialog, SFDialogs.DialogControl, ScriptForge.FileSystem

from scriptforge import CreateScriptService

# *******************************************************************
# ***	Adjust module name if not 'Module1'
# *******************************************************************
onnodeselected = 'vnd.sun.star.script:Module1.py$TreeSelected?language=Python&location=document'
onnodeexpanded = 'vnd.sun.star.script:Module1.py$TreeExpanded?language=Python&location=document'

# *******************************************************************
# ***	Set the starting folder of the file picker
# *******************************************************************
startfolder = '/opt/libreoffice24.2'

# *******************************************************************
# * Run the demo below
# *******************************************************************
def Main(event = None):
	#   dialog					The SFDialogs.Dialog object
	dialog = SetupDialog()
	InitTree(dialog)
	dialog.Execute()
	dialog.Terminate()


# *******************************************************************
# * Specific demo code
# *******************************************************************
def InitTree(dialog = None):
	#	Initialize the tree with the root node, i.e. an arbitrary folder

	# treecontrol				A SFDialogs.DialogControl service instance
	# rootnode					com.sun.star.awt.tree.XTreeNode

	treecontrol = dialog.Controls('FilePicker')
	#	Each node will contain	- a DisplayValue = last path component
	#							- a DataValue = the full path

	rootnode = treecontrol.CreateRoot(displayvalue = startfolder, datavalue = startfolder)
	SetSubtree(treecontrol, rootnode)

	#	Activate the node selection and expansion triggers
	treecontrol.OnNodeSelected = onnodeselected
	treecontrol.OnNodeExpanded = onnodeexpanded


# *******************************************************************
# * Fired when an item in the tree control is selected
# *******************************************************************
def TreeSelected(event = None):
	#	Triggered by the OnNodeSelected event

	# dialog					The SFDialogs.Dialog object
	# treecontrol				A SFDialogs.DialogControl service instance
	# node						com.sun.star.awt.tree.XTreeNode
	# textbox					A SFDialogs.DialogControl service instance
	# fullpath					A file or folder name
	# fso						The ScriptForge.FileSystem service unique instance

	if event is None:
		return

	treecontrol = CreateScriptService('DialogEvent', event)
	dialog = treecontrol.Parent
	#	Display the content of the selected node when it is not expandable
	node = treecontrol.CurrentNode

	fullpath = node.DataValue
	textbox = dialog.Controls('FileDetails')

	fso = CreateScriptService('FileSystem')
	fso.FileNaming = 'SYS'		#	Only use the system file notation
	if fso.FolderExists(fullpath):
		textbox.Value = 'FOLDER: ' + fullpath
	elif fso.FileExists(fullpath):
		textbox.Value = 'FILE: ' + fullpath + \
							'\n' + 'Length: ' + str(fso.GetFileLen(fullpath)) + ' bytes' + \
							'\n' + 'Modified on: ' + str(fso.GetFileModified(fullpath))


# *******************************************************************
# * Fired when an item in the tree control is expanded
# *******************************************************************
def TreeExpanded(event = None):
	#	Triggered by the OnNodeExpanded event

	# treecontrol				A SFDialogs.DialogControl service instance
	# node						com.sun.star.awt.tree.XTreeNode

	if event is None:
		return

	treecontrol = CreateScriptService('DialogEvent', event)
	node = event.Node

	if node.ChildCount > 0:			#	The node was expanded previously, do nothing
		return

	SetSubtree(treecontrol, node)


# *******************************************************************
# * Subfolders and subfiles
# * Called when root is created or when a folder is expanded
# *******************************************************************
def SetSubtree(treecontrol, node):
	#	Find all folders and files depending on the given node of the given treecontrol
	#	Sort them, folders first
	#	Add as subnodes all folders and files to the given node

	# folder					The folder represented by the fiven node
	# subfiles					List of files in the current folder
	# subfolders				List of subfolders in the current folder
	# subitems					List aggregating subfolders and subitems
	# fso						The ScriptForge.FileSystem service unique instance
	# s							Loop variable

	fso = CreateScriptService('FileSystem')
	fso.FileNaming = 'SYS'		#	Only use the system file notation

	folder = node.DataValue
	if fso.FolderExists(folder) is False:		#	The node is not a folder, exit
		return

	#	Collect all subfolders and files contained below the node argument
	subitems = fso.SubFolders(folder)
	subfolders = sorted(subitems, key = str.casefold)
	subitems = fso.Files(folder)
	subfiles = sorted(subitems, key = str.casefold)
	subitems = subfolders + subfiles

	#	Build the next level of the tree under the current node
	for s in subitems:
		treecontrol.AddSubNode(node, displayvalue = fso.GetName(s), datavalue = s)


# *******************************************************************
# * May be defined with the Basic IDE
# *******************************************************************
def SetupDialog():
	#	Build from scratch the example dialog and its controls

	# dialog					The returned SFDialogs.Dialog object
	# control					A SFDialogs.DialogControl object

	dialog = CreateScriptService('NewDialog', 'Tree', (115, 65, 260, 217))
	dialog.Caption = 'File picker'

	#	The close button
	control = dialog.CreateButton('CloseButton', place = (230, 207, 30, 12), push = 'OK')
	control.Caption = 'Close'
	#	The tree control
	control = dialog.CreateTreeControl('FilePicker', place = (10, 6, 245, 160))
	#	The textbox with the details
	control = dialog.CreateTextField('FileDetails', place = (10, 170, 245, 33), multiline = True)

	return dialog


g_exportedScripts = (Main,)

if __name__ == '__main__':
	Main()


See also