﻿;-- TIME_STAMP   2017-01-28 19:21:08

#include <File.au3>
#include <FileConstants.au3>
#include <GuiTreeView.au3>
#include <TreeViewConstants.au3>
#include <WindowsConstants.au3>

Global $aAllItem[1][3], $hGUI, $hTreeview

Global $sPathRoot = 'C:\Test'   ; Ordner selbst ist nicht in der Auflistung, aber seine Struktur
Global $sFileStruct = @ScriptDir & '\test.struct'

#cs   Bsp-Inhalt der Struktur Datei

1|Ordner1
1.1|Ordner1_Sub1
1.1.1|Ordner1_Sub1_Sub1
1.1.2|Ordner1_Sub1_Sub2
1.1.3|Ordner1_Sub1_Sub3
1.1.4|Ordner1_Sub1_Sub4
1.1.5|Ordner1_Sub1_Sub5
1.1.5.1|Ordner1_Sub1_Sub5_Sub1
1.1.5.2|Ordner1_Sub1_Sub5_Sub2
1.1.6|Ordner1_Sub1_Sub6
1.1.6.3|Ordner1_Sub1_Sub6_Sub3
1.1.6.4|Ordner1_Sub1_Sub6_Sub4
1.1.6.5|Ordner1_Sub1_Sub6_Sub5
1.1.7|Ordner1_Sub1_Sub7
1.1.8|Ordner1_Sub1_Sub8
1.1.8.6|Ordner1_Sub1_Sub8_Sub6
1.1.9|Ordner1_Sub1_Sub9
1.1.10|Ordner1_Sub1_Sub10
1.1.11|Ordner1_Sub1_Sub11
1.1.12|Ordner1_Sub1_Sub12
1.1.13|Ordner1_Sub1_Sub13
2|Ordner2

#ce

;===================================================================================================
; Struktur lesen und in Datei speichern
_FolderStructToFile($sPathRoot, $sFileStruct)
;===================================================================================================


;===================================================================================================
; aus Struktur in Zielverzeichnis schreiben
Global $sPathTarget = 'C:\Neu'  ; entspricht dem Quellordner $sPathRoot
;~ _CreateStructFromFile($sPathTarget, $sFileStruct)
;===================================================================================================



Func _CreateGUI()
	Local $iStyle = BitOR($TVS_EDITLABELS, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS)
	Local $iStyleEx = BitOR($WS_EX_COMPOSITED, $WS_EX_CLIENTEDGE)
	$hGUI = GUICreate('Temp')
	Local $cTreeview = GUICtrlCreateTreeView(10, 100, 100, 100, $iStyle, $iStyleEx)
	$hTreeview = GUICtrlGetHandle($cTreeview)
EndFunc

Func _FolderStructToFile($_sPathFolder, $_sPathStruct)
	_CreateGUI()
	; Root eintragen
	Local $hRootItem = 0;_GUICtrlTreeView_Add($hTreeview, 0, _StripPath($_sPathFolder))
	_FillTreeviewFromFolder($hTreeview, $hRootItem, $_sPathFolder, $_sPathFolder)
	_GUICtrlTreeView_WriteToOrderFile($_sPathStruct, $hTreeview)
	GUIDelete($hGUI)
EndFunc

Func _CreateStructFromFile($_sRootTarget, $_sPathStruct)
	_CreateGUI()
	_GUICtrlTreeView_CreateFromOrderFile($_sPathStruct, $hTreeview)

	; für jeden Pfad im Tree prüfen ob:
		; - existiert noch nicht in RootTarget
		; --> dann erstellen
	; Erstellen/Speichern Struktur in Projektordner
	Local $hItem = _GUICtrlTreeView_GetFirstItem($hTreeview)
	Local $sItemPath
	While $hItem <> 0
		$sItemPath = StringFormat('%s\%s', $_sRootTarget, StringReplace(_GUICtrlTreeView_GetTree($hTreeview, $hItem), '|', '\') )
		If Not FileExists($sItemPath) Then
			If Not DirCreate($sItemPath) Then
				_OutputEvent(StringFormat('!! FEHLER - "%s" konnte nicht erstellt werden', $sItemPath))
			EndIf
			_OutputEvent(StringFormat('>> ERSTELLT "%s"', $sItemPath))
		EndIf
		$hItem = _GUICtrlTreeView_GetNext($hTreeview, $hItem)
	WEnd
	GUIDelete($hGUI)
EndFunc

Func _OutputEvent($sEvent)
	; Ereignisausgabe in Konsole
	ConsoleWrite(StringFormat('%s%s', $sEvent, @CRLF))
EndFunc


Func _FillTreeviewFromFolder($hwnd, $hParent, $sPathParent, $sPathChild, $bCheckall=False)
	; Treeview befüllen mit der Ordnerstruktur eines übergebenen Pfades
	Local $aDir = _GetFolder($sPathChild), $hItem
	If $aDir[0] > 0 Then
		For $i = 1 To $aDir[0]
			$aAllItem[0][0] += 1
			ReDim $aAllItem[$aAllItem[0][0]+1][3]
			Local $sItemName = _StripPath($aDir[$i])
			$hItem = _GUICtrlTreeView_AddChild($hwnd, $hParent, $sItemName)
			If $bCheckall Then _GUICtrlTreeView_SetChecked($hwnd, $hItem)
			$aAllItem[$aAllItem[0][0]][0] = $hItem
			$aAllItem[$aAllItem[0][0]][1] = $sItemName
			_FillTreeviewFromFolder($hwnd, $hItem, $aDir[$i], $aDir[$i], $bCheckall)
		Next
	EndIf
EndFunc

Func _GetFolder($sPath)
	; Rückgabe Array mit allen Pfaden der Ordner eines Verzeichnisses (nicht rekursiv)
	Local $aFolder = _FileListToArrayRec($sPath, "*", $FLTAR_FOLDERS, $FLTAR_NORECUR, $FLTAR_SORT, $FLTAR_FULLPATH)
	If @error Then Local $aFolder[1] = [0]
	Return $aFolder
EndFunc

Func _StripPath($sFullPath, $retPath=0)
	; Rückgabe Ordnername oder Pfad ohne Ordnername
	Local $i = StringInStr($sFullPath, '\', 0, -1)
	If $retPath = 1 Then Return StringLeft($sFullPath, $i-1)
	Return StringTrimLeft($sFullPath, $i)
EndFunc

; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlTreeView_CreateFromOrderFile
; Description ...: Creates Treeview Item from a file with the stored order
; Syntax ........: _GUICtrlTreeView_CreateFromOrderFile($_sFile, $_hWnd[, $_sDelim = -1[, $_bCheckAll=False]])
; Parameters ....: $_sFile              - Path to file with the order
; ...............: $_hWnd               - Treeview handle
; ......optional.: $_sDelim             - [optional] Delimiter. Default: -1 = Opt("GUIDataSeparatorChar")
; ...............:                        $_sDelim between order-string and item text
; ......optional.: $_bCheckAll          - If treeview has checkbox style - check all item (True) or not (False - Default)
; Return values .: Success              Array [[Handle item, order-string, item text]]
; ...............: Failure              0  @error = 1 Reading file has failed
; ...............:                                = 2 file is empty
; Author ........: BugFix ( AutoIt@bug-fix.info )
; ===============================================================================================================================
Func _GUICtrlTreeView_CreateFromOrderFile($_sFile, $_hWnd, $_sDelim=-1, $_bCheckAll=False)
	If $_sDelim = -1 Then $_sDelim = Opt("GUIDataSeparatorChar")
	Local $fH = FileOpen($_sFile, 128) ; 128=$FO_UTF8
	If $fH = -1 Then Return SetError(1,0,0)
	Local $sRead = FileRead($fH)
	If @error Then Return SetError(1,0,0)
	FileClose($fH)
	Local $aItem = StringRegExp($sRead, "([\d\.]*)\" & $_sDelim & "([^\r\n]+)", 3)
	If Not IsArray($aItem) Then Return SetError(2,0,0)
	Local $n = 1, $aTree[(UBound($aItem)/2)+1][3] = [[UBound($aItem)/2]]  ; == [[Handle-Item, Item-Text, sOrder]]
	Local $sOrderParent
	_GUICtrlTreeView_BeginUpdate($_hWnd)
	For $i = 0 To UBound($aItem) -2 Step 2
		$sOrderParent = __GetParentOrderNumber($aItem[$i])
		Switch $sOrderParent
			Case ''
				$aTree[$n][0] = _GUICtrlTreeView_Add($_hWnd, 0, $aItem[$i+1])
				If $_bCheckAll Then _GUICtrlTreeView_SetChecked($_hWnd, $aTree[$n][0])
			Case Else
				For $j = 1 To $n -1
					If $aTree[$j][2] = $sOrderParent Then
						$aTree[$n][0] = _GUICtrlTreeView_AddChild($_hWnd, $aTree[$j][0], $aItem[$i+1])
						If $_bCheckAll Then _GUICtrlTreeView_SetChecked($_hWnd, $aTree[$n][0])
						ExitLoop
					EndIf
				Next
		EndSwitch
		$aTree[$n][1] = $aItem[$i+1]   ; == Item-Text
		$aTree[$n][2] = $aItem[$i]     ; == sOrder
		$n += 1
	Next
	_GUICtrlTreeView_EndUpdate($_hWnd)
	Return $aTree
EndFunc  ;==>_GUICtrlTreeView_CreateFromOrderFile

; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlTreeView_WriteToOrderFile
; Description ...: Writes the treeview structure to an file
; Syntax ........: _GUICtrlTreeView_WriteToOrderFile($_sFile, $_hWnd[, $_sDelim = -1])
; Parameters ....: $_sFile              - Path to file with the order
; ...............: $_hWnd               - Treeview handle
; ...............: $_sDelim             - [optional] Delimiter. Default: -1 = Opt("GUIDataSeparatorChar")
; ...............:                        $_sDelim between order-string and item text
; Return values .: Erfolg               1
; ...............: Fehler               0  @error = 1 Writing file has failed
; Author ........: BugFix ( AutoIt@bug-fix.info )
; ===============================================================================================================================
Func _GUICtrlTreeView_WriteToOrderFile($_sFile, $_hWnd, $_sDelim=-1)
	Local $sOrder = _GUICtrlTreeView_GetItemOrder($_hWnd, True, $_sDelim)
	Local $fH = FileOpen($_sFile, 2+8+128) ; 2=$FO_OVERWRITE  8=$FO_CREATEPATH  128=$FO_UTF8
	If $fH = -1 Then Return SetError(1,0,0)
	Local $iErr = 0, $iSucc = FileWrite($fH, $sOrder)
	FileClose($fH)
	If $iSucc <> 1 Then $iErr = 1
	Return SetError($iErr,0,$iSucc)
EndFunc  ;==>_GUICtrlTreeView_WriteToOrderFile

; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlTreeView_GetItemOrder
; Description ...: Reads all treeview item with a related order-string into a string (Default) or array
; ...............: The order string corresponds to the number of item occurrences in its level
; ...............: The first item in level 1 gets "1" (the root), its siblings gets "2", "3" and so on
; ...............: Children from item "1" gets "1.1", "1.2" ... "1.n"
; ...............: Children from item "2" gets "2.n+1", "2.n+2" ... and so also for all level
; Syntax ........: _GUICtrlTreeView_GetItemOrder($_hWnd[, $_bString = True[, $_sDelim = -1]])
; Parameters ....: $_hWnd       Treeview handle
; ...............: $_bString    1 (Default): Output as string "order-number DELIMITER item-text CRLF", 0 returns an array
; ...............: $_sDelim     -1 (Default): Char from Opt(GUIDataSeparatorChar)
; Return values .: Success      String to store item with their order to file or
; ...............:              Array [[item-handle, order-number, item-text]]
; Author ........: BugFix ( AutoIt@bug-fix.info )
;================================================================================================================================
Func _GUICtrlTreeView_GetItemOrder($_hWnd, $_bString=True, $_sDelim=-1)
	If $_sDelim = -1 Then $_sDelim = Opt("GUIDataSeparatorChar")
	Local $iCount = _GUICtrlTreeView_GetCount($_hWnd)
	If $iCount = 0 Then Return SetError(1,0,0)
	Local $hItem = _GUICtrlTreeView_GetFirstItem($_hWnd)
	Local $aItem[$iCount][3] = [[$hItem, '1', _GUICtrlTreeView_GetText($_hWnd, $hItem)]]
	__GetItemArray($_hWnd, $hItem, $aItem)
	If Not $_bString Then Return $aItem
	Local $sRet = ''
	For $i = 0 To UBound($aItem) -1
		$sRet &= $aItem[$i][1] & $_sDelim & $aItem[$i][2] & @CRLF
	Next
	Return $sRet
EndFunc  ;==>_GUICtrlTreeView_GetItemOrder

; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlTreeView_IndentationLevel
; Description ...: Sets a new value for the maximum possible indentation level or gets the current one.
; Syntax ........: _GUICtrlTreeView_IndentationLevel([$_iLevel = 256])
; Parameters ....: $_iLevel     [optional] The new value to set. Default = 256, the minimum is 64. '-1' gets the current value.
; Return values .: The new/current indentation level
; Author ........: BugFix ( AutoIt@bug-fix.info )
;================================================================================================================================
Func _GUICtrlTreeView_IndentationLevel($_iLevel=256)
	Local Static $MAX_INDENTATION_LEVEL = 256
	If $_iLevel > 0 Then $MAX_INDENTATION_LEVEL = $_iLevel <> $MAX_INDENTATION_LEVEL ? ($_iLevel < 64 ? 64 : $_iLevel) : $MAX_INDENTATION_LEVEL
	Return $MAX_INDENTATION_LEVEL
EndFunc  ;==>_GUICtrlTreeView_IndentationLevel

#Region - Helper Functions
Func __GetItemArray($_hWnd, $_hParent, ByRef $_aItem)
	Local $aLevel[_GUICtrlTreeView_IndentationLevel(-1)] = [1], $iIndex = 1
	Local $hItem = _GUICtrlTreeView_GetNext($_hWnd, $_hParent)
	While $hItem <> 0
		$_aItem[$iIndex][0] = $hItem
		$_aItem[$iIndex][1] = __OrderNumber($aLevel, _GUICtrlTreeView_Level($_hWnd, $hItem))
		$_aItem[$iIndex][2] = _GUICtrlTreeView_GetText($_hWnd, $hItem)
		$iIndex += 1
		$hItem = _GUICtrlTreeView_GetNext($_hWnd, $hItem)
	WEnd
EndFunc  ;==>__GetItemArray

Func __OrderNumber(ByRef $_aLevel, $_iLevel)
	$_aLevel[$_iLevel] += 1
	Local $sOrder = ''
	For $i = 0 To $_iLevel
		$sOrder &= $_aLevel[$i] & '.'
	Next
	Return StringTrimRight($sOrder, 1)
EndFunc  ;==>__OrderNumber

Func __GetParentOrderNumber($_sOrder)
	If $_sOrder = '1' Then Return ''
	Local $iPos = StringInStr($_sOrder, '.', 1, -1)
	Return StringLeft($_sOrder, $iPos -1)
EndFunc  ;==>__OrderNumber
#EndRegion - Helper Functions