diff --git a/Compiler.Core.ps1 b/Compiler.Core.ps1 index 050c4ac..91d9e56 100644 --- a/Compiler.Core.ps1 +++ b/Compiler.Core.ps1 @@ -2924,99 +2924,6 @@ return $ordered } - # Concat mit einer dynamischen Anzahl von Argumenten - static [string] Concat([string[]]$input) { - return $input -join '' - } - - # ToLower-Methode - static [string] ToLower([string[]]$input) { - return $input[0].ToLower() - } - - # ToUpper-Methode - static [string] ToUpper([string[]]$input) { - return $input[0].ToUpper() - } - - # FirstIndexOf-Methode - static [string] FirstIndexOf([string[]] $input){ - return $input[0] - } - - # LastIndexOf-Methode - static [string] LastIndexOf([string[]] $input){ - return $input[-1] - } - - # IndexOf-Methode - static [string] IndexOf([string[]] $input){ - return $input[$input[-1]] - } - - # Substring-Methode - static [String] Substring([string[]] $input){ - if($input.Count -eq 2){ - $array = $input.Split(',') - return $array[0].Substring($array[1]) - - }elseif($input.Count -eq 3){ - $array = $input.Split(',') - return $array[0].Substring($array[1],$array[2]) - - }else{ - Write-Warning "Zuviele Parameter" - return $false - } - } - - # Replace-Methode - static [String] Replace([string[]] $input){ - $array = $input.Split(',') - return $array[0].Replace($array[1],$array[2]) - } - - hidden [System.Collections.Specialized.OrderedDictionary] ResolveDeploymentParameterDefaultValues(){ - $TemplateClone = $this.Template - - if($TemplateClone.Contains("Parameters")){ - foreach($Parameter in $this.Template.Parameters.GetEnumerator()){ - if(!$Parameter.Value.Contains("Value")){ - $TemplateClone.Parameters[$Parameter.Name].Value = $this.Template.Parameters[$Parameter.Name].DefaultValue - } - } - } - return $TemplateClone - } - - [System.Collections.Specialized.OrderedDictionary] ResolveDeploymentDataVariables(){ - - - $TemplateClone = $this.ResolveDeploymentParameterDefaultValues() - - # Erst Variables auflösen (können Parameter-Referenzen enthalten) - if ($TemplateClone.Variables) { - $resolvedVariables = New-Object System.Collections.Specialized.OrderedDictionary - # WICHTIG: Keys-Array erstellen, um Collection-Modification zu vermeiden - $varKeys = @($TemplateClone.Variables.Keys) - foreach ($varKey in $varKeys) { - $resolvedVariables[$varKey] = $this.ResolveValue($TemplateClone.Variables[$varKey],$TemplateClone.Parameters,$TemplateClone.Variables) - } - $TemplateClone.Variables = $resolvedVariables - } - - # Dann den Rest des Templates auflösen - # WICHTIG: Keys-Array erstellen, um Collection-Modification zu vermeiden - $templateKeys = @($TemplateClone.Keys) - foreach ($key in $templateKeys) { - if ($key -ne 'Variables' -and $key -ne 'Parameters') { - $TemplateClone[$key] = $this.ResolveValue($TemplateClone[$key],$TemplateClone.Parameters,$TemplateClone.Variables) - } - } - - return $TemplateClone - } - hidden [System.Collections.Specialized.OrderedDictionary] ConvertFromPowerShellDataString($TemplatePath){ $errors = $null $tokens = $null @@ -3096,127 +3003,6 @@ return $ordered } - hidden [System.Object] ResolveValue($Value, $Parameters, $Variables){ - if ($Value -is [string]) { - # Resolve Parameter-Referenzen: [Parameter('name')] - while ($Value -match "\[Parameter\('([^']*)'\)\]") { - $paramName = $matches[1] - if ($Parameters.Contains($paramName)) { - - # Prüfe erst auf Value, dann auf DefaultValue - $paramValue = $Parameters[$paramName].Value - - if ($null -ne $paramValue) { - $Value = $Value -replace "\[Parameter\('$([regex]::Escape($paramName))'\)\]", $paramValue - } - else { - break - } - } - else { - Write-Warning "Parameter '$paramName' nicht gefunden" - break - } - } - - # Resolve Variable-Referenzen: [Variable('name')] - while ($Value -match "\[Variable\('([^']*)'\)\]") { - $varName = $matches[1] - if ($Variables.Contains($varName)) { - $varValue = $this.ResolveValue($Variables[$varName],$Parameters,$Variables) - $Value = $Value -replace "\[Variable\('$([regex]::Escape($varName))'\)\]", $varValue - } - else { - Write-Warning "Variable '$varName' nicht gefunden" - break - } - } - - while ($Value -match "Parameter\('([^']*)'\)") { - $paramName = $matches[1] - if ($Parameters.Contains($paramName)) { - # Prüfe erst auf Value, dann auf DefaultValue - $paramValue = if ($Parameters[$paramName].Value) { - $Parameters[$paramName].Value - } - elseif ($Parameters[$paramName].DefaultValue) { - $Parameters[$paramName].DefaultValue - } - else { - Write-Warning "Parameter '$paramName' hat weder Value noch DefaultValue" - $null - } - - if ($null -ne $paramValue) { - $Value = $Value -replace "Parameter\('$([regex]::Escape($paramName))'\)", $("'"+$paramValue+"'") - } - else { - break - } - } - else { - Write-Warning "Parameter '$paramName' nicht gefunden" - break - } - } - - #Resolve Variable-Referenzen: Variable('name') - while ($Value -match "Variable\('([^']*)'\)"){ - $varName = $matches[1] - if ($Variables.Contains($varName)) { - $varValue = $this.ResolveValue($Variables[$varName],$Parameters,$Variables) - $Value = $Value -replace "Variable\('$([regex]::Escape($varName))'\)", $("'"+$varValue+"'") - } - else { - Write-Warning "Variable '$varName' nicht gefunden" - break - } - } - - # Resolve SSPUtility-Funktionen - foreach($Function in $([TemplateBuilder].GetMethods('Static, Public')).Name | Get-Unique) { - $pattern = "\["+$Function+"\((.*?)\)\]" - while ($Value -match $pattern) { - try { - $fullMatch = $matches[0] - $argsString = $matches[1] - - # Parse die Argumente korrekt - sie sind bereits als PowerShell-Array formatiert - # Wir müssen sie nur evaluieren - $scriptBlock = [scriptblock]::Create("@($argsString)") - $argsArray = & $scriptBlock - - # Rufe die Methode direkt auf statt Invoke-Expression - $result = [TemplateBuilder]::$Function($argsArray) - $Value = $Value.Replace($fullMatch, $result) - } - catch { - Write-Warning "Fehler beim Ausführen von $matches[0] : $_" - break - } - } - } - - return $Value - } - elseif ($Value -is [System.Collections.IDictionary]) { - $resolved = New-Object System.Collections.Specialized.OrderedDictionary - foreach ($key in $Value.Keys) { - $resolved[$key] = $this.ResolveValue($Value[$key],$Parameters,$Variables) - } - return $resolved - } - elseif ($Value -is [array]) { - $resolved = @() - foreach ($item in $Value) { - $resolved += $this.ResolveValue($item,$Parameters,$Variables) - } - return $resolved - } - else { - return $Value - } - } } class TabControlBuilder : BaseComponent{ @@ -3335,6 +3121,23 @@ [BaseComponent]::InitializeShared($settingsManager, $logManager) + $script:MergedConfigurationData = $null + $script:ResolvedConfigurationData = $null + + $powerShellRoot = Split-Path -Path $PSScriptRoot -Parent + $mergeModulePath = Join-Path -Path $powerShellRoot -ChildPath "Merge-DSCConfigurationData\Merge-DSCConfigurationData.psd1" + $resolveModulePath = Join-Path -Path $powerShellRoot -ChildPath "Resolve-DSCConfigurationData\Resolve-DSCConfigurationData.psd1" + + foreach($modulePath in @($mergeModulePath, $resolveModulePath)){ + try{ + Import-Module $modulePath -Force -ErrorAction Stop + $logManager.Info("Modul geladen: $modulePath") + }catch{ + $logManager.Error("Fehler beim Laden des Moduls '$modulePath': $_") + throw + } + } + foreach($function in $(Get-ChildItem -Path $settingsManager.Get("FunctionsPath") -Recurse -Filter "*.ps1" -File)){ $logManager.Info("Lade Funktion: $($function.FullName)") try{ diff --git a/Compiler.ps1 b/Compiler.ps1 index a46eb23..b1d5134 100644 --- a/Compiler.ps1 +++ b/Compiler.ps1 @@ -1,3514 +1,5 @@ -<<<<<<< HEAD $formsType = 'System.Windows.Forms.Form' -as [type] if ($null -eq $formsType) { -======= - using namespace System.Windows.Forms - using namespace System.Drawing - - #region Class Definition - - class BaseComponent { - static [SettingsManager] $SettingsManager - static [LogManager] $LogManager - static [AccessibilityManager] $AccessibilityManager - - static [void] InitializeShared([SettingsManager]$SettingsManager, [LogManager]$LogManager) { - [BaseComponent]::SettingsManager = $SettingsManager - [BaseComponent]::LogManager = $LogManager - [BaseComponent]::AccessibilityManager = [AccessibilityManager]::new($SettingsManager, $LogManager) - } - - [object] GetSetting([string]$key) { - return [BaseComponent]::SettingsManager.Get($key) - } - - [object] GetSetting([string]$key, [object]$defaultValue) { - return [BaseComponent]::SettingsManager.Get($key, $defaultValue) - } - - [void] SetSetting([string]$key, [object]$value) { - [BaseComponent]::SettingsManager.Set($key, $value) - } - - [void] LogInfo([string]$message) { - if ($null -ne [BaseComponent]::LogManager) { - [BaseComponent]::LogManager.Info($message) - } - } - } - - class SettingsManager { - [System.String]$SettingsPath - [System.Collections.Hashtable]$Settings - - SettingsManager([System.String]$appName) { - $appDataPath = [Environment]::GetFolderPath('ApplicationData') - $appFolder = Join-Path $appDataPath $appName - - if (-not (Test-Path $appFolder)) { - New-Item -Path $appFolder -ItemType Directory -Force | Out-Null - } - - $this.SettingsPath = Join-Path $appFolder "settings.json" - $this.Load() - $this.EnsureDefaults() - } - - [void] Load() { - if (Test-Path $this.SettingsPath) { - try { - $json = Get-Content $this.SettingsPath -Raw | ConvertFrom-Json - $this.Settings = @{} - foreach ($prop in $json.PSObject.Properties) { - $this.Settings[$prop.Name] = $prop.Value - } - } catch { - Write-Warning "Fehler beim Laden der Settings: $_" - $this.Settings = @{} - } - } else { - $this.Settings = @{} - } - } - - # NEU: Stellt sicher, dass Standard-Einstellungen vorhanden sind - [void] EnsureDefaults() { - if (-not $this.Settings.ContainsKey("MenuStructure")) { - $this.Settings["MenuStructure"] = $this.GetDefaultMenuStructure() - $this.Save() - } - - if (-not $this.Settings.ContainsKey("WindowWidth")) { - $this.Settings["WindowWidth"] = 1024 - } - - if (-not $this.Settings.ContainsKey("WindowHeight")) { - $this.Settings["WindowHeight"] = 768 - } - - if (-not $this.Settings.ContainsKey("SplitterDistance")) { - $this.Settings["SplitterDistance"] = 200 - } - - if (-not $this.Settings.ContainsKey("TemplatePath")) { - $this.Settings["TemplatePath"] = (Join-Path -Path $this.Settings["RootPath"] -ChildPath "Templates") - } - - if (-not $this.Settings.ContainsKey("FunctionsPath")) { - $this.Settings["FunctionsPath"] = (Join-Path -Path $this.Settings["RootPath"] -ChildPath "Functions") - } - - if (-not $this.Settings.ContainsKey("DeploymentPath")) { - $this.Settings["DeploymentPath"] = (Join-Path -Path $this.Settings["RootPath"] -ChildPath "Deployments") - } - } - - # NEU: Standard-Menüstruktur - [object] GetDefaultMenuStructure() { - return @( - @{ - Name = "Datei" - Text = "Datei" - Items = @( - @{ Name = "Import"; Text = "Import" } - @{ Name = "Export"; Text = "Export" } - @{ Name = "Refresh"; Text = "Aktualisieren" } - @{ Type = "Separator" } - @{ Name = "Exit"; Text = "Beenden" } - ) - }, - @{ - Name = "Settings" - Text = "Einstellungen" - Items = @( - @{ Name = "OpenFolder"; Text = "Ordner wählen..." } - @{ Name = "ResetMenu"; Text = "Menü zurücksetzen" } - ) - }, - @{ - Name = "TemplateDesigner" - Text = "Template Designer" - }, - @{ - Name = "Help" - Text = "Hilfe" - Items = @( - @{ Name = "About"; Text = "Über..." } - ) - } - ) - } - - [void] Save() { - try { - $this.Settings | ConvertTo-Json -Depth 10 | Set-Content $this.SettingsPath -Encoding UTF8 - } catch { - Write-Warning "Fehler beim Speichern der Settings: $_" - } - } - - [object] Get([System.String]$key) { - return $this.Settings[$key] - } - - [object] Get([System.String]$key, [object]$defaultValue) { - if ($this.Settings.ContainsKey($key)) { - return $this.Settings[$key] - } - return $defaultValue - } - - [void] Set([System.String]$key, [object]$value) { - $this.Settings[$key] = $value - $this.Save() - } - - [bool] Contains([System.String]$key) { - return $this.Settings.ContainsKey($key) - } - - [void] Remove([System.String]$key) { - if ($this.Settings.ContainsKey($key)) { - $this.Settings.Remove($key) - $this.Save() - } - } - - [System.Collections.Hashtable] GetAll() { - return $this.Settings - } - - # NEU: Holt die Menüstruktur - [System.Array] GetMenuStructure() { - if ($this.Settings.ContainsKey("MenuStructure")) { - # Konvertiere PSCustomObject zurück zu Hashtable - return $this.ConvertToHashtable($this.Settings["MenuStructure"]) - } - return $this.GetDefaultMenuStructure() - } - - # NEU: Setzt eine neue Menüstruktur - [void] SetMenuStructure([System.Array]$menuStructure) { - $this.Settings["MenuStructure"] = $menuStructure - $this.Save() - } - - # NEU: Setzt Menü auf Standard zurück - [void] ResetMenuStructure() { - $this.Settings["MenuStructure"] = $this.GetDefaultMenuStructure() - $this.Save() - } - - # Hilfsfunktion: Konvertiert PSCustomObject zu Hashtable (für JSON-Deserialisierung) - hidden [object] ConvertToHashtable([object]$obj) { - if ($obj -is [System.Management.Automation.PSCustomObject]) { - $hash = @{} - foreach ($property in $obj.PSObject.Properties) { - $hash[$property.Name] = $this.ConvertToHashtable($property.Value) - } - return $hash - } - elseif ($obj -is [System.Array] -or $obj -is [System.Collections.ArrayList]) { - $array = @() - foreach ($item in $obj) { - $array += $this.ConvertToHashtable($item) - } - return $array - } - else { - return $obj - } - } - } - - class StateManager { - [System.Collections.Hashtable] $State = @{} - [System.Collections.ArrayList] $Buttons = @() - [System.Collections.Hashtable] $MenuItems = @{} - [System.Collections.ArrayList] $Forms = @() - - # Registriert einen Button mit seiner Bedingung - [void] RegisterButton([ButtonBuilder]$buttonBuilder) { - $this.Buttons.Add($buttonBuilder) | Out-Null - } - - # NEU: Registriert ein Menü-Item - [void] RegisterMenuItem([string]$menuName, [MenuBuilder]$menuBuilder) { - $this.MenuItems[$menuName] = $menuBuilder - } - - # Registriert einen Button mit seiner Bedingung - [void] RegisterForm([System.Object]$form) { - $this.Forms.Add($form) | Out-Null - } - - # Setzt einen State-Wert und aktualisiert alle Buttons und Menüs - [void] SetState([string]$key, [object]$value) { - $this.State[$key] = $value - $this.UpdateAll() - } - - [void] SetStates([hashtable]$states) { - foreach ($key in $states.Keys) { - $this.State[$key] = $states[$key] - } - $this.UpdateAll() - } - - # Holt einen State-Wert - [object] GetState([string]$key) { - return $this.State[$key] - } - - [hashtable] GetAllStates() { - return $this.State.Clone() - } - - # Aktualisiert alle registrierten Buttons - [void] UpdateAllButtons() { - foreach ($button in $this.Buttons) { - $button.UpdateEnabledState() - } - } - - # NEU: Aktualisiert alle registrierten Menü-Items - [void] UpdateAllMenuItems() { - foreach ($menuName in $this.MenuItems.Keys) { - $this.MenuItems[$menuName].UpdateMenuItemState($menuName) - } - } - - # Aktualisiert alle registrierten Buttons - [void] UpdateAllForms() { - foreach ($form in $this.Forms) { - $form.UpdateVisibleState() - } - } - - # NEU: Aktualisiert alles (Buttons + Menüs) - [void] UpdateAll() { - $this.UpdateAllButtons() - $this.UpdateAllMenuItems() - $this.UpdateAllForms() - } - } - - class LogManager { - [System.String]$LogPath - [bool]$EnableConsole = $false - - LogManager([System.String]$appName) { - $appDataPath = [Environment]::GetFolderPath('ApplicationData') - $logFolder = Join-Path $appDataPath "$appName\Logs" - - if (-not (Test-Path $logFolder)) { - New-Item -Path $logFolder -ItemType Directory -Force | Out-Null - } - - $timestamp = Get-Date -Format "yyyyMMdd" - $this.LogPath = Join-Path $logFolder "log_$timestamp.txt" - } - - [void] Info([string]$message) { - $this.Write("INFO", $message) - } - - [void] Warning([string]$message) { - $this.Write("WARN", $message) - } - - [void] Error([string]$message) { - $this.Write("ERROR", $message) - } - - hidden [void] Write([string]$level, [string]$message) { - $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" - $logLine = "[$timestamp] [$level] $message" - - Add-Content -Path $this.LogPath -Value $logLine - - if ($this.EnableConsole) { - Write-Host $logLine - } - } - } - - class AccessibilityManager { - [SettingsManager] $SettingsManager - [LogManager] $LogManager - [System.Collections.ArrayList] $FontControls = @() - [System.Collections.ArrayList] $Forms = @() - [System.Collections.ArrayList] $LayoutContainers = @() - [hashtable] $AccessibilitySettings = @{} - - - AccessibilityManager([SettingsManager]$SettingsManager, [LogManager]$LogManager) { - $this.SettingsManager = $SettingsManager - $this.LogManager = $LogManager - $this.InitializeDefaults() - } - - # Initialisiert Standard-Accessibility-Einstellungen - [void] InitializeDefaults() { - $this.AccessibilitySettings = @{ - FontSize = @{ Min = 6; Max = 32; Default = 9; Step = 1 } - FontSizeStep = @{ Min = 1; Max = 5; Default = 1 } - HighContrast = @{ Default = $false } - KeyboardShortcuts = @{ Default = $true } - ScreenReaderSupport = @{ Default = $false } - } - - # Stelle sicher, dass alle Settings existieren - foreach ($key in $this.AccessibilitySettings.Keys) { - if (-not $this.SettingsManager.Contains($key)) { - $this.SettingsManager.Set($key, $this.AccessibilitySettings[$key].Default) - } - } - } - - # Registriert ein Form für Accessibility-Features - [void] RegisterForm([System.Windows.Forms.Form]$form) { - if (-not $this.Forms.Contains($form)) { - $this.Forms.Add($form) | Out-Null - $this.AttachMouseWheelHandler($form) - $this.AttachKeyboardShortcuts($form) - $this.LogManager.Info("Form registriert für Accessibility-Features") - } - } - - # Registriert Container für automatisches Layout-Update - [void] RegisterLayoutContainer([System.Windows.Forms.Control]$container) { - if (-not $this.LayoutContainers.Contains($container)) { - $this.LayoutContainers.Add($container) | Out-Null - $this.LogManager.Info("Layout-Container registriert: $($container.GetType().Name)") - } - } - - # Registriert ein Control für Font-Updates - [void] RegisterFontControl([System.Windows.Forms.Control]$control) { - if (-not $this.FontControls.Contains($control)) { - $this.FontControls.Add($control) | Out-Null - $this.ApplyFontSize($control) - } - } - - # Registriert mehrere Controls - [void] RegisterFontControls([System.Windows.Forms.Control[]]$controls) { - foreach ($control in $controls) { - $this.RegisterFontControl($control) - } - } - - # Registriert alle Controls eines Forms/Containers rekursiv - [void] RegisterAllControls([System.Windows.Forms.Control]$container) { - # Registriere das Container-Control selbst (wenn es Text hat) - if ($container.GetType().GetProperty("Font") -ne $null) { - $this.RegisterFontControl($container) - } - - # Durchlaufe alle Child-Controls rekursiv - foreach ($control in $container.Controls) { - $this.RegisterAllControls($control) - } - - $this.LogManager.Info("Alle Controls von '$($container.GetType().Name)' registriert (Total: $($this.FontControls.Count))") - } - - # Optional: Registriert nur bestimmte Control-Typen - [void] RegisterControlsByType([System.Windows.Forms.Control]$container, [Type[]]$types) { - foreach ($control in $container.Controls) { - if ($types -contains $control.GetType()) { - $this.RegisterFontControl($control) - } - # Rekursiv durch Child-Controls - if ($control.Controls.Count -gt 0) { - $this.RegisterControlsByType($control, $types) - } - } - } - - # Fügt MouseWheel-Handler für Strg + Mausrad hinzu - hidden [void] AttachMouseWheelHandler([System.Windows.Forms.Form]$form) { - $form.Add_MouseWheel({ - param($sender, $e) - - if ([System.Windows.Forms.Control]::ModifierKeys -eq [System.Windows.Forms.Keys]::Control) { - $delta = if ($e.Delta -gt 0) { 1 } else { -1 } - [BaseComponent]::AccessibilityManager.ChangeFontSize($delta) - $e.Handled = $true - } - }.GetNewClosure()) - } - - # Fügt Tastatur-Shortcuts hinzu - hidden [void] AttachKeyboardShortcuts([System.Windows.Forms.Form]$form) { - $form.KeyPreview = $true - $form.Add_KeyDown({ - param($sender, $e) - - # Strg + 0: Reset auf Standard - if ($e.Control -and $e.KeyCode -eq [System.Windows.Forms.Keys]::D0) { - [BaseComponent]::AccessibilityManager.ResetFontSize() - $e.Handled = $true - } - - # Strg + Plus: Größer - if ($e.Control -and ($e.KeyCode -eq [System.Windows.Forms.Keys]::Add -or $e.KeyCode -eq [System.Windows.Forms.Keys]::Oemplus)) { - [BaseComponent]::AccessibilityManager.ChangeFontSize(1) - $e.Handled = $true - } - - # Strg + Minus: Kleiner - if ($e.Control -and ($e.KeyCode -eq [System.Windows.Forms.Keys]::Subtract -or $e.KeyCode -eq [System.Windows.Forms.Keys]::OemMinus)) { - [BaseComponent]::AccessibilityManager.ChangeFontSize(-1) - $e.Handled = $true - } - - # F11: High Contrast Toggle (optional) - if ($e.KeyCode -eq [System.Windows.Forms.Keys]::F11) { - [BaseComponent]::AccessibilityManager.ToggleHighContrast() - $e.Handled = $true - } - }.GetNewClosure()) - } - - # Ändert die Schriftgröße - [void] ChangeFontSize([int]$delta) { - $settings = $this.AccessibilitySettings["FontSize"] - $currentSize = $this.SettingsManager.Get("FontSize", $settings.Default) - $step = $this.SettingsManager.Get("FontSizeStep", 1) - $newSize = $currentSize + ($delta * $step) - - # Begrenzung - if ($newSize -lt $settings.Min) { $newSize = $settings.Min } - if ($newSize -gt $settings.Max) { $newSize = $settings.Max } - - if ($newSize -ne $currentSize) { - $this.SettingsManager.Set("FontSize", $newSize) - $this.UpdateAllFonts() - $this.LogManager.Info("Schriftgröße geändert: $currentSize -> $newSize") - } - } - - # Setzt Schriftgröße zurück - [void] ResetFontSize() { - $defaultSize = $this.AccessibilitySettings["FontSize"].Default - $this.SettingsManager.Set("FontSize", $defaultSize) - $this.UpdateAllFonts() - $this.LogManager.Info("Schriftgröße zurückgesetzt auf: $defaultSize") - } - - # Wendet Schriftgröße auf ein Control an - hidden [void] ApplyFontSize([System.Windows.Forms.Control]$control) { - $fontSize = $this.SettingsManager.Get("FontSize", 9) - try { - $control.Font = New-Object System.Drawing.Font($control.Font.FontFamily, $fontSize) - } catch { - $this.LogManager.Warning("Fehler beim Setzen der Schriftgröße für Control: $_") - } - } - - # Aktualisiert alle registrierten Controls - [void] UpdateAllFonts() { - foreach ($control in $this.FontControls) { - if ($null -ne $control -and -not $control.IsDisposed) { - $this.ApplyFontSize($control) - } - } - $this.UpdateAllLayouts() - } - - # Aktualisiert das Layout aller registrierten Container - hidden [void] UpdateAllLayouts() { - foreach ($container in $this.LayoutContainers) { - if ($null -ne $container -and -not $container.IsDisposed) { - # GroupBoxes: AutoSize aktivieren - if ($container -is [System.Windows.Forms.GroupBox]) { - $container.AutoSize = $true - $container.AutoSizeMode = 'GrowAndShrink' - } - - # FlowLayoutPanel: PerformLayout erzwingen - if ($container -is [System.Windows.Forms.FlowLayoutPanel]) { - foreach ($child in $container.Controls) { - if ($child -is [System.Windows.Forms.GroupBox]) { - $child.AutoSize = $true - $child.AutoSizeMode = 'GrowAndShrink' - - # Breite anpassen - $child.Width = $container.ClientSize.Width - 20 - } - } - - $container.PerformLayout() - $container.Refresh() - } - - # Panel: PerformLayout - if ($container -is [System.Windows.Forms.Panel]) { - $container.PerformLayout() - } - } - } - - $this.LogManager.Info("Layout-Update abgeschlossen") - } - - # Schaltet High Contrast Modus um - [void] ToggleHighContrast() { - $currentState = $this.SettingsManager.Get("HighContrast", $false) - $newState = -not $currentState - $this.SettingsManager.Set("HighContrast", $newState) - $this.ApplyHighContrast($newState) - $this.LogManager.Info("High Contrast: $newState") - } - - # Wendet High Contrast auf alle Forms an - hidden [void] ApplyHighContrast([bool]$enabled) { - foreach ($form in $this.Forms) { - if ($null -ne $form -and -not $form.IsDisposed) { - if ($enabled) { - # Form-Hintergrund - $form.BackColor = [System.Drawing.Color]::Black - $form.ForeColor = [System.Drawing.Color]::White - - # NEU: Rekursiv alle Controls anpassen - $this.ApplyHighContrastToControls($form, $enabled) - } else { - $form.BackColor = [System.Drawing.SystemColors]::Control - $form.ForeColor = [System.Drawing.SystemColors]::ControlText - - # NEU: Rekursiv alle Controls zurücksetzen - $this.ApplyHighContrastToControls($form, $enabled) - } - } - } - } - - # NEU: Wendet High Contrast rekursiv auf alle Controls an - hidden [void] ApplyHighContrastToControls([System.Windows.Forms.Control]$control, [bool]$enabled) { - if ($enabled) { - # Schwarzer Hintergrund → Weiße Schrift - switch ($control.GetType().Name) { - 'Panel' { - $control.BackColor = [System.Drawing.Color]::Black - $control.ForeColor = [System.Drawing.Color]::White - } - 'FlowLayoutPanel' { - $control.BackColor = [System.Drawing.Color]::Black - $control.ForeColor = [System.Drawing.Color]::White - } - 'GroupBox' { - $control.BackColor = [System.Drawing.Color]::Black - $control.ForeColor = [System.Drawing.Color]::White - } - 'Label' { - $control.ForeColor = [System.Drawing.Color]::White - # Transparent oder schwarz - if ($control.BackColor -ne [System.Drawing.Color]::Transparent) { - $control.BackColor = [System.Drawing.Color]::Black - } - } - 'Button' { - $control.BackColor = [System.Drawing.Color]::FromArgb(40, 40, 40) - $control.ForeColor = [System.Drawing.Color]::White - $control.FlatStyle = 'Flat' - } - 'TextBox' { - $control.BackColor = [System.Drawing.Color]::FromArgb(30, 30, 30) - $control.ForeColor = [System.Drawing.Color]::White - } - 'TreeView' { - $control.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 20) - $control.ForeColor = [System.Drawing.Color]::White - } - 'ListBox' { - $control.BackColor = [System.Drawing.Color]::FromArgb(20, 20, 20) - $control.ForeColor = [System.Drawing.Color]::White - } - 'DataGridView' { - $control.BackgroundColor = [System.Drawing.Color]::Black - $control.ForeColor = [System.Drawing.Color]::White - $control.DefaultCellStyle.BackColor = [System.Drawing.Color]::FromArgb(30, 30, 30) - $control.DefaultCellStyle.ForeColor = [System.Drawing.Color]::White - $control.ColumnHeadersDefaultCellStyle.BackColor = [System.Drawing.Color]::FromArgb(50, 50, 50) - $control.ColumnHeadersDefaultCellStyle.ForeColor = [System.Drawing.Color]::White - } - 'TabControl' { - $control.BackColor = [System.Drawing.Color]::Black - $control.ForeColor = [System.Drawing.Color]::White - } - 'TabPage' { - $control.BackColor = [System.Drawing.Color]::Black - $control.ForeColor = [System.Drawing.Color]::White - } - } - } else { - # Zurück zu Standard-Farben - switch ($control.GetType().Name) { - 'Panel' { - $control.BackColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - } - 'FlowLayoutPanel' { - $control.BackColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - } - 'GroupBox' { - $control.BackColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - } - 'Label' { - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - if ($control.BackColor -ne [System.Drawing.Color]::Transparent) { - $control.BackColor = [System.Drawing.SystemColors]::Control - } - } - 'Button' { - $control.BackColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - $control.FlatStyle = 'Standard' - } - 'TextBox' { - $control.BackColor = [System.Drawing.SystemColors]::Window - $control.ForeColor = [System.Drawing.SystemColors]::WindowText - } - 'TreeView' { - $control.BackColor = [System.Drawing.SystemColors]::Window - $control.ForeColor = [System.Drawing.SystemColors]::WindowText - } - 'ListBox' { - $control.BackColor = [System.Drawing.SystemColors]::Window - $control.ForeColor = [System.Drawing.SystemColors]::WindowText - } - 'DataGridView' { - $control.BackgroundColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - $control.DefaultCellStyle.BackColor = [System.Drawing.SystemColors]::Window - $control.DefaultCellStyle.ForeColor = [System.Drawing.SystemColors]::WindowText - $control.ColumnHeadersDefaultCellStyle.BackColor = [System.Drawing.SystemColors]::Control - $control.ColumnHeadersDefaultCellStyle.ForeColor = [System.Drawing.SystemColors]::ControlText - } - 'TabControl' { - $control.BackColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - } - 'TabPage' { - $control.BackColor = [System.Drawing.SystemColors]::Control - $control.ForeColor = [System.Drawing.SystemColors]::ControlText - } - } - } - - # Rekursiv für alle Child-Controls - foreach ($child in $control.Controls) { - $this.ApplyHighContrastToControls($child, $enabled) - } - } - - # Gibt aktuelle Accessibility-Einstellungen zurück - [hashtable] GetCurrentSettings() { - return @{ - FontSize = $this.SettingsManager.Get("FontSize", 9) - HighContrast = $this.SettingsManager.Get("HighContrast", $false) - KeyboardShortcuts = $this.SettingsManager.Get("KeyboardShortcuts", $true) - } - } - - # Setzt eine spezifische Accessibility-Einstellung - [void] SetAccessibilitySetting([string]$key, [object]$value) { - $this.SettingsManager.Set($key, $value) - - # Wende Änderung sofort an - switch ($key) { - "FontSize" { $this.UpdateAllFonts() } - "HighContrast" { $this.ApplyHighContrast($value) } - } - } - } - - class FormBuilder : BaseComponent { - - [System.String] $Title - [System.Windows.Forms.Form] $Form - [MenuBuilder] $Menu - [StatusStripBuilder] $StatusBar - - - FormBuilder($Title){ - $this.Form = New-Object System.Windows.Forms.Form - $this.Form.Text = $Title - $this.Form.StartPosition = "CenterScreen" - - # HIER wird RegisterForm automatisch aufgerufen: - [BaseComponent]::AccessibilityManager.RegisterForm($this.Form) - } - - # Registriert ein Control für Accessibility-Features - [FormBuilder] RegisterAccessibleControl([System.Windows.Forms.Control]$control) { - [BaseComponent]::AccessibilityManager.RegisterFontControl($control) - return $this - } - - # Registriert mehrere Controls - [FormBuilder] RegisterAccessibleControls([System.Windows.Forms.Control[]]$controls) { - [BaseComponent]::AccessibilityManager.RegisterFontControls($controls) - return $this - } - - # NEU: Registriert automatisch ALLE Controls des Forms - [FormBuilder] RegisterAllAccessibleControls() { - [BaseComponent]::AccessibilityManager.RegisterAllControls($this.Form) - return $this - } - - # NEU: Registriert nur bestimmte Control-Typen (z.B. nur TextBoxen und Labels) - [FormBuilder] RegisterAccessibleControlsByType([Type[]]$types) { - [BaseComponent]::AccessibilityManager.RegisterControlsByType($this.Form, $types) - return $this - } - - [FormBuilder] AddMenu([MenuBuilder]$menuBuilder) { - $this.Menu = $menuBuilder - $this.Form.Controls.Add($menuBuilder.GetMenuStrip()) - return $this - } - - # Fügt eine StatusBar hinzu - [FormBuilder] AddStatusBar([StatusStripBuilder]$statusBar) { - $this.StatusBar = $statusBar - $this.Form.Controls.Add($statusBar.GetStatusStrip()) - return $this - } - - # Fügt ein SplitPanel hinzu - [FormBuilder] AddSplitPanel([SplitPanelBuilder]$splitPanel) { - $this.Form.Controls.Add($splitPanel.GetSplitContainer()) - return $this - } - - # Fügt ein beliebiges Control hinzu - [FormBuilder] AddControl([System.Windows.Forms.Control]$control) { - $this.Form.Controls.Add($control) - return $this - } - - # Fügt mehrere Controls hinzu - [FormBuilder] AddControls([System.Windows.Forms.Control[]]$controls) { - foreach ($control in $controls) { - $this.Form.Controls.Add($control) - } - return $this - } - - [void] SetTitle($Title) { - $this.Form.Text = $Title - } - - # Setzt die Größe des Forms - [FormBuilder] SetSize([int]$width, [int]$height) { - $this.Form.Size = New-Object System.Drawing.Size($width, $height) - return $this - } - - # Setzt nur die Breite - [FormBuilder] SetWidth([int]$width) { - $this.Form.Width = $width - return $this - } - - # Setzt nur die Höhe - [FormBuilder] SetHeight([int]$height) { - $this.Form.Height = $height - return $this - } - - # Setzt die Mindestgröße - [FormBuilder] SetMinimumSize([int]$width, [int]$height) { - $this.Form.MinimumSize = New-Object System.Drawing.Size($width, $height) - return $this - } - - # Setzt die Maximalgröße - [FormBuilder] SetMaximumSize([int]$width, [int]$height) { - $this.Form.MaximumSize = New-Object System.Drawing.Size($width, $height) - return $this - } - - # Setzt die Startposition - [FormBuilder] SetStartPosition([System.String]$position) { - $this.Form.StartPosition = [System.Windows.Forms.FormStartPosition]::$position - return $this - } - - # Setzt die Location (Position auf dem Bildschirm) - [FormBuilder] SetLocation([int]$x, [int]$y) { - $this.Form.Location = New-Object System.Drawing.Point($x, $y) - return $this - } - - # Setzt den WindowState - [FormBuilder] SetWindowState([System.String]$state) { - $this.Form.WindowState = [System.Windows.Forms.FormWindowState]::$state - return $this - } - - [FormBuilder] AddLoadHandler([scriptblock]$handler) { - $this.Form.Add_Load($handler) - return $this - } - - # Shown Event (wenn Form zum ersten Mal angezeigt wird) - [FormBuilder] AddShownHandler([scriptblock]$handler) { - $this.Form.Add_Shown($handler) - return $this - } - - # FormClosing Event (bevor Form geschlossen wird - kann abgebrochen werden) - [FormBuilder] AddFormClosingHandler([scriptblock]$handler) { - $this.Form.Add_FormClosing($handler) - return $this - } - - # FormClosed Event (nachdem Form geschlossen wurde) - [FormBuilder] AddFormClosedHandler([scriptblock]$handler) { - $this.Form.Add_FormClosed($handler) - return $this - } - - # Resize Event - [FormBuilder] AddResizeHandler([scriptblock]$handler) { - $this.Form.Add_Resize($handler) - return $this - } - - # Move Event - [FormBuilder] AddMoveHandler([scriptblock]$handler) { - $this.Form.Add_Move($handler) - return $this - } - - # KeyDown Event - [FormBuilder] AddKeyDownHandler([scriptblock]$handler) { - $this.Form.Add_KeyDown($handler) - return $this - } - - # Activate Event (wenn Form aktiviert wird) - [FormBuilder] AddActivateHandler([scriptblock]$handler) { - $this.Form.Add_Activated($handler) - return $this - } - - # Deactivate Event - [FormBuilder] AddDeactivateHandler([scriptblock]$handler) { - $this.Form.Add_Deactivate($handler) - return $this - } - - # Generischer Event-Handler für alle Events - [FormBuilder] AddEventHandler([System.String]$eventName, [scriptblock]$handler) { - $this.Form."Add_$eventName"($handler) - return $this - } - - [void] Show(){ - [void]$this.Form.ShowDialog() - } - } - - class MenuBuilder : BaseComponent{ - - [System.Windows.Forms.MenuStrip] $MenuStrip - [System.Collections.Hashtable] $MenuItems = @{} - [System.Collections.Hashtable] $MenuConditions = @{} - [StateManager] $StateManager = $null - - MenuBuilder() { - $this.MenuStrip = New-Object System.Windows.Forms.MenuStrip - $this.MenuStrip.Dock = 'Top' - } - - # NEU: Setzt den StateManager - [MenuBuilder] WithStateManager([StateManager]$stateManager) { - $this.StateManager = $stateManager - return $this - } - - # Fügt ein Hauptmenü-Element hinzu - JETZT MIT RETURN - [MenuBuilder] AddMainMenu([System.String]$name, [System.String]$text) { - $menuItem = New-Object System.Windows.Forms.ToolStripMenuItem $text - $this.MenuStrip.Items.Add($menuItem) | Out-Null - $this.MenuItems[$name] = $menuItem - return $this | Out-Null - } - - # Fügt ein Untermenü-Element hinzu - JETZT MIT RETURN - [MenuBuilder] AddSubMenu([System.String]$parentName, [System.String]$name, [System.String]$text) { - if ($this.MenuItems.ContainsKey($parentName)) { - $menuItem = New-Object System.Windows.Forms.ToolStripMenuItem $text - $this.MenuItems[$parentName].DropDownItems.Add($menuItem) | Out-Null - $this.MenuItems[$name] = $menuItem - return $this | Out-Null - } - throw "Parent menu '$parentName' nicht gefunden" - } - - # NEU: Fügt mehrere Untermenüs auf einmal hinzu - [MenuBuilder] AddSubMenus([System.String]$parentName, [hashtable[]]$items) { - foreach ($item in $items) { - if ($item.Type -eq "Separator") { - $this.AddSeparator($parentName) - } - else { - $this.AddSubMenu($parentName, $item.Name, $item.Text) - if ($item.Handler) { - $this.SetClickHandler($item.Name, $item.Handler) - } - } - } - return $this - } - - # NEU: Erstellt komplettes Menü aus einer Struktur - [MenuBuilder] BuildFromStructure([hashtable[]]$structure) { - foreach ($mainMenu in $structure) { - $this.AddMainMenu($mainMenu.Name, $mainMenu.Text) - - if ($mainMenu.Items) { - $this.AddSubMenus($mainMenu.Name, $mainMenu.Items) - } - } - return $this - } - - # Fügt einen Separator hinzu - JETZT MIT RETURN - [MenuBuilder] AddSeparator([System.String]$parentName) { - if ($this.MenuItems.ContainsKey($parentName)) { - $this.MenuItems[$parentName].DropDownItems.Add('-') | Out-Null - } - return $this | Out-Null - } - - # Setzt einen Event-Handler für ein Menü-Element - JETZT MIT RETURN - [MenuBuilder] SetClickHandler([System.String]$menuName, [scriptblock]$handler) { - if ($this.MenuItems.ContainsKey($menuName)) { - $this.MenuItems[$menuName].Add_Click($handler) - } - return $this | Out-Null - } - - # NEU: Setzt einen Click-Handler mit Enable-Bedingung - [MenuBuilder] SetClickHandler([System.String]$menuName, [scriptblock]$handler, [scriptblock]$enableCondition) { - if ($this.MenuItems.ContainsKey($menuName)) { - $this.MenuItems[$menuName].Add_Click($handler) - $this.MenuConditions[$menuName] = $enableCondition - - # Initial den Status setzen - $this.UpdateMenuItemState($menuName) - - # Bei StateManager registrieren - if ($null -ne $this.StateManager) { - $this.StateManager.RegisterMenuItem($menuName, $this) - } - } - return $this | Out-Null - } - - # NEU: Setzt mehrere Click-Handler auf einmal - [MenuBuilder] SetClickHandlers([System.Collections.Hashtable]$handlers) { - foreach ($key in $handlers.Keys) { - $this.SetClickHandler($key, $handlers[$key]) - } - return $this | Out-Null - } - - # NEU: Setzt mehrere Click-Handler mit Bedingungen - [MenuBuilder] SetClickHandlersWithConditions([System.Collections.Hashtable]$handlers) { - foreach ($key in $handlers.Keys) { - $config = $handlers[$key] - if ($config.Condition) { - $this.SetClickHandler($key, $config.Handler, $config.Condition) - } else { - $this.SetClickHandler($key, $config.Handler) - } - } - return $this | Out-Null - } - - # NEU: Aktualisiert den Enabled-Status eines Menü-Items - [void] UpdateMenuItemState([System.String]$menuName) { - if ($this.MenuItems.ContainsKey($menuName) -and $this.MenuConditions.ContainsKey($menuName)) { - try { - $result = & $this.MenuConditions[$menuName] - $this.MenuItems[$menuName].Enabled = [bool]$result - } catch { - Write-Warning "Fehler beim Evaluieren der Menu-Bedingung für '$menuName': $_" - $this.MenuItems[$menuName].Enabled = $false - } - } - } - - # NEU: Aktualisiert alle Menü-Items mit Bedingungen - [void] UpdateAllMenuItems() { - foreach ($menuName in $this.MenuConditions.Keys) { - $this.UpdateMenuItemState($menuName) - } - } - - # Gibt das MenuStrip-Objekt zurück - [System.Windows.Forms.MenuStrip] GetMenuStrip() { - return $this.MenuStrip - } - - # Aktiviert/Deaktiviert ein Menü-Element - JETZT MIT RETURN - [MenuBuilder] SetEnabled([System.String]$menuName, [bool]$enabled) { - if ($this.MenuItems.ContainsKey($menuName)) { - $this.MenuItems[$menuName].Enabled = $enabled - } - return $this - } - - # NEU: Holt ein Menü-Item - [System.Windows.Forms.ToolStripMenuItem] GetMenuItem([System.String]$menuName) { - if ($this.MenuItems.ContainsKey($menuName)) { - return $this.MenuItems[$menuName] - } - return $null - } - } - - class StatusStripBuilder : BaseComponent{ - [System.Windows.Forms.StatusStrip] $StatusStrip - [System.Collections.Hashtable] $Labels = @{} - - StatusStripBuilder() { - $this.StatusStrip = New-Object System.Windows.Forms.StatusStrip - } - - # Fügt ein Label zur StatusBar hinzu - [System.Windows.Forms.ToolStripStatusLabel] AddLabel([System.String]$name, [System.String]$text) { - $label = New-Object System.Windows.Forms.ToolStripStatusLabel - $label.Text = $text - $this.StatusStrip.Items.Add($label) | Out-Null - $this.Labels[$name] = $label - return $label - } - - # Fügt ein Label mit Spring-Eigenschaft hinzu (füllt verfügbaren Platz) - [System.Windows.Forms.ToolStripStatusLabel] AddSpringLabel([System.String]$name, [System.String]$text) { - $label = New-Object System.Windows.Forms.ToolStripStatusLabel - $label.Text = $text - $label.Spring = $true - $label.TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft - $this.StatusStrip.Items.Add($label) | Out-Null - $this.Labels[$name] = $label - return $label - } - - # Setzt den Text eines Labels - [void] SetText([System.String]$labelName, [System.String]$text) { - if ($this.Labels.ContainsKey($labelName)) { - $this.Labels[$labelName].Text = $text - } - } - - # Fügt einen Separator hinzu - [void] AddSeparator() { - $separator = New-Object System.Windows.Forms.ToolStripSeparator - $this.StatusStrip.Items.Add($separator) | Out-Null - } - - # Fügt eine ProgressBar hinzu - [System.Windows.Forms.ToolStripProgressBar] AddProgressBar([System.String]$name) { - $progressBar = New-Object System.Windows.Forms.ToolStripProgressBar - $progressBar.Size = New-Object System.Drawing.Size(100, 16) - $this.StatusStrip.Items.Add($progressBar) | Out-Null - $this.Labels[$name] = $progressBar - return $progressBar - } - - # Setzt den Fortschritt einer ProgressBar - [void] SetProgress([System.String]$progressBarName, [int]$value) { - if ($this.Labels.ContainsKey($progressBarName)) { - $this.Labels[$progressBarName].Value = $value - } - } - - # Gibt das StatusStrip-Objekt zurück - [System.Windows.Forms.StatusStrip] GetStatusStrip() { - return $this.StatusStrip - } - - # Zeigt/Versteckt ein Element - [void] SetVisible([System.String]$itemName, [bool]$visible) { - if ($this.Labels.ContainsKey($itemName)) { - $this.Labels[$itemName].Visible = $visible - } - } - - # Setzt die Hintergrundfarbe eines Labels - [void] SetBackColor([System.String]$labelName, [System.Drawing.Color]$color) { - if ($this.Labels.ContainsKey($labelName)) { - $this.Labels[$labelName].BackColor = $color - } - } - - # Setzt die Textfarbe eines Labels - [void] SetForeColor([System.String]$labelName, [System.Drawing.Color]$color) { - if ($this.Labels.ContainsKey($labelName)) { - $this.Labels[$labelName].ForeColor = $color - } - } - } - - class SplitPanelBuilder : BaseComponent{ - [System.Windows.Forms.SplitContainer] $SplitContainer - - [Int] $DesiredPanel1MinSize = 100 - [Int] $DesiredPanel2MinSize = 250 - [Int] $DesiredSplitterDistance = 200 - [Double] $SplitterDistanceRatio = 0.0 - - SplitPanelBuilder([System.String]$orientation) { - $this.SplitContainer = New-Object System.Windows.Forms.SplitContainer - $this.SplitContainer.Dock = 'Fill' - - if ($orientation -eq 'Horizontal') { - $this.SplitContainer.Orientation = 'Horizontal' - } else { - $this.SplitContainer.Orientation = 'Vertical' - } - } - - # Konstruktor mit MinSize-Optionen - Verzögerte Initialisierung - SplitPanelBuilder([System.String]$orientation, [int]$splitterDistance, [int]$panel1MinSize, [int]$panel2MinSize) { - $this.SplitContainer = New-Object System.Windows.Forms.SplitContainer - $this.SplitContainer.Dock = 'Fill' - $this.SplitContainer.Orientation = $orientation - - # Speichere die gewünschten Werte für spätere Initialisierung - $this.DesiredPanel1MinSize = $panel1MinSize - $this.DesiredPanel2MinSize = $panel2MinSize - $this.DesiredSplitterDistance = $splitterDistance - - # Setze nur die absolut notwendigen Anfangswerte - $this.SplitContainer.Panel1MinSize = [Math]::Min($panel1MinSize, 25) - $this.SplitContainer.Panel2MinSize = 25 - } - - # Konstruktor mit Verhältnis (Ratio) für SplitterDistance - SplitPanelBuilder([System.String]$orientation, [double]$splitterRatio, [int]$panel1MinSize, [int]$panel2MinSize) { - $this.SplitContainer = New-Object System.Windows.Forms.SplitContainer - $this.SplitContainer.Dock = 'Fill' - $this.SplitContainer.Orientation = $orientation - - # Speichere die gewünschten Werte - $this.DesiredPanel1MinSize = $panel1MinSize - $this.DesiredPanel2MinSize = $panel2MinSize - $this.SplitterDistanceRatio = $splitterRatio - - # Setze nur die absolut notwendigen Anfangswerte - $this.SplitContainer.Panel1MinSize = [Math]::Min($panel1MinSize, 25) - $this.SplitContainer.Panel2MinSize = 25 - } - - # Initialisiert den SplitContainer mit den finalen Werten (nach Form.Shown) - [void] InitializeAfterShown([System.Windows.Forms.Form]$form) { - # Bestimme verfügbare Breite/Höhe aus dem SplitContainer selbst - $availableSize = if ($this.SplitContainer.Orientation -eq 'Vertical') { - $this.SplitContainer.Width - } else { - $this.SplitContainer.Height - } - - # Sicherheitscheck: Mindestgröße - if ($availableSize -lt 100) { - Write-Warning "SplitContainer zu klein: $availableSize px. Verwende ClientSize." - $availableSize = if ($this.SplitContainer.Orientation -eq 'Vertical') { - $form.ClientSize.Width - } else { - $form.ClientSize.Height - } - } - - # Panel2MinSize anpassen falls nötig - $proposedPanel2 = $this.DesiredPanel2MinSize - $maxAllowed = $availableSize - $this.DesiredPanel1MinSize - $this.SplitContainer.SplitterWidth - - if ($maxAllowed -lt 25) { - # Nicht genug Platz - verwende Minimalkonfiguration - $this.SplitContainer.Panel1MinSize = 25 - $this.SplitContainer.Panel2MinSize = 25 - $this.SplitContainer.SplitterDistance = 25 - Write-Warning "Nicht genug Platz für gewünschte MinSizes. Verwende Minimalwerte." - return - } - - if ($proposedPanel2 -gt $maxAllowed) { - $proposedPanel2 = [Math]::Max(25, [int]($maxAllowed / 2)) - } - - # Panel1MinSize setzen - $this.SplitContainer.Panel1MinSize = $this.DesiredPanel1MinSize - - # Panel2MinSize setzen - $this.SplitContainer.Panel2MinSize = $proposedPanel2 - - # SplitterDistance berechnen und setzen - if ($this.SplitterDistanceRatio -gt 0) { - # Wenn Ratio angegeben wurde - $desired = [int]($availableSize * $this.SplitterDistanceRatio) - } else { - # Wenn fester Wert angegeben wurde - $desired = $this.DesiredSplitterDistance - } - - # Validierung mit strengeren Grenzen - $minAllowed = $this.SplitContainer.Panel1MinSize - $maxAllowed = $availableSize - $this.SplitContainer.Panel2MinSize - $this.SplitContainer.SplitterWidth - - if ($desired -lt $minAllowed) { - $desired = $minAllowed - } - if ($desired -gt $maxAllowed) { - $desired = $maxAllowed - } - - # Finale Sicherheitsprüfung - if ($desired -lt 1) { - $desired = $minAllowed - } - - $this.SplitContainer.SplitterDistance = $desired - } - - # Setzt Padding für Panel mit Berücksichtigung der Menühöhe - [void] SetPanelPaddingWithMenu([int]$panelNumber, [System.Windows.Forms.MenuStrip]$menu, [int]$left, [int]$right, [int]$bottom) { - try { - $menuHeight = $menu.Height - $topPadding = $menuHeight + 6 - } catch { - $topPadding = 36 # Fallback - } - - $padding = New-Object System.Windows.Forms.Padding($left, $topPadding, $right, $bottom) - - if ($panelNumber -eq 1) { - $this.SplitContainer.Panel1.Padding = $padding - } else { - $this.SplitContainer.Panel2.Padding = $padding - } - } - - [System.Windows.Forms.SplitterPanel] GetPanel1() { - return $this.SplitContainer.Panel1 - } - - # KORREKTUR: Gibt $this zurück für Fluent API - [SplitPanelBuilder] AddToPanel1([System.Windows.Forms.Control]$control) { - $this.SplitContainer.Panel1.Controls.Add($control) - return $this - } - - # KORREKTUR: Gibt $this zurück für Fluent API - [SplitPanelBuilder] ClearPanel1() { - $this.SplitContainer.Panel1.Controls.Clear() - return $this - } - - [System.Windows.Forms.SplitterPanel] GetPanel2() { - return $this.SplitContainer.Panel2 - } - - # KORREKTUR: Gibt $this zurück für Fluent API - [SplitPanelBuilder] AddToPanel2([System.Windows.Forms.Control]$control) { - $this.SplitContainer.Panel2.Controls.Add($control) - return $this - } - - # KORREKTUR: Gibt $this zurück für Fluent API - [SplitPanelBuilder] ClearPanel2() { - $this.SplitContainer.Panel2.Controls.Clear() - return $this - } - - # Berechnet die optimale SplitterDistance basierend auf den Controls in Panel1 - [void] AutoSizeSplitterToPanel1Content() { - $maxSize = 0 - - foreach ($control in $this.SplitContainer.Panel1.Controls) { - if ($this.SplitContainer.Orientation -eq 'Vertical') { - # Bei vertikaler Orientierung: Breite berechnen - $requiredSize = $control.Right + $control.Margin.Right - } else { - # Bei horizontaler Orientierung: Höhe berechnen - $requiredSize = $control.Bottom + $control.Margin.Bottom - } - - if ($requiredSize -gt $maxSize) { - $maxSize = $requiredSize - } - } - - # Padding von Panel1 berücksichtigen - if ($this.SplitContainer.Orientation -eq 'Vertical') { - $maxSize += $this.SplitContainer.Panel1.Padding.Right - } else { - $maxSize += $this.SplitContainer.Panel1.Padding.Bottom - } - - # Sicherheitsabstand hinzufügen - $maxSize += 10 - - # Mit Constraints validieren und setzen - $this.SetSplitterDistance($maxSize) - } - - # Setzt die Splitter-Position mit Validierung - [SplitPanelBuilder] SetSplitterDistance([int]$distance) { - $minDistance = $this.SplitContainer.Panel1MinSize - $maxDistance = $this.SplitContainer.Width - $this.SplitContainer.Panel2MinSize - - if ($distance -lt $minDistance) { - $this.SplitContainer.SplitterDistance = $minDistance - } - elseif ($distance -gt $maxDistance) { - $this.SplitContainer.SplitterDistance = $maxDistance - } - else { - $this.SplitContainer.SplitterDistance = $distance - } - return $this - } - - # Fixiert den Splitter - [SplitPanelBuilder] SetFixedPanel([System.String]$panel) { - switch ($panel) { - 'Panel1' { $this.SplitContainer.FixedPanel = 'Panel1' } - 'Panel2' { $this.SplitContainer.FixedPanel = 'Panel2' } - default { $this.SplitContainer.FixedPanel = 'None' } - } - return $this - } - - # Verhindert das Verschieben des Splitters - [SplitPanelBuilder] SetIsSplitterFixed([bool]$fixed) { - $this.SplitContainer.IsSplitterFixed = $fixed - return $this - } - - # Setzt die Splitter-Breite - [SplitPanelBuilder] SetSplitterWidth([int]$width) { - $this.SplitContainer.SplitterWidth = $width - return $this - } - - # Gibt das SplitContainer-Objekt zurück - [System.Windows.Forms.SplitContainer] GetSplitContainer() { - return $this.SplitContainer - } - } - - class FlowLayoutPanelBuilder { - [System.Windows.Forms.FlowLayoutPanel]$control - - FlowLayoutPanelBuilder() { - $this.control = New-Object System.Windows.Forms.FlowLayoutPanel - # Standard-Einstellungen - $this.control.Dock = 'Fill' - $this.control.AutoScroll = $true - $this.control.FlowDirection = 'TopDown' - $this.control.WrapContents = $false - } - - [FlowLayoutPanelBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [FlowLayoutPanelBuilder] SetAutoScroll([bool]$autoScroll) { - $this.control.AutoScroll = $autoScroll - return $this - } - - [FlowLayoutPanelBuilder] SetFlowDirection([System.String]$direction) { - $this.control.FlowDirection = [System.Windows.Forms.FlowDirection]::$direction - return $this - } - - [FlowLayoutPanelBuilder] SetWrapContents([bool]$wrap) { - $this.control.WrapContents = $wrap - return $this - } - - [FlowLayoutPanelBuilder] SetPadding([int]$all) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($all) - return $this - } - - [FlowLayoutPanelBuilder] SetPadding([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - [FlowLayoutPanelBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.control.BackColor = $color - return $this - } - - [FlowLayoutPanelBuilder] SetWidth([int]$width) { - $this.control.Width = $width - return $this - } - - [FlowLayoutPanelBuilder] SetHeight([int]$height) { - $this.control.Height = $height - return $this - } - - [FlowLayoutPanelBuilder] SetSize([int]$width, [int]$height) { - $this.control.Width = $width - $this.control.Height = $height - return $this - } - - [FlowLayoutPanelBuilder] SetBorderStyle([System.String]$style) { - $this.control.BorderStyle = [System.Windows.Forms.BorderStyle]::$style - return $this - } - - [FlowLayoutPanelBuilder] AddControl([System.Windows.Forms.Control]$childControl) { - $this.control.Controls.Add($childControl) - return $this - } - - [FlowLayoutPanelBuilder] AddControls([System.Windows.Forms.Control[]]$controls) { - foreach ($ctrl in $controls) { - $this.control.Controls.Add($ctrl) - } - return $this - } - - [FlowLayoutPanelBuilder] ClearControls() { - $this.control.Controls.Clear() - return $this - } - - [System.Windows.Forms.FlowLayoutPanel] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.control) - return $this.control - } - - [System.Windows.Forms.FlowLayoutPanel] Build() { - return $this.control - } - } - - class ButtonBuilder : BaseComponent { - [System.Windows.Forms.Button] $Button - [scriptblock] $EnableCondition = $null - [StateManager] $StateManager = $null - - ButtonBuilder() { - $this.Button = New-Object System.Windows.Forms.Button - $this.Button.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize")) - $this.SetSize(40, 40) - $this.Button.Margin = New-Object System.Windows.Forms.Padding(5) - } - - ButtonBuilder([System.String]$text) { - $this.Button = New-Object System.Windows.Forms.Button - $this.Button.Text = $text - $this.Button.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize")) - $this.SetSize(40, 40) - } - - # Konstruktor mit Text und Höhe - ButtonBuilder([System.String]$text, [int]$height) { - $this.Button = New-Object System.Windows.Forms.Button - $this.Button.Text = $text - $this.Button.Height = $height - $this.Button.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize")) - } - - # Setzt den Text - [ButtonBuilder] SetText([System.String]$text) { - $this.Button.Text = $text - return $this - } - - # Setzt die Höhe - [ButtonBuilder] SetHeight([int]$height) { - $this.Button.Height = $height - return $this - } - - # Setzt die Breite - [ButtonBuilder] SetWidth([int]$width) { - $this.Button.Width = $width - return $this - } - - # Setzt die Größe - [ButtonBuilder] SetSize([int]$width, [int]$height) { - $this.Button.Size = New-Object System.Drawing.Size($width, $height) - return $this - } - - # Setzt das Dock - [ButtonBuilder] SetDock([System.String]$dock) { - $this.Button.Dock = $dock - return $this - } - - # Setzt die Position - [ButtonBuilder] SetLocation([int]$x, [int]$y) { - $this.Button.Location = New-Object System.Drawing.Point($x, $y) - return $this - } - - # Setzt die Schriftart - [ButtonBuilder] SetFont([System.String]$fontFamily, [int]$fontSize) { - $this.Button.Font = New-Object System.Drawing.Font($fontFamily, $fontSize) - return $this - } - - # Setzt die Schriftart mit Stil - [ButtonBuilder] SetFont([System.String]$fontFamily, [int]$fontSize, [System.Drawing.FontStyle]$fontStyle) { - $this.Button.Font = New-Object System.Drawing.Font($fontFamily, $fontSize, $fontStyle) - return $this - } - - # Setzt die Hintergrundfarbe - [ButtonBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.Button.BackColor = $color - return $this - } - - # Setzt die Textfarbe - [ButtonBuilder] SetForeColor([System.Drawing.Color]$color) { - $this.Button.ForeColor = $color - return $this - } - - # Setzt den Enabled-Status - [ButtonBuilder] SetEnabled([bool]$enabled) { - $this.Button.Enabled = $enabled - return $this - } - - # Setzt die Sichtbarkeit - [ButtonBuilder] SetVisible([bool]$visible) { - $this.Button.Visible = $visible - return $this - } - - # Setzt das FlatStyle - [ButtonBuilder] SetFlatStyle([System.String]$style) { - switch ($style) { - 'Flat' { $this.Button.FlatStyle = 'Flat' } - 'Popup' { $this.Button.FlatStyle = 'Popup' } - 'Standard' { $this.Button.FlatStyle = 'Standard' } - 'System' { $this.Button.FlatStyle = 'System' } - } - return $this - } - - # Setzt ein MDL2-Icon - [ButtonBuilder] SetMDL2Icon([System.String]$unicodeChar) { - $this.Button.Font = New-Object System.Drawing.Font("Segoe MDL2 Assets", 14) - $this.Button.Text = $unicodeChar - return $this - } - - # Setzt ein Fluent-Icon - [ButtonBuilder] SetFluentIcon([System.String]$unicodeChar) { - $this.Button.Font = New-Object System.Drawing.Font("Segoe Fluent Icons", 14) - $this.Button.Text = $unicodeChar - return $this - } - - # NEU: Bindet Button an StateManager (ohne Bedingung) - [ButtonBuilder] WithStateManager([StateManager]$stateManager) { - $this.StateManager = $stateManager - return $this - } - - # NEU: Kombinierte Methode - Bedingung + StateManager - [ButtonBuilder] BindEnabled([scriptblock]$condition, [StateManager]$stateManager) { - $this.EnableCondition = $condition - $this.StateManager = $stateManager - $this.UpdateEnabledState() - return $this - } - - # Original-Methode - nur Bedingung, kein StateManager - [ButtonBuilder] BindEnabled([scriptblock]$condition) { - $this.EnableCondition = $condition - $this.UpdateEnabledState() - return $this - } - - # Aktualisiert den Enabled-Status basierend auf der Bedingung - [void] UpdateEnabledState() { - if ($null -ne $this.EnableCondition) { - try { - $result = & $this.EnableCondition - $this.Button.Enabled = [bool]$result - } catch { - Write-Warning "Fehler beim Evaluieren der Enable-Bedingung: $_" - $this.Button.Enabled = $false - } - } - } - - # Setzt den Click-Handler - [ButtonBuilder] SetClickHandler([scriptblock]$handler) { - $this.Button.Add_Click($handler) - return $this - } - - # Setzt einen Tooltip - [ButtonBuilder] SetToolTip([System.String]$text) { - $tooltip = New-Object System.Windows.Forms.ToolTip - $tooltip.SetToolTip($this.Button, $text) - return $this - } - - # Setzt das Anchor - [ButtonBuilder] SetAnchor([System.Windows.Forms.AnchorStyles]$anchor) { - $this.Button.Anchor = $anchor - return $this - } - - # Gibt das Button-Objekt zurück - [System.Windows.Forms.Button] GetButton() { - return $this.Button - } - - # Fügt den Button zu einem Control hinzu - [void] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.Button) - } - - # NEU: Build mit Auto-Registrierung beim StateManager - [System.Windows.Forms.Button] Build() { - # Auto-Registrierung wenn StateManager gesetzt - if ($null -ne $this.StateManager -and $null -ne $this.EnableCondition) { - $this.StateManager.RegisterButton($this) - } - return $this.Button - } - } - - class LabelBuilder : BaseComponent { - [System.Windows.Forms.Label] $Label - - LabelBuilder([System.String]$text) { - $this.Label = New-Object System.Windows.Forms.Label - $this.Label.Text = $text - $this.Label.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize")) - } - - # Konstruktor mit Text und Höhe - LabelBuilder([System.String]$text, [int]$height) { - $this.Label = New-Object System.Windows.Forms.Label - $this.Label.Text = $text - $this.Label.Height = $height - $this.Label.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize")) - } - - # Setzt den Text - [LabelBuilder] SetText([System.String]$text) { - $this.Label.Text = $text - return $this - } - - # Setzt die Höhe - [LabelBuilder] SetHeight([int]$height) { - $this.Label.Height = $height - return $this - } - - # Setzt die Breite - [LabelBuilder] SetWidth([int]$width) { - $this.Label.Width = $width - return $this - } - - # Setzt die Größe - [LabelBuilder] SetSize([int]$width, [int]$height) { - $this.Label.Size = New-Object System.Drawing.Size($width, $height) - return $this - } - - # Setzt das Dock - [LabelBuilder] SetDock([System.String]$dock) { - $this.Label.Dock = $dock - return $this - } - - # Setzt die Position - [LabelBuilder] SetLocation([int]$x, [int]$y) { - $this.Label.Location = New-Object System.Drawing.Point($x, $y) - return $this - } - - # Setzt die Schriftart - [LabelBuilder] SetFont([System.String]$fontFamily, [int]$fontSize) { - $this.Label.Font = New-Object System.Drawing.Font($fontFamily, $fontSize) - return $this - } - - # Setzt die Schriftart mit Stil - [LabelBuilder] SetFont([System.String]$fontFamily, [int]$fontSize, [System.Drawing.FontStyle]$fontStyle) { - $this.Label.Font = New-Object System.Drawing.Font($fontFamily, $fontSize, $fontStyle) - return $this - } - - # Setzt die Hintergrundfarbe - [LabelBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.Label.BackColor = $color - return $this - } - - # Setzt die Textfarbe - [LabelBuilder] SetForeColor([System.Drawing.Color]$color) { - $this.Label.ForeColor = $color - return $this - } - - # Setzt die Textausrichtung - [LabelBuilder] SetTextAlign([System.Drawing.ContentAlignment]$alignment) { - $this.Label.TextAlign = $alignment - return $this - } - - # Setzt AutoSize - [LabelBuilder] SetAutoSize([bool]$autoSize) { - $this.Label.AutoSize = $autoSize - return $this - } - - # Setzt den Enabled-Status - [LabelBuilder] SetEnabled([bool]$enabled) { - $this.Label.Enabled = $enabled - return $this - } - - # Setzt die Sichtbarkeit - [LabelBuilder] SetVisible([bool]$visible) { - $this.Label.Visible = $visible - return $this - } - - # Setzt BorderStyle - [LabelBuilder] SetBorderStyle([System.String]$style) { - switch ($style) { - 'None' { $this.Label.BorderStyle = 'None' } - 'FixedSingle' { $this.Label.BorderStyle = 'FixedSingle' } - 'Fixed3D' { $this.Label.BorderStyle = 'Fixed3D' } - } - return $this - } - - # Setzt das Padding - [LabelBuilder] SetPadding([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.Label.Padding = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - # Setzt das Margin - [LabelBuilder] SetMargin([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.Label.Margin = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - # Setzt das Padding (alle Seiten gleich) - [LabelBuilder] SetPadding([int]$all) { - $this.Label.Padding = New-Object System.Windows.Forms.Padding($all) - return $this - } - - # Setzt das Anchor - [LabelBuilder] SetAnchor([System.Windows.Forms.AnchorStyles]$anchor) { - $this.Label.Anchor = $anchor - return $this - } - - # Setzt einen Tooltip - [LabelBuilder] SetToolTip([System.String]$text) { - $tooltip = New-Object System.Windows.Forms.ToolTip - $tooltip.SetToolTip($this.Label, $text) - return $this - } - - # Setzt das UseMnemonic (für & Zeichen) - [LabelBuilder] SetUseMnemonic([bool]$useMnemonic) { - $this.Label.UseMnemonic = $useMnemonic - return $this - } - - # Gibt das Label-Objekt zurück - [System.Windows.Forms.Label] GetLabel() { - return $this.Label - } - - # Fügt das Label zu einem Control hinzu - [void] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.Label) - } - - [System.Windows.Forms.Label] Build() { - return $this.Label - } - } - - class TreeViewBuilder : BaseComponent { - [System.Windows.Forms.TreeView]$control - - TreeViewBuilder() { - $this.control = New-Object System.Windows.Forms.TreeView - # Standard-Einstellungen - $this.control.Dock = 'Fill' - $this.control.HideSelection = $false - $this.control.ShowPlusMinus = $true - $this.control.ShowRootLines = $true - $this.control.FullRowSelect = $true - } - - [TreeViewBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [TreeViewBuilder] SetFont([System.String]$family, [float]$size) { - $this.control.Font = New-Object System.Drawing.Font($family, $size) - return $this - } - - [TreeViewBuilder] SetFont([System.String]$family, [float]$size, [System.Drawing.FontStyle]$style) { - $this.control.Font = New-Object System.Drawing.Font($family, $size, $style) - return $this - } - - [TreeViewBuilder] SetHideSelection([bool]$hide) { - $this.control.HideSelection = $hide - return $this - } - - [TreeViewBuilder] SetShowPlusMinus([bool]$show) { - $this.control.ShowPlusMinus = $show - return $this - } - - [TreeViewBuilder] SetShowRootLines([bool]$show) { - $this.control.ShowRootLines = $show - return $this - } - - [TreeViewBuilder] SetFullRowSelect([bool]$select) { - $this.control.FullRowSelect = $select - return $this - } - - [TreeViewBuilder] SetShowLines([bool]$show) { - $this.control.ShowLines = $show - return $this - } - - [TreeViewBuilder] SetCheckBoxes([bool]$show) { - $this.control.CheckBoxes = $show - return $this - } - - [TreeViewBuilder] SetImageList([System.Windows.Forms.ImageList]$imageList) { - $this.control.ImageList = $imageList - return $this - } - - [TreeViewBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.control.BackColor = $color - return $this - } - - [TreeViewBuilder] SetForeColor([System.Drawing.Color]$color) { - $this.control.ForeColor = $color - return $this - } - - [TreeViewBuilder] AddNode([System.String]$name) { - $this.control.Nodes.Add([System.Windows.Forms.TreeNode]::new($name)) | Out-Null - return $this - } - - [TreeViewBuilder] AddNode([System.Windows.Forms.TreeNode]$node) { - $this.control.Nodes.Add($node) | Out-Null - return $this - } - - [TreeViewBuilder] AddNodes([System.Windows.Forms.TreeNode[]]$nodes) { - foreach ($node in $nodes) { - $this.control.Nodes.Add($node) | Out-Null - } - return $this - } - - # NEU: Lädt Hashtable/Template in TreeView - [TreeViewBuilder] LoadTemplate([object]$template, [System.String]$rootName = "Template") { - $this.control.Nodes.Clear() - $rootNode = $this.control.Nodes.Add($rootName) - - try { - if ($template -is [System.Collections.IDictionary]) { - # WICHTIG: Keine Sortierung, Keys in Original-Reihenfolge - foreach ($key in $template.Keys) { - $this.AddTreeNodeRecursive($rootNode, $template[$key], $key, "") - } - } else { - $this.AddTreeNodeRecursive($rootNode, $template, $rootName, "") - } - } catch { - $rootNode.Nodes.Add("Fehler beim Lesen: $($_.Exception.Message)") | Out-Null - } - - $rootNode.ExpandAll() - return $this - } - - # NEU: Rekursive Methode zum Hinzufügen von Nodes - hidden [void] AddTreeNodeRecursive([System.Windows.Forms.TreeNode]$parentNode, [object]$value, [System.String]$name, [System.String]$path) { - $currentPath = if ($path -eq "") { $name } else { "$path.$name" } - - if ($value -is [System.Collections.IDictionary]) { - $node = $parentNode.Nodes.Add($name, $name) - $node.Tag = @{ Type = "Hashtable"; Path = $currentPath; Value = $value } - - # WICHTIG: KEIN Sort-Object! Behält die Original-Reihenfolge bei - foreach ($k in $value.Keys) { - $this.AddTreeNodeRecursive($node, $value[$k], $k, $currentPath) - } - } - elseif ($value -is [System.Collections.IEnumerable] -and -not ($value -is [string])) { - $node = $parentNode.Nodes.Add($name, $name) - $node.Tag = @{ Type = "Array"; Path = $currentPath; Value = $value } - $i = 0 - foreach ($item in $value) { - $this.AddTreeNodeRecursive($node, $item, "[$i]", $currentPath) - $i++ - } - } - else { - $displayText = "$name = $value" - $node = $parentNode.Nodes.Add($name, $displayText) - $node.Tag = @{ Type = "Value"; Path = $currentPath; Key = $name; Value = $value } - } - } - - # NEU: Löscht alle Nodes - [TreeViewBuilder] ClearNodes() { - $this.control.Nodes.Clear() - return $this - } - - [TreeViewBuilder] AddEventHandler([System.String]$eventName, [scriptblock]$handler) { - $this.control."Add_$eventName"($handler) - return $this - } - - [System.Windows.Forms.TreeView] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.control) - return $this.control - } - - [System.Windows.Forms.TreeView] Build() { - return $this.control - } - } - - class DataGridViewBuilder : BaseComponent{ - [System.Windows.Forms.DataGridView] $control - - DataGridViewBuilder() { - $this.control = New-Object System.Windows.Forms.DataGridView - $this.control.Dock = "Fill" - $this.control.ColumnHeadersHeight = 30 - $this.control.AutoSizeColumnsMode = "Fill" - } - - [DataGridViewBuilder] SetAllowAddRows([Boolean] $enabled) { - $this.control.AllowUserToAddRows = $enabled - return $this - } - - [DataGridViewBuilder] SetHeaderColumns([System.Array] $Columns) { - foreach($Column in $Columns){ - $this.control.Columns.Add($Column,$Column) - } - return $this - } - - [DataGridViewBuilder] SetHeaderColumnReadOnly([System.String] $Name) { - $this.control.Columns[$Name].ReadOnly = $true - return $this - } - - [System.Windows.Forms.DataGridView] Build() { - return $this.control - } - } - - class GroupBoxBuilder : BaseComponent { - [System.Windows.Forms.GroupBox]$control - [bool]$autoSizeToContent = $false - - GroupBoxBuilder([System.String]$text) { - $this.control = New-Object System.Windows.Forms.GroupBox - $this.control.Text = $text - $this.control.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize"),[System.Drawing.FontStyle]::Bold) - #$this.control.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::GrowOnly - } - - [GroupBoxBuilder] SetText([System.String]$text) { - $this.control.Text = $text - return $this - } - - [GroupBoxBuilder] SetWidth([int]$width) { - $this.control.Width = $width - return $this - } - - [GroupBoxBuilder] SetHeight([int]$height) { - $this.control.Height = $height - return $this - } - - [GroupBoxBuilder] SetSize([int]$width, [int]$height) { - $this.control.Width = $width - $this.control.Height = $height - return $this - } - - [GroupBoxBuilder] SetFont([System.String]$family, [float]$size) { - $this.control.Font = New-Object System.Drawing.Font($family, $size) - return $this - } - - [GroupBoxBuilder] SetFont([System.String]$family, [float]$size, [System.Drawing.FontStyle]$style) { - $this.control.Font = New-Object System.Drawing.Font($family, $size, $style) - return $this - } - - [GroupBoxBuilder] SetMargin([int]$all) { - $this.control.Margin = New-Object System.Windows.Forms.Padding($all) - return $this - } - - [GroupBoxBuilder] SetMargin([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.control.Margin = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - [GroupBoxBuilder] SetPadding([int]$all) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($all) - return $this - } - - [GroupBoxBuilder] SetPadding([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - [GroupBoxBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [GroupBoxBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.control.BackColor = $color - return $this - } - - [GroupBoxBuilder] SetForeColor([System.Drawing.Color]$color) { - $this.control.ForeColor = $color - return $this - } - - [GroupBoxBuilder] SetAutoSize([bool]$autoSize) { - $this.control.AutoSize = $autoSize - return $this - } - - [GroupBoxBuilder] SetAutoSizeMode([System.String]$autoSizeMode) { - $this.control.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::$autoSizeMode - return $this - } - - [GroupBoxBuilder] AddControl([System.Windows.Forms.Control]$childControl) { - $this.control.Controls.Add($childControl) - return $this - } - - [GroupBoxBuilder] AddControls([System.Windows.Forms.Control[]]$controls) { - foreach ($ctrl in $controls) { - $this.control.Controls.Add($ctrl) - } - return $this - } - - [System.Windows.Forms.GroupBox] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.control) - return $this.control - } - - [System.Windows.Forms.GroupBox] Build() { - return $this.control - } - } - - class ListBoxBuilder : BaseComponent { - [System.Windows.Forms.ListBox]$control - - ListBoxBuilder() { - $this.control = New-Object System.Windows.Forms.ListBox - # Standard-Einstellungen - $this.control.DisplayMember = 'BaseName' - $this.control.ValueMember = 'FullName' - $this.control.Dock = 'Fill' - $this.control.Font = New-Object System.Drawing.Font("Segoe UI", $this.GetSetting("FontSize")) - } - - [ListBoxBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [ListBoxBuilder] SetFont([System.String]$family, [float]$size) { - $this.control.Font = New-Object System.Drawing.Font($family, $size) - return $this - } - - [ListBoxBuilder] SetFont([System.String]$family, [float]$size, [System.Drawing.FontStyle]$style) { - $this.control.Font = New-Object System.Drawing.Font($family, $size, $style) - return $this - } - - [ListBoxBuilder] SetSelectionMode([System.String]$mode) { - $this.control.SelectionMode = [System.Windows.Forms.SelectionMode]::$mode - return $this - } - - [ListBoxBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.control.BackColor = $color - return $this - } - - [ListBoxBuilder] SetForeColor([System.Drawing.Color]$color) { - $this.control.ForeColor = $color - return $this - } - - [ListBoxBuilder] SetBorderStyle([System.String]$style) { - $this.control.BorderStyle = [System.Windows.Forms.BorderStyle]::$style - return $this - } - - [ListBoxBuilder] SetHorizontalScrollbar([bool]$show) { - $this.control.HorizontalScrollbar = $show - return $this - } - - [ListBoxBuilder] SetIntegralHeight([bool]$integral) { - $this.control.IntegralHeight = $integral - return $this - } - - [ListBoxBuilder] SetSorted([bool]$sorted) { - $this.control.Sorted = $sorted - return $this - } - - [ListBoxBuilder] SetHeight([Int]$height) { - $this.control.Height = $height - return $this - } - - [ListBoxBuilder] AddItem([object]$item) { - $this.control.Items.Add($item) | Out-Null - return $this - } - - [ListBoxBuilder] AddItems([object[]]$items) { - foreach ($item in $items) { - $this.control.Items.Add($item) | Out-Null - } - return $this - } - - [ListBoxBuilder] ClearItems() { - $this.control.Items.Clear() - return $this - } - - [ListBoxBuilder] SetDataSource([object]$dataSource) { - $this.control.DataSource = $dataSource - return $this - } - - [ListBoxBuilder] SetDisplayMember([System.String]$member) { - $this.control.DisplayMember = $member - return $this - } - - [ListBoxBuilder] SetValueMember([System.String]$member) { - $this.control.ValueMember = $member - return $this - } - - [ListBoxBuilder] AddSelectedIndexChangedHandler([scriptblock]$handler) { - $this.control.Add_SelectedIndexChanged($handler) - return $this - } - - [ListBoxBuilder] AddMouseDoubleClickHandler([scriptblock]$handler) { - $this.control.Add_MouseDoubleClick($handler) - return $this - } - - [ListBoxBuilder] AddEventHandler([System.String]$eventName, [scriptblock]$handler) { - $this.control."Add_$eventName"($handler) - return $this - } - - [System.Windows.Forms.ListBox] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.control) - return $this.control - } - - [System.Windows.Forms.ListBox] Build() { - return $this.control - } - } - - class PanelBuilder : BaseComponent{ - [System.Windows.Forms.Panel]$control - - [scriptblock] $EnableCondition = $null - [StateManager] $StateManager = $null - - - PanelBuilder() { - $this.control = New-Object System.Windows.Forms.Panel - } - - [PanelBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [PanelBuilder] SetWidth([int]$width) { - $this.control.Width = $width - return $this - } - - [PanelBuilder] SetHeight([int]$height) { - $this.control.Height = $height - return $this - } - - [PanelBuilder] SetSize([int]$width, [int]$height) { - $this.control.Size = New-Object System.Drawing.Size($width, $height) - return $this - } - - [PanelBuilder] SetLocation([int]$x, [int]$y) { - $this.control.Location = New-Object System.Drawing.Point($x, $y) - return $this - } - - [PanelBuilder] SetBackColor([System.Drawing.Color]$color) { - $this.control.BackColor = $color - return $this - } - - [PanelBuilder] SetForeColor([System.Drawing.Color]$color) { - $this.control.ForeColor = $color - return $this - } - - [PanelBuilder] SetBorderStyle([System.String]$style) { - $this.control.BorderStyle = [System.Windows.Forms.BorderStyle]::$style - return $this - } - - [PanelBuilder] SetAutoScroll([bool]$autoScroll) { - $this.control.AutoScroll = $autoScroll - return $this - } - - [PanelBuilder] SetPadding([int]$all) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($all) - return $this - } - - [PanelBuilder] SetPadding([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - [PanelBuilder] SetMargin([int]$all) { - $this.control.Margin = New-Object System.Windows.Forms.Padding($all) - return $this - } - - [PanelBuilder] SetMargin([int]$left, [int]$top, [int]$right, [int]$bottom) { - $this.control.Margin = New-Object System.Windows.Forms.Padding($left, $top, $right, $bottom) - return $this - } - - [PanelBuilder] SetAnchor([System.Windows.Forms.AnchorStyles]$anchor) { - $this.control.Anchor = $anchor - return $this - } - - [PanelBuilder] SetVisible([bool]$visible) { - $this.control.Visible = $visible - return $this - } - - [PanelBuilder] SetEnabled([bool]$enabled) { - $this.control.Enabled = $enabled - return $this - } - - [PanelBuilder] SetAutoSize([bool]$autoSize) { - $this.control.AutoSize = $autoSize - return $this - } - - [PanelBuilder] SetAutoSizeMode([System.String]$mode) { - $this.control.AutoSizeMode = [System.Windows.Forms.AutoSizeMode]::$mode - return $this - } - - [PanelBuilder] AddControl([System.Windows.Forms.Control]$childControl) { - $this.control.Controls.Add($childControl) - return $this - } - - [PanelBuilder] AddControls([System.Windows.Forms.Control[]]$controls) { - foreach ($ctrl in $controls) { - $this.control.Controls.Add($ctrl) - } - return $this - } - - [PanelBuilder] ClearControls() { - $this.control.Controls.Clear() - return $this - } - - [PanelBuilder] AddEventHandler([System.String]$eventName, [scriptblock]$handler) { - $this.control."Add_$eventName"($handler) - return $this - } - - [PanelBuilder] SetName([System.String]$name) { - $this.control.Name = $name - return $this - } - - [PanelBuilder] SetTag([object]$tag) { - $this.control.Tag = $tag - return $this - } - - [System.Windows.Forms.Panel] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.control) - return $this.control - } - - [PanelBuilder] BindEnabled([scriptblock]$condition, [StateManager]$stateManager) { - $this.EnableCondition = $condition - $this.StateManager = $stateManager - $this.UpdateVisibleState() - return $this - } - - # Aktualisiert den Visible-Status basierend auf der Bedingung - [void] UpdateVisibleState() { - if ($null -ne $this.EnableCondition) { - try { - $result = & $this.EnableCondition - $this.control.Visible = [bool]$result - } catch { - Write-Warning "Fehler beim Evaluieren der Visible-Bedingung: $_" - $this.control.Visible = $false - } - } - } - - [System.Windows.Forms.Panel] Build() { - if ($null -ne $this.StateManager -and $null -ne $this.EnableCondition) { - $this.StateManager.RegisterForm($this) - } - return $this.control - } - - [System.Windows.Forms.Panel] GetPanel() { - return $this.control - } - } - - class DialogBuilder : BaseComponent { - [object] $Dialog # Kann FileDialog oder FolderBrowserDialog sein - [System.String] $DialogType - - # Privater Konstruktor - hidden DialogBuilder([System.String]$type) { - $this.DialogType = $type - - switch ($type) { - "Open" { - $this.Dialog = New-Object System.Windows.Forms.OpenFileDialog - $this.Dialog.Multiselect = $false - $this.Dialog.Filter = "Alle Dateien (*.*)|*.*" - $this.Dialog.FilterIndex = 1 - $this.Dialog.RestoreDirectory = $true - } - "Save" { - $this.Dialog = New-Object System.Windows.Forms.SaveFileDialog - $this.Dialog.OverwritePrompt = $true - $this.Dialog.Filter = "Alle Dateien (*.*)|*.*" - $this.Dialog.FilterIndex = 1 - $this.Dialog.RestoreDirectory = $true - } - "Folder" { - $this.Dialog = New-Object System.Windows.Forms.FolderBrowserDialog - $this.Dialog.ShowNewFolderButton = $true - } - } - } - - # === FACTORY-METHODEN === - - static [DialogBuilder] OpenFile() { - return [DialogBuilder]::new("Open") - } - - static [DialogBuilder] SaveFile() { - return [DialogBuilder]::new("Save") - } - - static [DialogBuilder] SelectFolder() { - return [DialogBuilder]::new("Folder") - } - - # === GEMEINSAME METHODEN (FileDialog) === - - # Setzt den Titel - [DialogBuilder] SetTitle([System.String]$title) { - if ($this.DialogType -eq "Folder") { - $this.Dialog.Description = $title - } else { - $this.Dialog.Title = $title - } - return $this - } - - # Setzt den Filter (nur File-Dialoge) - [DialogBuilder] SetFilter([System.String]$filter) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.Filter = $filter - } else { - Write-Warning "Filter ist nur für File-Dialoge verfügbar" - } - return $this - } - - # Setzt den aktiven Filter-Index (nur File-Dialoge) - [DialogBuilder] SetFilterIndex([int]$index) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.FilterIndex = $index - } - return $this - } - - # Setzt das Initial-Verzeichnis - [DialogBuilder] SetInitialDirectory([System.String]$path) { - if ($this.DialogType -eq "Folder") { - if (Test-Path $path) { - $this.Dialog.SelectedPath = $path - } else { - Write-Warning "Pfad existiert nicht: $path" - } - } else { - if (Test-Path $path) { - $this.Dialog.InitialDirectory = $path - } else { - Write-Warning "Pfad existiert nicht: $path" - } - } - return $this - } - - # Setzt den Standard-Dateinamen (nur File-Dialoge) - [DialogBuilder] SetFileName([System.String]$fileName) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.FileName = $fileName - } - return $this - } - - # Prüft ob Datei existieren muss (nur File-Dialoge) - [DialogBuilder] SetCheckFileExists([bool]$check) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.CheckFileExists = $check - } - return $this - } - - # Prüft ob Pfad existieren muss (nur File-Dialoge) - [DialogBuilder] SetCheckPathExists([bool]$check) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.CheckPathExists = $check - } - return $this - } - - # Wiederherstellt letztes Verzeichnis (nur File-Dialoge) - [DialogBuilder] SetRestoreDirectory([bool]$restore) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.RestoreDirectory = $restore - } - return $this - } - - # Validiert Namen gegen ungültige Zeichen (nur File-Dialoge) - [DialogBuilder] SetValidateNames([bool]$validate) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.ValidateNames = $validate - } - return $this - } - - # Dereferenziert Links/Shortcuts (nur File-Dialoge) - [DialogBuilder] SetDereferenceLinks([bool]$dereference) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.DereferenceLinks = $dereference - } - return $this - } - - # Setzt die Standard-Erweiterung (nur File-Dialoge) - [DialogBuilder] SetDefaultExt([System.String]$ext) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.DefaultExt = $ext.TrimStart('.') - } - return $this - } - - # Fügt automatisch Erweiterung hinzu (nur File-Dialoge) - [DialogBuilder] SetAddExtension([bool]$add) { - if ($this.DialogType -ne "Folder") { - $this.Dialog.AddExtension = $add - } - return $this - } - - # Setzt Custom Places (nur File-Dialoge) - [DialogBuilder] AddCustomPlace([System.String]$path) { - if ($this.DialogType -ne "Folder") { - if (Test-Path $path) { - $this.Dialog.CustomPlaces.Add($path) - } - } - return $this - } - - # Setzt mehrere Custom Places (nur File-Dialoge) - [DialogBuilder] AddCustomPlaces([System.String[]]$paths) { - if ($this.DialogType -ne "Folder") { - foreach ($path in $paths) { - if (Test-Path $path) { - $this.Dialog.CustomPlaces.Add($path) - } - } - } - return $this - } - - # === OPENFILEDIALOG-SPEZIFISCH === - - # Aktiviert/Deaktiviert Mehrfachauswahl - [DialogBuilder] SetMultiselect([bool]$multiselect) { - if ($this.DialogType -eq "Open") { - $this.Dialog.Multiselect = $multiselect - } else { - Write-Warning "Multiselect ist nur für OpenFileDialog verfügbar" - } - return $this - } - - # Zeigt Read-Only Checkbox - [DialogBuilder] SetShowReadOnly([bool]$show) { - if ($this.DialogType -eq "Open") { - $this.Dialog.ShowReadOnly = $show - } - return $this - } - - # Setzt Read-Only Status - [DialogBuilder] SetReadOnlyChecked([bool]$checked) { - if ($this.DialogType -eq "Open") { - $this.Dialog.ReadOnlyChecked = $checked - } - return $this - } - - # === SAVEFILEDIALOG-SPEZIFISCH === - - # Warnt bei Überschreiben - [DialogBuilder] SetOverwritePrompt([bool]$prompt) { - if ($this.DialogType -eq "Save") { - $this.Dialog.OverwritePrompt = $prompt - } - return $this - } - - # Warnt beim Erstellen neuer Dateien - [DialogBuilder] SetCreatePrompt([bool]$prompt) { - if ($this.DialogType -eq "Save") { - $this.Dialog.CreatePrompt = $prompt - } - return $this - } - - # === FOLDERBROWSERDIALOG-SPEZIFISCH === - - # Zeigt "Neuer Ordner"-Button - [DialogBuilder] SetShowNewFolderButton([bool]$show) { - if ($this.DialogType -eq "Folder") { - $this.Dialog.ShowNewFolderButton = $show - } - return $this - } - - # Setzt die Beschreibung (Folder-spezifisch) - [DialogBuilder] SetDescription([System.String]$description) { - if ($this.DialogType -eq "Folder") { - $this.Dialog.Description = $description - } - return $this - } - - # Setzt den Root-Folder (Folder-spezifisch) - [DialogBuilder] SetRootFolder([System.String]$specialFolder) { - if ($this.DialogType -eq "Folder") { - try { - $this.Dialog.RootFolder = [System.Environment+SpecialFolder]::$specialFolder - } catch { - Write-Warning "Ungültiger SpecialFolder: $specialFolder" - } - } - return $this - } - - # Setzt den ausgewählten Pfad (Folder-spezifisch) - [DialogBuilder] SetSelectedPath([System.String]$path) { - if ($this.DialogType -eq "Folder") { - if (Test-Path $path) { - $this.Dialog.SelectedPath = $path - } else { - Write-Warning "Pfad existiert nicht: $path" - } - } - return $this - } - - # Verwendet die neue Folder-Browser-Darstellung (Vista-Style) - [DialogBuilder] SetUseDescriptionForTitle([bool]$use) { - if ($this.DialogType -eq "Folder") { - $this.Dialog.UseDescriptionForTitle = $use - } - return $this - } - - # === VOREINGESTELLTE FILTER === - - # Schnell-Methode für häufige Filter (nur File-Dialoge) - [DialogBuilder] SetCommonFilter([System.String]$type) { - if ($this.DialogType -eq "Folder") { - Write-Warning "Filter sind für FolderBrowserDialog nicht verfügbar" - return $this - } - - switch ($type) { - 'Text' { - $this.Dialog.Filter = "Text-Dateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "txt" - } - 'PowerShell' { - $this.Dialog.Filter = "PowerShell-Dateien (*.ps1;*.psm1;*.psd1)|*.ps1;*.psm1;*.psd1|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "ps1" - } - 'PSD1' { - $this.Dialog.Filter = "PowerShell Data-Dateien (*.psd1)|*.psd1|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "psd1" - } - 'JSON' { - $this.Dialog.Filter = "JSON-Dateien (*.json)|*.json|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "json" - } - 'XML' { - $this.Dialog.Filter = "XML-Dateien (*.xml)|*.xml|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "xml" - } - 'CSV' { - $this.Dialog.Filter = "CSV-Dateien (*.csv)|*.csv|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "csv" - } - 'Excel' { - $this.Dialog.Filter = "Excel-Dateien (*.xlsx;*.xls)|*.xlsx;*.xls|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "xlsx" - } - 'Image' { - $this.Dialog.Filter = "Bild-Dateien (*.png;*.jpg;*.jpeg;*.gif;*.bmp)|*.png;*.jpg;*.jpeg;*.gif;*.bmp|Alle Dateien (*.*)|*.*" - $this.Dialog.DefaultExt = "png" - } - 'All' { - $this.Dialog.Filter = "Alle Dateien (*.*)|*.*" - } - default { - Write-Warning "Unbekannter Filter-Typ: $type" - } - } - return $this - } - - # === SHOW UND BUILD === - - # Zeigt den Dialog und gibt das Ergebnis zurück - [System.Collections.Hashtable] Show() { - $result = @{ - Result = $false - FileName = $null - FileNames = @() - SafeFileName = $null - SafeFileNames = @() - SelectedPath = $null - } - - $dialogResult = $this.Dialog.ShowDialog() - - if ($dialogResult -eq 'OK') { - $result.Result = $true - - if ($this.DialogType -eq "Folder") { - $result.SelectedPath = $this.Dialog.SelectedPath - $result.FileName = $this.Dialog.SelectedPath - } else { - $result.FileName = $this.Dialog.FileName - $result.SafeFileName = $this.Dialog.SafeFileName - - if ($this.DialogType -eq "Open") { - $result.FileNames = $this.Dialog.FileNames - $result.SafeFileNames = $this.Dialog.SafeFileNames - } else { - $result.FileNames = @($this.Dialog.FileName) - $result.SafeFileNames = @($this.Dialog.SafeFileName) - } - } - } - - return $result - } - - # Zeigt den Dialog mit Custom Parent Window - [System.Collections.Hashtable] Show([System.Windows.Forms.IWin32Window]$owner) { - $result = @{ - Result = $false - FileName = $null - FileNames = @() - SafeFileName = $null - SafeFileNames = @() - SelectedPath = $null - } - - $dialogResult = $this.Dialog.ShowDialog($owner) - - if ($dialogResult -eq 'OK') { - $result.Result = $true - - if ($this.DialogType -eq "Folder") { - $result.SelectedPath = $this.Dialog.SelectedPath - $result.FileName = $this.Dialog.SelectedPath - } else { - $result.FileName = $this.Dialog.FileName - $result.SafeFileName = $this.Dialog.SafeFileName - - if ($this.DialogType -eq "Open") { - $result.FileNames = $this.Dialog.FileNames - $result.SafeFileNames = $this.Dialog.SafeFileNames - } else { - $result.FileNames = @($this.Dialog.FileName) - $result.SafeFileNames = @($this.Dialog.SafeFileName) - } - } - } - - return $result - } - - # Gibt das Dialog-Objekt zurück (für erweiterte Szenarien) - [object] Build() { - return $this.Dialog - } - - # Dispose des Dialogs - [void] Dispose() { - if ($null -ne $this.Dialog) { - $this.Dialog.Dispose() - } - } - } - - class TemplateBuilder : BaseComponent{ - - [System.Collections.Specialized.OrderedDictionary] $Template - - # Konstruktor: Pfad zu PSD1-Datei - TemplateBuilder([System.String]$TemplatePath) { - $this.Template = $this.ConvertFromPowerShellDataString($TemplatePath) - } - - # Konstruktor: Hashtable direkt übergeben - TemplateBuilder([hashtable]$TemplateHashtable) { - $this.Template = $this.ConvertHashtableToOrdered($TemplateHashtable) - } - - # Konstruktor: OrderedDictionary direkt übergeben - TemplateBuilder([System.Collections.Specialized.OrderedDictionary]$TemplateOrdered) { - $this.Template = $TemplateOrdered - } - - # Hilfsmethode: Konvertiert eine normale Hashtable in OrderedDictionary (rekursiv) - hidden [System.Collections.Specialized.OrderedDictionary] ConvertHashtableToOrdered([hashtable]$Hashtable) { - $ordered = New-Object System.Collections.Specialized.OrderedDictionary - - foreach ($key in $Hashtable.Keys) { - $value = $Hashtable[$key] - - # Rekursive Konvertierung für verschachtelte Hashtables - if ($value -is [hashtable]) { - $ordered[$key] = $this.ConvertHashtableToOrdered($value) - } - # Array mit Hashtables - elseif ($value -is [array]) { - $arrayResult = @() - foreach ($item in $value) { - if ($item -is [hashtable]) { - $arrayResult += $this.ConvertHashtableToOrdered($item) - } - else { - $arrayResult += $item - } - } - $ordered[$key] = $arrayResult - } - else { - $ordered[$key] = $value - } - } - - return $ordered - } - - # Concat mit einer dynamischen Anzahl von Argumenten - static [string] Concat([object[]]$input) { - return (($input | ForEach-Object { [string]$_ }) -join '') - } - - # ToLower-Methode - static [string] ToLower([object[]]$input) { - if ($input.Count -lt 1) { - return "" - } - - return ([string]$input[0]).ToLowerInvariant() - } - - # ToUpper-Methode - static [string] ToUpper([object[]]$input) { - if ($input.Count -lt 1) { - return "" - } - - return ([string]$input[0]).ToUpperInvariant() - } - - # FirstIndexOf-Methode - static [string] FirstIndexOf([object[]] $input){ - if ($input.Count -lt 1) { - return "" - } - - return [string]$input[0] - } - - # LastIndexOf-Methode - static [string] LastIndexOf([object[]] $input){ - if ($input.Count -lt 1) { - return "" - } - - return [string]$input[-1] - } - - # IndexOf-Methode - static [string] IndexOf([object[]] $input){ - if ($input.Count -lt 2) { - throw "IndexOf benötigt mindestens zwei Argumente." - } - - return [string]$input[[int]$input[-1]] - } - - # Substring-Methode - static [String] Substring([object[]] $input){ - if($input.Count -eq 2){ - return ([string]$input[0]).Substring([int]$input[1]) - - }elseif($input.Count -eq 3){ - return ([string]$input[0]).Substring([int]$input[1],[int]$input[2]) - - }else{ - throw "Substring erwartet zwei oder drei Argumente." - } - } - - # Replace-Methode - static [String] Replace([object[]] $input){ - if ($input.Count -lt 3) { - throw "Replace erwartet drei Argumente." - } - - return ([string]$input[0]).Replace([string]$input[1],[string]$input[2]) - } - - hidden [System.Collections.Specialized.OrderedDictionary] ResolveDeploymentParameterDefaultValues(){ - $TemplateClone = $this.Template - - if($TemplateClone.Contains("Parameters")){ - foreach($Parameter in $this.Template.Parameters.GetEnumerator()){ - if(!$Parameter.Value.Contains("Value")){ - $TemplateClone.Parameters[$Parameter.Name].Value = $this.Template.Parameters[$Parameter.Name].DefaultValue - } - } - } - return $TemplateClone - } - - [System.Collections.Specialized.OrderedDictionary] ResolveDeploymentDataVariables(){ - - - $TemplateClone = $this.ResolveDeploymentParameterDefaultValues() - - # Erst Variables auflösen (können Parameter-Referenzen enthalten) - if ($TemplateClone.Variables) { - $resolvedVariables = New-Object System.Collections.Specialized.OrderedDictionary - # WICHTIG: Keys-Array erstellen, um Collection-Modification zu vermeiden - $varKeys = @($TemplateClone.Variables.Keys) - foreach ($varKey in $varKeys) { - $resolvedVariables[$varKey] = $this.ResolveValue($TemplateClone.Variables[$varKey],$TemplateClone.Parameters,$TemplateClone.Variables) - } - $TemplateClone.Variables = $resolvedVariables - } - - # Dann den Rest des Templates auflösen - # WICHTIG: Keys-Array erstellen, um Collection-Modification zu vermeiden - $templateKeys = @($TemplateClone.Keys) - foreach ($key in $templateKeys) { - if ($key -ne 'Variables' -and $key -ne 'Parameters') { - $TemplateClone[$key] = $this.ResolveValue($TemplateClone[$key],$TemplateClone.Parameters,$TemplateClone.Variables) - } - } - - return $TemplateClone - } - - hidden [System.Collections.Specialized.OrderedDictionary] ConvertFromPowerShellDataString($TemplatePath){ - $errors = $null - $tokens = $null - - $ast = [System.Management.Automation.Language.Parser]::ParseFile( - $TemplatePath, - [ref]$tokens, - [ref]$errors - ) - - if ($errors) { - throw "Fehler beim Parsen der Datei: $($errors[0].Message)" - } - - $hashtableAst = $ast.Find({ - $args[0] -is [System.Management.Automation.Language.HashtableAst] - }, $true) - - if (-not $hashtableAst) { - throw "Keine Hashtable im $TemplatePath gefunden" - } - - $this.Template = $this.ConvertToOrderedHashtable($hashtableAst) - - return $this.Template - } - - hidden [System.Collections.Specialized.OrderedDictionary] ConvertToOrderedHashtable([System.Management.Automation.Language.HashtableAst]$HashtableAst){ - $ordered = New-Object System.Collections.Specialized.OrderedDictionary - - $sortedKvps = $HashtableAst.KeyValuePairs | Sort-Object { $_.Item1.Extent.StartOffset } - - foreach ($kvp in $sortedKvps) { - $key = [string]$this.ConvertAstValue($kvp.Item1) - $value = $this.ConvertAstValue($kvp.Item2) - $ordered.Add($key, $value) - } - - return $ordered - } - - hidden [System.Object] ConvertAstValue([System.Management.Automation.Language.Ast]$Ast) { - if ($null -eq $Ast) { - return $null - } - - if ($Ast -is [System.Management.Automation.Language.PipelineAst]) { - if ($Ast.PipelineElements.Count -eq 1 -and $Ast.PipelineElements[0] -is [System.Management.Automation.Language.CommandExpressionAst]) { - return $this.ConvertAstValue($Ast.PipelineElements[0].Expression) - } - - return $Ast.SafeGetValue() - } - - if ($Ast -is [System.Management.Automation.Language.CommandExpressionAst]) { - return $this.ConvertAstValue($Ast.Expression) - } - - if ($Ast -is [System.Management.Automation.Language.ParenExpressionAst]) { - return $this.ConvertAstValue($Ast.Pipeline) - } - - if ($Ast -is [System.Management.Automation.Language.ArrayExpressionAst]) { - return $this.ConvertAstValue($Ast.SubExpression) - } - - if ($Ast -is [System.Management.Automation.Language.StatementBlockAst]) { - if ($Ast.Statements.Count -eq 1 -and $Ast.Statements[0] -is [System.Management.Automation.Language.PipelineAst]) { - return $this.ConvertAstValue($Ast.Statements[0]) - } - - throw "Nicht unterstützter Ausdruck in PSD1-Datei: $($Ast.Extent.Text)" - } - - if ($Ast -is [System.Management.Automation.Language.ArrayLiteralAst]) { - $result = @() - foreach ($element in $Ast.Elements) { - $result += $this.ConvertAstValue($element) - } - - return $result - } - - if ($Ast -is [System.Management.Automation.Language.HashtableAst]) { - return $this.ConvertToOrderedHashtable($Ast) - } - - if ($Ast -is [System.Management.Automation.Language.VariableExpressionAst]) { - switch ($Ast.VariablePath.UserPath) { - 'true' { return $true } - 'false' { return $false } - 'null' { return $null } - default { return $Ast.Extent.Text } - } - } - - try { - return $Ast.SafeGetValue() - } - catch { - return $Ast.Extent.Text - } - } - - hidden [System.Object] ResolveValue($Value, $Parameters, $Variables){ - $resolutionStack = [System.Collections.Generic.List[string]]::new() - return $this.ResolveValueInternal($Value, $Parameters, $Variables, $resolutionStack) - } - - hidden [System.Object] ResolveValueInternal($Value, $Parameters, $Variables, [System.Collections.Generic.List[string]]$ResolutionStack){ - if ($Value -is [string]) { - $trimmedValue = $Value.Trim() - if ($this.IsTemplateExpression($trimmedValue)) { - return $this.EvaluateTemplateExpression($trimmedValue.Substring(1, $trimmedValue.Length - 2), $Parameters, $Variables, $ResolutionStack) - } - - return $this.ResolveInlineTemplateExpressions($Value, $Parameters, $Variables, $ResolutionStack) - } - elseif ($Value -is [System.Collections.IDictionary]) { - $resolved = New-Object System.Collections.Specialized.OrderedDictionary - foreach ($key in $Value.Keys) { - $resolved[$key] = $this.ResolveValueInternal($Value[$key], $Parameters, $Variables, $ResolutionStack) - } - return $resolved - } - elseif ($Value -is [array]) { - $resolved = @() - foreach ($item in $Value) { - $resolved += $this.ResolveValueInternal($item, $Parameters, $Variables, $ResolutionStack) - } - return $resolved - } - else { - return $Value - } - } - - hidden [bool] IsTemplateExpression([string]$Value) { - if ([string]::IsNullOrWhiteSpace($Value)) { - return $false - } - - if (-not ($Value.StartsWith('[') -and $Value.EndsWith(']'))) { - return $false - } - - return $this.IsFunctionInvocation($Value.Substring(1, $Value.Length - 2)) - } - - hidden [bool] IsFunctionInvocation([string]$Value) { - return $Value.Trim() -match '^[A-Za-z_][A-Za-z0-9_]*\s*\(.*\)$' - } - - hidden [string] ResolveInlineTemplateExpressions([string]$Value, $Parameters, $Variables, [System.Collections.Generic.List[string]]$ResolutionStack) { - $resolved = $Value - $matches = [regex]::Matches($Value, '\[[^\[\]]+\]') - - for ($i = $matches.Count - 1; $i -ge 0; $i--) { - $match = $matches[$i] - $expressionText = $match.Value.Substring(1, $match.Value.Length - 2) - if (-not $this.IsFunctionInvocation($expressionText)) { - continue - } - - $replacement = $this.EvaluateTemplateExpression($expressionText, $Parameters, $Variables, $ResolutionStack) - $resolved = $resolved.Remove($match.Index, $match.Length).Insert($match.Index, [string]$replacement) - } - - return $resolved - } - - hidden [System.Object] EvaluateTemplateExpression([string]$ExpressionText, $Parameters, $Variables, [System.Collections.Generic.List[string]]$ResolutionStack) { - $trimmedExpression = $ExpressionText.Trim() - if ($trimmedExpression -notmatch '^([A-Za-z_][A-Za-z0-9_]*)\s*\((.*)\)$') { - return $ExpressionText - } - - $functionName = $matches[1] - $argumentsText = $matches[2] - $resolvedArguments = @() - $result = $null - - foreach ($argument in $this.SplitExpressionArguments($argumentsText)) { - $resolvedArguments += ,($this.ResolveExpressionToken($argument, $Parameters, $Variables, $ResolutionStack)) - } - - switch ($functionName.ToLowerInvariant()) { - 'parameter' { $result = $this.GetParameterValue([string]$resolvedArguments[0], $Parameters); break } - 'parameters' { $result = $this.GetParameterValue([string]$resolvedArguments[0], $Parameters); break } - 'variable' { $result = $this.GetVariableValue([string]$resolvedArguments[0], $Parameters, $Variables, $ResolutionStack); break } - 'variables' { $result = $this.GetVariableValue([string]$resolvedArguments[0], $Parameters, $Variables, $ResolutionStack); break } - 'concat' { $result = [TemplateBuilder]::Concat($resolvedArguments); break } - 'tolower' { $result = [TemplateBuilder]::ToLower($resolvedArguments); break } - 'toupper' { $result = [TemplateBuilder]::ToUpper($resolvedArguments); break } - 'firstindexof' { $result = [TemplateBuilder]::FirstIndexOf($resolvedArguments); break } - 'lastindexof' { $result = [TemplateBuilder]::LastIndexOf($resolvedArguments); break } - 'indexof' { $result = [TemplateBuilder]::IndexOf($resolvedArguments); break } - 'substring' { $result = [TemplateBuilder]::Substring($resolvedArguments); break } - 'replace' { $result = [TemplateBuilder]::Replace($resolvedArguments); break } - default { - throw "Nicht unterstützte Template-Funktion '$functionName'" - return $null - } - } - - return $result - } - - hidden [string[]] SplitExpressionArguments([string]$ArgumentsText) { - $arguments = New-Object 'System.Collections.Generic.List[string]' - if ([string]::IsNullOrWhiteSpace($ArgumentsText)) { - return $arguments.ToArray() - } - - $builder = New-Object System.Text.StringBuilder - $depth = 0 - $inSingleQuote = $false - $inDoubleQuote = $false - - for ($i = 0; $i -lt $ArgumentsText.Length; $i++) { - $char = $ArgumentsText[$i] - - if ($char -eq "'" -and -not $inDoubleQuote) { - [void]$builder.Append($char) - if ($inSingleQuote -and $i + 1 -lt $ArgumentsText.Length -and $ArgumentsText[$i + 1] -eq "'") { - $i++ - [void]$builder.Append($ArgumentsText[$i]) - continue - } - - $inSingleQuote = -not $inSingleQuote - continue - } - - if ($char -eq '"' -and -not $inSingleQuote) { - $inDoubleQuote = -not $inDoubleQuote - [void]$builder.Append($char) - continue - } - - if (-not $inSingleQuote -and -not $inDoubleQuote) { - if ($char -eq '(') { - $depth++ - } - elseif ($char -eq ')') { - $depth-- - } - elseif ($char -eq ',' -and $depth -eq 0) { - $arguments.Add($builder.ToString().Trim()) - [void]$builder.Clear() - continue - } - } - - [void]$builder.Append($char) - } - - if ($builder.Length -gt 0 -or $ArgumentsText.Trim().Length -gt 0) { - $arguments.Add($builder.ToString().Trim()) - } - - return $arguments.ToArray() - } - - hidden [System.Object] ResolveExpressionToken([string]$Token, $Parameters, $Variables, [System.Collections.Generic.List[string]]$ResolutionStack) { - $trimmedToken = $Token.Trim() - if ([string]::IsNullOrWhiteSpace($trimmedToken)) { - return '' - } - - if ($this.IsTemplateExpression($trimmedToken)) { - return $this.EvaluateTemplateExpression($trimmedToken.Substring(1, $trimmedToken.Length - 2), $Parameters, $Variables, $ResolutionStack) - } - - if ($this.IsFunctionInvocation($trimmedToken)) { - return $this.EvaluateTemplateExpression($trimmedToken, $Parameters, $Variables, $ResolutionStack) - } - - if (($trimmedToken.StartsWith("'") -and $trimmedToken.EndsWith("'")) -or ($trimmedToken.StartsWith('"') -and $trimmedToken.EndsWith('"'))) { - return $this.UnquoteString($trimmedToken) - } - - if ($trimmedToken -match '^\$?true$') { - return $true - } - - if ($trimmedToken -match '^\$?false$') { - return $false - } - - if ($trimmedToken -match '^\$?null$') { - return $null - } - - if ($trimmedToken -match '^-?\d+$') { - return [int]$trimmedToken - } - - if ($trimmedToken -match '^-?\d+\.\d+$') { - return [double]$trimmedToken - } - - return $trimmedToken - } - - hidden [string] UnquoteString([string]$Value) { - if ($Value.StartsWith("'") -and $Value.EndsWith("'")) { - return ($Value.Substring(1, $Value.Length - 2) -replace "''", "'") - } - - if ($Value.StartsWith('"') -and $Value.EndsWith('"')) { - return $Value.Substring(1, $Value.Length - 2) - } - - return $Value - } - - hidden [System.Object] GetParameterValue([string]$ParameterName, $Parameters) { - if ($null -eq $Parameters -or -not $Parameters.Contains($ParameterName)) { - throw "Parameter '$ParameterName' nicht gefunden" - } - - $parameter = $Parameters[$ParameterName] - if ($parameter -is [System.Collections.IDictionary]) { - if ($parameter.Contains('Value') -and $null -ne $parameter.Value) { - return $parameter.Value - } - - if ($parameter.Contains('DefaultValue')) { - return $parameter.DefaultValue - } - } - - return $parameter - } - - hidden [System.Object] GetVariableValue([string]$VariableName, $Parameters, $Variables, [System.Collections.Generic.List[string]]$ResolutionStack) { - if ($null -eq $Variables -or -not $Variables.Contains($VariableName)) { - throw "Variable '$VariableName' nicht gefunden" - return $null - } - - if ($ResolutionStack.Contains($VariableName)) { - $cycle = @($ResolutionStack.ToArray()) + $VariableName - throw "Zirkuläre Variablenreferenz erkannt: $($cycle -join ' -> ')" - return $null - } - - $ResolutionStack.Add($VariableName) - $resolvedValue = $null - try { - $resolvedValue = $this.ResolveValueInternal($Variables[$VariableName], $Parameters, $Variables, $ResolutionStack) - } - finally { - [void]$ResolutionStack.Remove($VariableName) - } - - return $resolvedValue - } - } - - class TabControlBuilder : BaseComponent{ - [System.Windows.Forms.TabControl] $control - - TabControlBuilder() { - $this.control = New-Object System.Windows.Forms.TabControl - } - - [TabControlBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [TabControlBuilder] SetWidth([Int]$width) { - $this.control.Width = $width - return $this - } - - [TabControlBuilder] SetVisible([Boolean]$visible) { - $this.control.Visible = $visible - return $this - } - - [TabControlBuilder] SetSelectedIndex([int]$index) { - $this.control.SelectedIndex = $index - return $this - } - - [TabControlBuilder] AddTabPage([System.Windows.Forms.TabPage]$tabPage) { - $this.control.TabPages.Add($tabPage) | Out-Null - return $this - } - - [System.Windows.Forms.TabControl] Build() { - return $this.control - } - } - - class TabPageBuilder : BaseComponent{ - [System.Windows.Forms.TabPage]$control - - TabPageBuilder([System.String]$text) { - $this.control = New-Object System.Windows.Forms.TabPage - $this.control.Text = $text - } - - [TabPageBuilder] SetPadding([int]$all) { - $this.control.Padding = New-Object System.Windows.Forms.Padding($all) - return $this - } - - [TabPageBuilder] AddControl([System.Windows.Forms.Control]$childControl) { - $this.control.Controls.Add($childControl) - return $this - } - - [void] AddTo([System.Windows.Forms.Control]$parent) { - $parent.Controls.Add($this.control) - } - - [System.Windows.Forms.TabPage] Build() { - return $this.control - } - } - - class ListViewBuilder : BaseComponent { - [System.Windows.Forms.ListView]$control - - ListViewBuilder() { - $this.control = New-Object System.Windows.Forms.ListView - $this.control.View = 'Details' - } - - [ListViewBuilder] SetDock([System.String]$dock) { - $this.control.Dock = [System.Windows.Forms.DockStyle]::$dock - return $this - } - - [ListViewBuilder] SetView([System.String]$view) { - $this.control.View = [System.Windows.Forms.View]::$view - return $this - } - - [ListViewBuilder] SetFullRowSelect([bool]$select) { - $this.control.FullRowSelect = $select - return $this - } - - [ListViewBuilder] SetGridLines([bool]$gridLines) { - $this.control.GridLines = $gridLines - return $this - } - - [ListViewBuilder] AddColumn([System.String]$text, [int]$width) { - $this.control.Columns.Add($text, $width) | Out-Null - return $this - } - - [ListViewBuilder] AddDoubleClickHandler([scriptblock]$handler) { - $this.control.Add_DoubleClick($handler) - return $this - } - - [System.Windows.Forms.ListView] Build() { - return $this.control - } - } - #endregion - ->>>>>>> 7dd71be14c5216e6f7f99d006643ed1139a69376 Add-Type -AssemblyName System.Windows.Forms } @@ -3525,475 +16,5 @@ if ([System.Threading.Thread]::CurrentThread.GetApartmentState() -ne [System.Thr } } -<<<<<<< HEAD $coreScript = Join-Path -Path $PSScriptRoot -ChildPath 'Compiler.Core.ps1' & $coreScript @args -======= - $stateManager = [StateManager]::new() - $stateManager.SetStates(@{ - hasSelection = $false - isMerged = $false - isResolved = $false - }) - - # Menü erstellen - $menuBuilder = ( - [MenuBuilder]::new(). - BuildFromStructure($settingsManager.GetMenuStructure()). - WithStateManager($stateManager) - ) - - $menuHandlers = @{ - "Import" = @{ - Handler = { - Import-ConfigurationData - $statusBar.SetText("Status", "Deployment importiert.") - } - Condition = { - -not $stateManager.GetState("isMerged") - } - } - "Export" = @{ - Handler = { - Export-ConfigurationData - $statusBar.SetText("Status", "Deployment exportiert.") - } - Condition = { - $stateManager.GetState("isMerged") -eq $true - } - } - "Refresh" = @{ - Handler = { - - $statusBar.SetText("Status", "Wird aktualisiert...") - } - } - "Exit" = { - $form.Form.Close() - } - "OpenFolder" = @{ - Handler = { - $result = [DialogBuilder]::SelectFolder(). - SetDescription("Wählen Sie den Root-Ordner für Templates"). - SetSelectedPath($settingsManager.Get("RootPath", "C:\")). - SetShowNewFolderButton($true). - SetUseDescriptionForTitle($true). - Show() - - if ($result.Result) { - $settingsManager.Set("RootPath", $result.SelectedPath) - $statusBar.SetText("Status", "Ordner gesetzt: $($result.SelectedPath)") - #Load-Templates - } - } - } - "ResetMenu" = { - $result = [System.Windows.Forms.MessageBox]::Show( - "Möchten Sie das Menü auf die Standardeinstellungen zurücksetzen?`n`nDie Anwendung wird danach neu gestartet.", - "Menü zurücksetzen", - [System.Windows.Forms.MessageBoxButtons]::YesNo, - [System.Windows.Forms.MessageBoxIcon]::Question - ) - - if ($result -eq 'Yes') { - $settingsManager.ResetMenuStructure() - [System.Windows.Forms.MessageBox]::Show( - "Menü wurde zurückgesetzt. Bitte starten Sie die Anwendung neu.", - "Erfolg", - [System.Windows.Forms.MessageBoxButtons]::OK, - [System.Windows.Forms.MessageBoxIcon]::Information - ) - $form.Form.Close() - } - } - "About" = { - [System.Windows.Forms.MessageBox]::Show( - "DSC Tool v1.0`n`nEin modernes Tool zur Verwaltung von DSC-Konfigurationen.`n`n© 2024", - "Über DSC Tool", - [System.Windows.Forms.MessageBoxButtons]::OK, - [System.Windows.Forms.MessageBoxIcon]::Information - ) - } - } - - # Handler setzen - $menuBuilder.SetClickHandlersWithConditions($menuHandlers) - - # StatusBar erstellen - $statusBar = [StatusStripBuilder]::new() - - # FlowLayoutPanel erstellen - $flow = ( - [FlowLayoutPanelBuilder]::new(). - SetPadding(6). - Build() - ) - - ## Rechte Seite - # Rechtes Label - - $tabControl = ( - [TabControlBuilder]::new(). - SetDock("Fill"). - Build() - ) - - $buttonClear = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xed62). - SetToolTip("Clear"). - Build() - ) - - $tabControlButtonPanel = ( - [FlowLayoutPanelBuilder]::new(). - SetDock("Right"). - SetPadding(6). - SetWidth(52). - SetFlowDirection("TopDown"). - SetWrapContents($false). - AddControls(@($buttonClear)). - Build() - ) - - $tabPanel = ( - [PanelBuilder]::new(). - SetDock("Top"). - SetHeight(200). - BindEnabled({ - $stateManager.GetState("isResolved") -eq $true - }, $stateManager). - AddControls(@($tabControl,$tabControlButtonPanel)). - Build() - ) - - $rightLabel = ( - [LabelBuilder]::new("Datei-Inhalt / Details"). - SetDock('Top'). - SetHeight(24). - SetFont("Segoe UI", 9, [System.Drawing.FontStyle]::Bold). - SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft). - SetPadding(5, 0, 0, 0). - Build() - ) - - # TreeView - $treeView = ( - [TreeViewBuilder]::new(). - SetFont("Consolas", 10). - AddNode("Keine Auswahl"). - Build() - ) - - $buttonImport = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xed25). - SetToolTip("Import - Datei laden"). - BindEnabled({ - -not $stateManager.GetState("isMerged") - }, $stateManager). - SetClickHandler({ - Import-ConfigurationData - }). - Build() - ) - - $buttonMerge = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xe9f5). - SetToolTip("Merge - Ausgewählte Dateien zusammenführen"). - BindEnabled({ - $selectionList.Items.Count -gt 0 -and $stateManager.GetState("isMerged") -eq $false - }, $stateManager). - SetClickHandler({ - param($s, $e) - - if($selectionList.Items.Count -gt 0){ - Merge-Templates - $stateManager.SetState("isResolved",$true) - }else{ - [System.Windows.Forms.MessageBox]::Show("Keine Einträge vorhanden","Info",[System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information) - } - }). - Build() - ) - - $buttonClear = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xed62). - SetToolTip("Clear - TreeView leeren"). - BindEnabled({ - $treeView.Nodes.Count -gt 0 - }, $stateManager). - SetClickHandler({ - $treeView.Nodes.Clear() - $treeView.Nodes.Add("Keine Auswahl") | Out-Null - $statusBar.SetText("Status", "TreeView geleert") - $stateManager.SetStates(@{ - "isMerged" = $false - "isResolved" = $false - }) - }). - Build() - ) - - $buttonExport = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xe74e). - SetToolTip("Export - Als PSD1 speichern"). - BindEnabled({ - $stateManager.GetState("isResolved") -eq $true - }, $stateManager). - SetClickHandler({ - Export-ConfigurationData - }). - Build() - ) - - $treeButtonPanel = ( - [FlowLayoutPanelBuilder]::new(). - SetDock("Right"). - SetPadding(6). - SetWidth(52). - SetFlowDirection("TopDown"). - SetWrapContents($false). - AddControls(@($buttonImport, $buttonMerge, $buttonClear, $buttonExport)). - Build() - ) - - $treeViewPanel = ( - [PanelBuilder]::new(). - SetDock("Fill"). - AddControls(@($treeView,$treeButtonPanel)). - Build() - ) - - $selectionLabel = ( - [LabelBuilder]::new("Ausgewählte Dateien"). - SetHeight(20). - SetDock("Bottom"). - Build() - ) - - $selectionList = ( - [ListBoxBuilder]::new(). - SetFont("Segoe UI", 9). - SetDock('Fill'). # Füllt die GroupBox aus - SetHeight(120). - Build() - ) - - $buttonMoveUp = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xe74a). - SetToolTip("Element nach oben verschieben"). - BindEnabled({ - $selectionList.Items.Count -gt 1 - }, $stateManager). - SetClickHandler({ - $SelectedIndex = $selectionList.SelectedIndex - if ($SelectedIndex -gt 0) { - $item = $selectionList.Items[$SelectedIndex] - $selectionList.Items.RemoveAt($SelectedIndex) - $selectionList.Items.Insert($SelectedIndex-1, $item) - $selectionList.SelectedIndex = $SelectedIndex-1 - $stateManager.SetState("isMerged",$false) - } - }). - Build() - ) - - $buttonRemoveSelection = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xe894). - SetToolTip("Element löschen"). - BindEnabled({ - $selectionList.Items.Count -gt 0 - }, $stateManager). - SetClickHandler({ - $SelectedIndex = $selectionList.SelectedIndex - if ($SelectedIndex -ge 0) { - $removed = $selectionList.Items[$SelectedIndex] - $resp = [System.Windows.Forms.MessageBox]::Show("Eintrag wirklich löschen?`r`n$($removed.FullName)","Bestätigen",[System.Windows.Forms.MessageBoxButtons]::YesNo,[System.Windows.Forms.MessageBoxIcon]::Question) - if ($resp -eq [System.Windows.Forms.DialogResult]::Yes) { - $selectionList.Items.RemoveAt($SelectedIndex) - $stateManager.SetState("hasSelection", $selectionList.Items.Count -gt 0) - $stateManager.UpdateAllButtons() - $statusBar.SetText("Status","Eintrag entfernt: $($removed.FullName)") - if ($selectionList.Items.Count -eq 0) { - Update-TreeView - } else { - Merge-Templates - } - } - } else { - [System.Windows.Forms.MessageBox]::Show("Kein Eintrag ausgewählt","Info",[System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information) - } - }). - Build() - ) - - $buttonClearSelection = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xe74d). - SetToolTip("Element löschen"). - BindEnabled({ - $selectionList.Items.Count -gt 0 - }, $stateManager). - SetClickHandler({ - if ($SelectedIndex -ge 0) { - $selectionList.Items.Clear() - } else { - [System.Windows.Forms.MessageBox]::Show("Kein Eintrag vorhanden","Info",[System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information) - } - Update-TreeView - }). - Build() - ) - - $buttonMoveDown = ( - [ButtonBuilder]::new(). - SetFluentIcon([char]0xe74b). - SetToolTip("Element nach unten verschieben"). - BindEnabled({ - $selectionList.Items.Count -gt 1 - }, $stateManager). - SetClickHandler({ - $SelectedIndex = $selectionList.SelectedIndex - if ($SelectedIndex -ge 0 -and $SelectedIndex -lt ($selectionList.Items.Count - 1)) { - $item = $selectionList.Items[$SelectedIndex] - $selectionList.Items.RemoveAt($SelectedIndex) - $selectionList.Items.Insert($SelectedIndex+1, $item) - $selectionList.SelectedIndex = $SelectedIndex+1 - $stateManager.SetState("isMerged",$false) - } - }). - Build() - ) - - $selectionButtonPanel = ( - [FlowLayoutPanelBuilder]::new(). - SetDock("Right"). - SetPadding(6). - SetWidth(48). - SetFlowDirection("TopDown"). - SetWrapContents($false). - AddControls(@($buttonMoveUp,$buttonRemoveSelection,$buttonClearSelection,$buttonMoveDown)). - Build() - ) - - $selectionBottomPanel = ( - [PanelBuilder]::new(). - SetDock('Bottom'). - SetHeight(200). - AddControls(@($selectionList,$selectionButtonPanel)). - Build() - ) - - # SplitPanel erstellen - $splitPanel = ( - [SplitPanelBuilder]::new('Vertical', 0.30, 100, 150). - AddToPanel1($flow). - ClearPanel2(). - AddToPanel2($treeViewPanel). - AddToPanel2($rightLabel). - AddToPanel2($selectionLabel). - AddToPanel2($selectionBottomPanel). - AddToPanel2($tabPanel) - ) - - # Form erstellen - $form = ( - [FormBuilder]::new("Test"). - SetSize( - $settingsManager.Get("WindowWidth", 1024), - $settingsManager.Get("WindowHeight", 768) - ). - AddMenu($menuBuilder). - AddStatusBar($statusBar). - AddSplitPanel($splitPanel). - AddKeyDownHandler({ - param($s, $e) - - # Ctrl+S für Export - if ($e.Control -and $e.KeyCode -eq 'S') { - if ($stateManager.GetState("isMerged")) { - Export-ConfigurationData - } - $e.Handled = $true - } - - # Ctrl+O für Import - if ($e.Control -and $e.KeyCode -eq 'O') { - $buttonImport.PerformClick() - $e.Handled = $true - } - - # F5 für Refresh - if ($e.KeyCode -eq 'F5') { - Load-Templates - $e.Handled = $true - } - - # Ctrl+M für Merge - if ($e.Control -and $e.KeyCode -eq 'M') { - if ($selectionList.Items.Count -gt 0) { - Merge-Templates - } - $e.Handled = $true - } - }). - AddLoadHandler({ - # Beim Laden der Form - $rootPath = $settingsManager.Get("RootPath") - if ($rootPath -and (Test-Path $rootPath)) { - $statusBar.AddLabel("Status", "Lade gespeicherten Pfad: $rootPath") - } - - Load-Templates - - # Registriere Layout-Container für automatisches Resize - [BaseComponent]::AccessibilityManager.RegisterLayoutContainer($flow) - - # Registriere alle Controls für Accessibility - $form.RegisterAllAccessibleControls() | Out-Null - }). - AddFormClosedHandler({ - # Settings speichern - $settingsManager.Set("WindowWidth", $form.Form.Width) - $settingsManager.Set("WindowHeight", $form.Form.Height) - $settingsManager.Set("SplitterDistance", $splitPanel.SplitContainer.SplitterDistance) - - # Ressourcen freigeben - $treeView.Dispose() - $selectionList.Dispose() - $flow.Dispose() - }). - AddShownHandler({ - # ZUERST: SplitPanel initialisieren - $splitPanel.InitializeAfterShown($form.Form) - - # DANN: Padding setzen - $splitPanel.SetPanelPaddingWithMenu(1, $menuBuilder.GetMenuStrip(), 6, 6, 6) - $splitPanel.SetPanelPaddingWithMenu(2, $menuBuilder.GetMenuStrip(), 6, 6, $($statusBar.GetStatusStrip().Height + 6)) - - foreach($Groupbox in $flow.Controls){ - # GroupBox-Breite anpassen - $Groupbox.Width = $flow.ClientSize.Width - 20 - } - - $splitPanel.AutoSizeSplitterToPanel1Content() - - # Focus setzen - $treeView.Focus() - - # StatusBar Update - $statusBar.SetText("Status", "Initialisierung abgeschlossen") - }) - ) - - # Initial alle Button-States aktualisieren - $stateManager.UpdateAllButtons() - - $form.Show() ->>>>>>> 7dd71be14c5216e6f7f99d006643ed1139a69376 diff --git a/Functions/Export-ConfigurationData.ps1 b/Functions/Export-ConfigurationData.ps1 index 8a1b021..41029b1 100644 --- a/Functions/Export-ConfigurationData.ps1 +++ b/Functions/Export-ConfigurationData.ps1 @@ -10,8 +10,9 @@ function Export-ConfigurationData { ) if ($result.Result) { try { - $ConfigurationData = @{ - "Resources" = $(ConvertFrom-TreeView -TreeView $treeView -SkipRootNode) + $ConfigurationData = $script:ResolvedConfigurationData + if($null -eq $ConfigurationData){ + throw "Keine aufgelöste ConfigurationData zum Exportieren vorhanden." } Export-Hashtable -Hashtable $ConfigurationData -Path $result.FileName @@ -21,4 +22,4 @@ function Export-ConfigurationData { [System.Windows.Forms.MessageBox]::Show("Export war nicht erfolgreich", "Info", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) } } -} \ No newline at end of file +} diff --git a/Functions/Get-TemplatePreviewData.ps1 b/Functions/Get-TemplatePreviewData.ps1 new file mode 100644 index 0000000..f09e860 --- /dev/null +++ b/Functions/Get-TemplatePreviewData.ps1 @@ -0,0 +1,170 @@ +function Get-TemplatePreviewData { + [CmdletBinding()] + Param( + [Parameter(Mandatory = $true)] + [string] + $TemplatePath + ) + + if (-not (Test-Path -Path $TemplatePath -PathType Leaf)) { + throw "Template nicht gefunden: $TemplatePath" + } + + $directory = Split-Path -Path $TemplatePath -Parent + $defaultFiles = @(Get-ChildItem -Path $directory -Filter "*.psd1" -File -ErrorAction SilentlyContinue | + Where-Object { $_.BaseName -eq "Default" -or $_.BaseName -like "*.Default" } | + Sort-Object Name) + + $mergeFiles = @() + $mergeFiles += @($defaultFiles | ForEach-Object { $_.FullName }) + $mergeFiles += $TemplatePath + $mergedConfigurationData = $null + + foreach ($file in $mergeFiles) { + $templateData = Import-PowerShellDataFile -Path $file -ErrorAction Stop + + if ($null -eq $mergedConfigurationData) { + $mergedConfigurationData = $templateData + } + else { + $mergedConfigurationData = Merge-DSCConfigurationData -Template $mergedConfigurationData -Deployment $templateData + } + } + + $resolvedConfigurationData = $null + $resolveError = $null + + try { + $resolvedConfigurationData = Resolve-DSCConfigurationData -ConfigurationData $mergedConfigurationData -ErrorAction Stop + } + catch { + $resolveError = $_ + } + + $displayOrder = $null + if (Get-Command -Name Import-OrderedPowerShellDataFile -ErrorAction SilentlyContinue) { + foreach ($file in $mergeFiles) { + $orderedTemplateData = Import-OrderedPowerShellDataFile -Path $file -ErrorAction Stop + + if ($null -eq $displayOrder) { + $displayOrder = $orderedTemplateData + } + else { + $displayOrder = Merge-TemplatePreviewOrder -Base $displayOrder -Override $orderedTemplateData + } + } + } + + $displaySource = if ($null -ne $resolvedConfigurationData) { $resolvedConfigurationData } else { $mergedConfigurationData } + $displayConfigurationData = ConvertTo-TemplatePreviewDisplayOrder -Value $displaySource -Order $displayOrder + + [PSCustomObject]@{ + Files = $mergeFiles + Merged = $mergedConfigurationData + Resolved = $resolvedConfigurationData + Display = $displayConfigurationData + ResolveError = $resolveError + } +} + +function Test-TemplatePreviewDictionaryKey { + Param( + [Parameter(Mandatory = $true)] + [System.Collections.IDictionary] + $Dictionary, + + [Parameter(Mandatory = $true)] + [string] + $Key + ) + + if ($Dictionary -is [System.Collections.Specialized.OrderedDictionary]) { + return $Dictionary.Contains($Key) + } + + return $Dictionary.ContainsKey($Key) +} + +function Merge-TemplatePreviewOrder { + Param( + [AllowNull()] + $Base, + + [AllowNull()] + $Override + ) + + if ($Base -is [System.Collections.IDictionary] -and $Override -is [System.Collections.IDictionary]) { + $ordered = New-Object System.Collections.Specialized.OrderedDictionary + + foreach ($key in $Base.Keys) { + if (Test-TemplatePreviewDictionaryKey -Dictionary $Override -Key $key) { + $ordered.Add($key, (Merge-TemplatePreviewOrder -Base $Base[$key] -Override $Override[$key])) + } + else { + $ordered.Add($key, $Base[$key]) + } + } + + foreach ($key in $Override.Keys) { + if (-not (Test-TemplatePreviewDictionaryKey -Dictionary $ordered -Key $key)) { + $ordered.Add($key, $Override[$key]) + } + } + + return $ordered + } + + return $Override +} + +function ConvertTo-TemplatePreviewDisplayOrder { + Param( + [AllowNull()] + $Value, + + [AllowNull()] + $Order + ) + + if ($Value -is [System.Collections.IDictionary]) { + $ordered = New-Object System.Collections.Specialized.OrderedDictionary + $orderedKeys = @() + + if ($Order -is [System.Collections.IDictionary]) { + foreach ($key in $Order.Keys) { + if (Test-TemplatePreviewDictionaryKey -Dictionary $Value -Key $key) { + $orderedKeys += $key + $ordered.Add($key, (ConvertTo-TemplatePreviewDisplayOrder -Value $Value[$key] -Order $Order[$key])) + } + } + } + + foreach ($key in $Value.Keys) { + if ($orderedKeys -notcontains $key) { + $ordered.Add($key, (ConvertTo-TemplatePreviewDisplayOrder -Value $Value[$key] -Order $null)) + } + } + + return $ordered + } + + if ($Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string])) { + $items = @() + $index = 0 + + foreach ($item in $Value) { + $itemOrder = $null + if ($Order -is [System.Array] -and $Order.Count -gt $index) { + $itemOrder = $Order[$index] + } + + $items += ,(ConvertTo-TemplatePreviewDisplayOrder -Value $item -Order $itemOrder) + $index++ + } + + return ,$items + } + + return $Value +} diff --git a/Functions/Import-OrderedPowerShellDataFile.ps1 b/Functions/Import-OrderedPowerShellDataFile.ps1 new file mode 100644 index 0000000..ca5dbeb --- /dev/null +++ b/Functions/Import-OrderedPowerShellDataFile.ps1 @@ -0,0 +1,117 @@ +function Import-OrderedPowerShellDataFile { + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true)] + [string] + $Path + ) + + function ConvertTo-OrderedHashtable { + Param( + [Parameter(Mandatory=$true)] + $HashtableAst + ) + + $Ordered = New-Object System.Collections.Specialized.OrderedDictionary + $SortedPairs = $HashtableAst.KeyValuePairs | Sort-Object { $_.Item1.Extent.StartOffset } + + foreach($Pair in $SortedPairs){ + $Key = $Pair.Item1.Extent.Text.Trim("'`"") + $Ordered.Add($Key, (ConvertFrom-DataAst -Ast $Pair.Item2)) + } + + return $Ordered + } + + function ConvertFrom-DataAst { + Param( + [AllowNull()] + $Ast + ) + + if($null -eq $Ast){ + return $null + } + + if($Ast -is [System.Management.Automation.Language.HashtableAst]){ + return ConvertTo-OrderedHashtable -HashtableAst $Ast + } + + if($Ast -is [System.Management.Automation.Language.PipelineAst]){ + return ConvertFrom-DataAst -Ast $Ast.PipelineElements[0] + } + + if($Ast -is [System.Management.Automation.Language.CommandExpressionAst]){ + return ConvertFrom-DataAst -Ast $Ast.Expression + } + + if($Ast -is [System.Management.Automation.Language.ParenExpressionAst]){ + return ConvertFrom-DataAst -Ast $Ast.Pipeline + } + + if($Ast -is [System.Management.Automation.Language.StatementBlockAst]){ + $Items = @() + foreach($Statement in $Ast.Statements){ + $Items += ,(ConvertFrom-DataAst -Ast $Statement) + } + return ,$Items + } + + if($Ast -is [System.Management.Automation.Language.ArrayExpressionAst]){ + return @(ConvertFrom-DataAst -Ast $Ast.SubExpression) + } + + if($Ast -is [System.Management.Automation.Language.ArrayLiteralAst]){ + $Items = @() + foreach($Element in $Ast.Elements){ + $Items += ,(ConvertFrom-DataAst -Ast $Element) + } + return ,$Items + } + + if($Ast -is [System.Management.Automation.Language.StringConstantExpressionAst]){ + return $Ast.Value + } + + if($Ast -is [System.Management.Automation.Language.ExpandableStringExpressionAst]){ + return $Ast.Value + } + + if($Ast -is [System.Management.Automation.Language.ConstantExpressionAst]){ + return $Ast.Value + } + + if($Ast -is [System.Management.Automation.Language.VariableExpressionAst]){ + switch($Ast.VariablePath.UserPath){ + "true" { return $true } + "false" { return $false } + "null" { return $null } + } + } + + if($Ast -is [System.Management.Automation.Language.UnaryExpressionAst]){ + $ChildValue = ConvertFrom-DataAst -Ast $Ast.Child + if($Ast.TokenKind -eq [System.Management.Automation.Language.TokenKind]::Minus){ + return -1 * $ChildValue + } + return $ChildValue + } + + throw "Nicht unterstützter Ausdruck in PSD1: $($Ast.Extent.Text)" + } + + $Tokens = $null + $Errors = $null + $Ast = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$Tokens, [ref]$Errors) + + if($Errors.Count -gt 0){ + throw "Fehler beim Parsen der Datei: $($Errors[0].Message)" + } + + $HashtableAst = $Ast.Find({ $args[0] -is [System.Management.Automation.Language.HashtableAst] }, $true) + if($null -eq $HashtableAst){ + throw "Keine Hashtable in der Datei gefunden." + } + + return ConvertTo-OrderedHashtable -HashtableAst $HashtableAst +} diff --git a/Functions/Load-Templates.ps1 b/Functions/Load-Templates.ps1 index e513262..c817411 100644 --- a/Functions/Load-Templates.ps1 +++ b/Functions/Load-Templates.ps1 @@ -1,126 +1,172 @@ function Load-Templates { - $flow.SuspendLayout() $flow.Controls.Clear() - - # Lokales Tracking-Objekt + $selectionTracker = @{ LastSelectedListBox = $null } - if (-not (Test-Path -Path $($settingsManager.Get("TemplatePath")))) { - $statusBar.SetText("Status", "Root-Ordner nicht gefunden: $rootPath") + $templatePath = $settingsManager.Get("TemplatePath") + if (-not (Test-Path -Path $templatePath)) { + $statusBar.SetText("Status", "Template-Ordner nicht gefunden: $templatePath") + $flow.ResumeLayout() + return } - else { - try { - $Categories = Get-ChildItem -Path $($settingsManager.Get("TemplatePath")) -Directory -ErrorAction Stop - } - catch { - $statusBar.SetText("Status", "Fehler beim Laden: $($_.Exception.Message)") - [System.Windows.Forms.MessageBox]::Show( - "Konnte Kategorien nicht laden: $($_.Exception.Message)", - "Fehler", - [System.Windows.Forms.MessageBoxButtons]::OK, - [System.Windows.Forms.MessageBoxIcon]::Error - ) - return - } - if ($Categories.Count -eq 0) { - $labelNoCategories = ( - [LabelBuilder]::new("Keine Unterordner gefunden.", 24). - SetDock('Top'). - SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft). - SetPadding(5, 0, 0, 0). - Build() - ) - $flow.Controls.Add($labelNoCategories) - return - } - else { - foreach ($Categorie in $Categories) { - - $GroupBox = ( - [GroupBoxBuilder]::new($Categorie.Name). - #SetAutoSize($true). - SetWidth(0). - SetHeight(90). - SetMargin(4). - SetPadding(10). - AddTo($flow) - ) - - $GroupBox.Tag = $Categorie.Name - - $Files = Get-ChildItem -Path $Categorie.FullName -Filter "*.psd1" -File -ErrorAction SilentlyContinue | Sort-Object Name - if ($Files.Count -eq 0) { - $ListBox = ( - [ListBoxBuilder]::new(). - SetDock('Fill'). # Füllt die GroupBox aus - AddItem("Keine Templates"). - AddTo($GroupBox) - ) + + try { + $categories = @(Get-ChildItem -Path $templatePath -Directory -ErrorAction Stop | Where-Object { + @(Get-ChildItem -Path $_.FullName -Filter "*.psd1" -File -ErrorAction SilentlyContinue).Count -gt 0 + }) + } + catch { + $statusBar.SetText("Status", "Fehler beim Laden: $($_.Exception.Message)") + [System.Windows.Forms.MessageBox]::Show( + "Konnte Kategorien nicht laden: $($_.Exception.Message)", + "Fehler", + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Error + ) + $flow.ResumeLayout() + return + } + + if ($categories.Count -eq 0) { + $labelNoCategories = ( + [LabelBuilder]::new("Keine Templates gefunden.", 24). + SetDock('Top'). + SetTextAlign([System.Drawing.ContentAlignment]::MiddleLeft). + SetPadding(5, 0, 0, 0). + Build() + ) + $flow.Controls.Add($labelNoCategories) + $flow.ResumeLayout() + return + } + + foreach ($category in $categories) { + $groupBoxWidth = [Math]::Max(($flow.ClientSize.Width - 20), 220) + + $groupBox = ( + [GroupBoxBuilder]::new($category.Name). + SetWidth($groupBoxWidth). + SetHeight(90). + SetMargin(4). + SetPadding(10). + AddTo($flow) + ) + + $groupBox.Tag = $category.Name + + $files = @(Get-ChildItem -Path $category.FullName -Filter "*.psd1" -File -ErrorAction SilentlyContinue | + Where-Object { $_.BaseName -ne "Default" -and $_.BaseName -notlike "*.Default" } | + Sort-Object Name) + + $listBox = ( + [ListBoxBuilder]::new(). + SetDock('Fill'). + AddSelectedIndexChangedHandler({ + param($s, $e) + + if ($null -ne $selectionTracker.LastSelectedListBox -and $selectionTracker.LastSelectedListBox -ne $s) { + $selectionTracker.LastSelectedListBox.ClearSelected() } - else { - - $ListBox = ( - [ListBoxBuilder]::new(). - SetDock('Fill'). - AddSelectedIndexChangedHandler({ - param($s, $e) - if ($null -ne $selectionTracker.LastSelectedListBox -and - $selectionTracker.LastSelectedListBox -ne $s) { - - # Deselektiere die vorherige ListBox - $selectionTracker.LastSelectedListBox.ClearSelected() - } - - # Speichere die aktuelle ListBox - $selectionTracker.LastSelectedListBox = $s + $selectionTracker.LastSelectedListBox = $s + $selectedItem = $s.SelectedItem - $selectedItem = $s.SelectedItem - if ($null -ne $selectedItem -and ($selectedItem -isnot [string])) { - $currentGroupBox = $s.Parent - $statusBar.SetText("Status", "Ausgewählt: $($selectedItem.FullName) [Kategorie: $($currentGroupBox.Tag)]") - Show-Template -Template $([TemplateBuilder]::new($selectedItem.FullName).ResolveDeploymentDataVariables()) - } - }.GetNewClosure()). - AddMouseDoubleClickHandler({ - param($s, $e) - $selectedItem = $s.SelectedItem - if ($null -ne $selectedItem -and ($selectedItem -isnot [string])) { - $fullPath = $selectedItem.FullName - if (-not (Test-Path $fullPath)) { - [System.Windows.Forms.MessageBox]::Show("Datei nicht gefunden: $fullPath", "Fehler", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) - return - } - $newItem = New-Object PSObject -Property @{ BaseName = [System.IO.Path]::GetFileNameWithoutExtension($fullPath); FullName = $fullPath } - if (-not ($selectionList.Items | Where-Object { $_.FullName -eq $newItem.FullName })) { - $selectionList.Items.Add($newItem) | Out-Null - $stateManager.SetState("hasSelection", $true) - $stateManager.SetState("isMerged", $false) - $stateManager.UpdateAllButtons() - $statusBar.SetText("Status", "Zur Auswahl hinzugefügt: $fullPath") - } - else { - $statusBar.SetText("Status", "Datei bereits in der Auswahl") - } - } - }) - ) + if ($null -ne $selectedItem -and ($selectedItem -isnot [string])) { + $currentGroupBox = $s.Parent + $statusBar.SetText("Status", "Ausgewählt: $($selectedItem.FullName) [Kategorie: $($currentGroupBox.Tag)]") - foreach ($file in $files) { - $item = New-Object PSObject -Property @{ BaseName = $file.BaseName; FullName = $file.FullName } - $ListBox.AddItem($item) - $ListBox.AddTo($GroupBox) + try { + if (-not (Get-Command -Name Get-TemplatePreviewData -ErrorAction SilentlyContinue)) { + $previewFunctionPath = Join-Path -Path $settingsManager.Get("FunctionsPath") -ChildPath "Get-TemplatePreviewData.ps1" + if (Test-Path -Path $previewFunctionPath -PathType Leaf) { + . $previewFunctionPath + } + } + + if (-not (Get-Command -Name Get-TemplatePreviewData -ErrorAction SilentlyContinue)) { + $templateData = Import-OrderedPowerShellDataFile -Path $selectedItem.FullName -ErrorAction Stop + Show-Template -Template $templateData + $statusBar.SetText("Status", "Vorschau ohne Default-Merge geladen: Get-TemplatePreviewData ist nicht verfügbar") + return + } + + $preview = Get-TemplatePreviewData -TemplatePath $selectedItem.FullName -ErrorAction Stop + $previewData = if ($null -ne $preview.Display) { $preview.Display } elseif ($null -ne $preview.Resolved) { $preview.Resolved } else { $preview.Merged } + + Show-Template -Template $previewData + Update-ParametersPanel -ConfigurationData $preview.Merged + + if ($null -ne $preview.ResolveError) { + $statusBar.SetText("Status", "Vorschau gemerged, Resolve unvollständig: $($preview.ResolveError.Exception.Message)") + } + else { + $statusBar.SetText("Status", "Vorschau geladen: $($preview.Files.Count) Datei(en) inklusive Defaults") + } + } + catch { + [System.Windows.Forms.MessageBox]::Show( + "Datei konnte nicht geladen werden: $($_.Exception.Message)", + "Fehler", + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Error + ) } } + }.GetNewClosure()). + AddMouseDoubleClickHandler({ + param($s, $e) + + $selectedItem = $s.SelectedItem + if ($null -ne $selectedItem -and ($selectedItem -isnot [string])) { + $fullPath = $selectedItem.FullName + if (-not (Test-Path $fullPath)) { + [System.Windows.Forms.MessageBox]::Show("Datei nicht gefunden: $fullPath", "Fehler", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) + return + } + + $newItem = New-Object PSObject -Property @{ + BaseName = [System.IO.Path]::GetFileNameWithoutExtension($fullPath) + FullName = $fullPath + } + + if (-not ($selectionList.Items | Where-Object { $_.FullName -eq $newItem.FullName })) { + $selectionList.Items.Add($newItem) | Out-Null + $stateManager.SetState("hasSelection", $true) + $stateManager.SetState("isMerged", $false) + $stateManager.UpdateAllButtons() + $statusBar.SetText("Status", "Zur Auswahl hinzugefügt: $fullPath") + } + else { + $statusBar.SetText("Status", "Datei bereits in der Auswahl") + } + } + }). + AddTo($groupBox) + ) + + if($files.Count -eq 0){ + $listBox.Items.Add("Keine Templates vorhanden") | Out-Null + }else{ + foreach ($file in $files) { + $item = New-Object PSObject -Property @{ + BaseName = $file.BaseName + FullName = $file.FullName + } + $listBox.Items.Add($item) | Out-Null } - $flow.ResumeLayout() } } - + + $flow.ResumeLayout() + + foreach ($groupBox in $flow.Controls) { + $groupBox.Width = [Math]::Max(($flow.ClientSize.Width - 20), 220) + } + $form.Form.Invoke([Action] { - $splitPanel.AutoSizeSplitterToPanel1Content() - }) -} \ No newline at end of file + $splitPanel.AutoSizeSplitterToPanel1Content() + }) +} diff --git a/Functions/Merge-ConfigurationData.ps1 b/Functions/Merge-ConfigurationData.ps1 deleted file mode 100644 index 0cc1185..0000000 --- a/Functions/Merge-ConfigurationData.ps1 +++ /dev/null @@ -1,83 +0,0 @@ -function Merge-ConfigurationData { - [CmdletBinding()] - Param( - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] - $Template, - [Parameter(Mandatory = $true)] - [System.Collections.Hashtable] - $Deployment, - [Parameter(Mandatory = $false)] - [System.Collections.Hashtable] - $Output - ) - - # Prüfe auf zirkuläre Referenzen - if ($Template -eq $Deployment) { - throw "Zirkuläre Referenz erkannt" - } - - if ($Output -eq $null) { - $Output = $Deployment - } - - foreach ($Property in $Template.GetEnumerator()) { - if ($Property.Value -is [System.Collections.Hashtable]) { - Write-Verbose "Key [$($Property.Name)] is a Hashtable" - if ($null -ne $Deployment.$($Property.Name)) { - Write-Verbose "Key [$($Property.Name)] is present in Deployment Data" - $Output.($Property.Name) = Merge-ConfigurationData -Template $Template.$($Property.Name) -Deployment $Deployment.$($Property.Name) -Output $Output.$($Property.Name) - } - else { - Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data" - $Output.Add($($Property.Name), $Template.$($Property.Name)) - } - } - elseif ($Property.Value -is [System.Collections.Specialized.OrderedDictionary]) { - Write-Verbose "Key [$($Property.Name)] is a Ordered Dictionary" - if ($null -ne $Deployment.$($Property.Name)) { - Write-Verbose "Key [$($Property.Name)] is present in Deployment Data" - $Output.($Property.Name) = Merge-ConfigurationData -Template $Template.$($Property.Name) -Deployment $Deployment.$($Property.Name) -Output $Output.$($Property.Name) - } - else { - Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data" - $Output.Add($($Property.Name), $Template.$($Property.Name)) - } - } - elseif ($Property.Value -is [System.Array]) { - Write-Verbose "$($Property.Name) is ein Array" - Write-Verbose "Total Items in Template Array [$($Property.Value.Count)]" - Write-Verbose "Total Items in Deployment Array [$($Deployment.$($Property.Name).Count)]" - if ($null -ne $Deployment.$($Property.Name)) { - Write-Verbose "Array is defined in Deployment" - for ($i = 0; $i -lt $Property.Value.Count; $i++) { - - $SearchItem = $($Property.Value[$i].GetEnumerator() | Where-Object { ($_.Value -is [String]) -and ($_.Name -like "*Name") })[0] - if ($($Deployment.$($Property.Name) | ? { $_.($SearchItem.Name) -eq $SearchItem.Value })) { - Merge-ConfigurationData -Template $Property.Value[$i] -Deployment $($Deployment.$($Property.Name) | ? { $_.($SearchItem.Name) -eq $SearchItem.Value }) -Output $($Output.$($Property.Name) | ? { $_.($SearchItem.Name) -eq $SearchItem.Value }) | Out-Null - } - else { - Write-Verbose "Pair $($Key.Name) - $($Key.Value) not present" - $Output.$($Property.Name) += $Property.Value[$i] - } - } - } - else { - Write-Verbose "Array is not defined in Deployment" - $Output.$($Property.Name) = $Template.$($Property.Name) - } - } - else { - Write-Verbose "$($Property.Name) is a String or Integer Value" - if ($null -eq $Deployment.$($Property.Name)) { - - $Output.Add($Property.Name, $Template.($Property.Name)) - - } - elseif ($Deployment.$($Property.Name) -ne $Property.Value) { - - } - } - } - return $Output -} \ No newline at end of file diff --git a/Functions/Merge-Templates.ps1 b/Functions/Merge-Templates.ps1 index 462a9a1..3488808 100644 --- a/Functions/Merge-Templates.ps1 +++ b/Functions/Merge-Templates.ps1 @@ -1,36 +1,74 @@ function Merge-Templates { $Errors = @() - [System.Collections.Hashtable] $ConfigurationData = @{} - #[System.Collections.Specialized.OrderedDictionary] $ConfigurationData = @{} + $MergedConfigurationData = $null + $MergeFiles = @() + $AddedDefaultFiles = @{} for ($i = 0; $i -lt $selectionList.Items.Count; $i++) { $item = $selectionList.Items[$i] $file = $item.FullName - if (-not (Test-Path $file)) { $Errors += "Datei nicht gefunden: $file"; continue } + if (-not (Test-Path $file)) { + $Errors += "Datei nicht gefunden: $file" + continue + } + + $directory = Split-Path -Path $file -Parent + $defaultFiles = @(Get-ChildItem -Path $directory -Filter "*.psd1" -File -ErrorAction SilentlyContinue | + Where-Object { $_.BaseName -eq "Default" -or $_.BaseName -like "*.Default" } | + Sort-Object Name) + + foreach($defaultFile in $defaultFiles){ + if(-not $AddedDefaultFiles.ContainsKey($defaultFile.FullName)){ + $MergeFiles += $defaultFile.FullName + $AddedDefaultFiles[$defaultFile.FullName] = $true + } + } + + $MergeFiles += $file + } + + foreach($file in $MergeFiles){ try { try { - $TemplateData = [TemplateBuilder]::new($file).Template + $TemplateData = Import-PowerShellDataFile -Path $file -ErrorAction Stop } catch { - $Errors += "Datei konnte nicht importiert werden" + $Errors += "Datei konnte nicht importiert werden: $file" continue } - $ConfigurationData = Merge-ConfigurationData -Template $ConfigurationData -Deployment $TemplateData + if($null -eq $MergedConfigurationData){ + $MergedConfigurationData = $TemplateData + }else{ + $MergedConfigurationData = Merge-DSCConfigurationData -Template $MergedConfigurationData -Deployment $TemplateData + } } catch { $Errors += "Fehler beim Verarbeiten $($file): $($_.Exception.Message)" } } - if ($null -ne $ConfigurationData) { - Update-TreeView -ConfigurationData $([TemplateBuilder]::new($ConfigurationData).ResolveDeploymentDataVariables()) - $statusBar.SetText("Status", "Merge erfolgreich: $($selectionList.Items.Count) Dateien") + if ($null -ne $MergedConfigurationData) { + try { + $script:MergedConfigurationData = $MergedConfigurationData + $script:ResolvedConfigurationData = Resolve-DSCConfigurationData -ConfigurationData $MergedConfigurationData + } + catch { + $Errors += "Fehler beim Auflösen der ConfigurationData: $($_.Exception.Message)" + $script:ResolvedConfigurationData = $null + } + + if($null -ne $script:ResolvedConfigurationData){ + Update-TreeView -ConfigurationData $script:ResolvedConfigurationData + }else{ + Update-TreeView -ConfigurationData $MergedConfigurationData + } + + $statusBar.SetText("Status", "Merge erfolgreich: $($selectionList.Items.Count) Queue-Dateien, $($MergeFiles.Count) inklusive Defaults") } else { - - Update-TreeView -ConfigurationData $ConfigurationData + Update-TreeView -ConfigurationData $MergedConfigurationData $statusLabel.Text = "Merge ergab kein Ergebnis" } @@ -38,7 +76,6 @@ function Merge-Templates { [System.Windows.Forms.MessageBox]::Show(($Errors -join "`r`n"), "Merge Warnungen", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Warning) return } - else { - return $ConfigurationData - } + + return $script:ResolvedConfigurationData } diff --git a/Functions/Show-Template.ps1 b/Functions/Show-Template.ps1 index 561d5d4..bbe5a7d 100644 --- a/Functions/Show-Template.ps1 +++ b/Functions/Show-Template.ps1 @@ -1,10 +1,15 @@ function Show-Template { Param( - [System.Collections.Hashtable] $Template + $Template ) $treeView.Nodes.Clear() $tempBuilder = [TreeViewBuilder]::new() $tempBuilder.control = $treeView - $tempBuilder.LoadTemplate($Template, "Template") -} \ No newline at end of file + + if($null -ne $Template -and $Template.Contains("Resources")){ + $tempBuilder.LoadTemplate($Template["Resources"], "Template") + }else{ + $treeView.Nodes.Add("No resources found") | Out-Null + } +} diff --git a/Functions/Update-ParametersPanel.ps1 b/Functions/Update-ParametersPanel.ps1 index 9c899e9..4728469 100644 --- a/Functions/Update-ParametersPanel.ps1 +++ b/Functions/Update-ParametersPanel.ps1 @@ -2,54 +2,64 @@ function Update-ParametersPanel { Param( [System.Collections.Hashtable] $ConfigurationData ) - - if ($ConfigurationData.Contains("Parameters") -or $ConfigurationData.Contains("Variables")) { - if ($ConfigurationData.Contains("Parameters")) { - if (!($tabControl.Controls | ? { $_.Text -eq "Parameters" })) { - $ParametersTabPage = ( - [TabPageBuilder]::new("Parameters"). - Build() - ) - } - - $GridView = ( - [DataGridViewBuilder]::new(). - SetHeaderColumns(@("Name", "Value")). - SetHeaderColumnReadOnly("Name"). - Build() - ) - - foreach ($Parameter in $ConfigurationData.Parameters.GetEnumerator()) { - $GridView.Rows.Add($Parameter.Name, $($Parameter.Value.Value)) | Out-Null - - } - $ParametersTabPage.Controls.Add($GridView) - $tabControl.Controls.Add($ParametersTabPage) - - } - - if ($ConfigurationData.Contains("Variables")) { - if (!($tabControl.Controls | ? { $_.Text -eq "Variables" })) { - $VariablesTabPage = ( - [TabPageBuilder]::new("Variables"). - Build() - ) - } - - $GridView = ( - [DataGridViewBuilder]::new(). - SetHeaderColumns(@("Name", "Value")). - SetHeaderColumnReadOnly("Name"). - Build() - ) - - foreach ($Variable in $ConfigurationData.Variables.GetEnumerator()) { - $GridView.Rows.Add($Variable.Name, $($Variable.Value)) | Out-Null - - } - $VariablesTabPage.Controls.Add($GridView) - $tabControl.Controls.Add($VariablesTabPage) + foreach ($tabName in @("Parameters", "Variables")) { + $existingTabs = @($tabControl.Controls | Where-Object { $_.Text -eq $tabName }) + foreach ($tab in $existingTabs) { + $tabControl.Controls.Remove($tab) + $tab.Dispose() } } -} \ No newline at end of file + + if ($null -eq $ConfigurationData) { + return + } + + if ($ConfigurationData.Contains("Parameters")) { + $parametersTabPage = ( + [TabPageBuilder]::new("Parameters"). + Build() + ) + + $gridView = ( + [DataGridViewBuilder]::new(). + SetHeaderColumns(@("Name", "Value", "Type", "Required")). + SetHeaderColumnReadOnly("Name"). + Build() + ) + + foreach ($parameter in $ConfigurationData.Parameters.GetEnumerator()) { + $value = $parameter.Value + $gridView.Rows.Add( + $parameter.Name, + $value.Value, + $value.Type, + $value.Required + ) | Out-Null + } + + $parametersTabPage.Controls.Add($gridView) + $tabControl.Controls.Add($parametersTabPage) + } + + if ($ConfigurationData.Contains("Variables")) { + $variablesTabPage = ( + [TabPageBuilder]::new("Variables"). + Build() + ) + + $gridView = ( + [DataGridViewBuilder]::new(). + SetHeaderColumns(@("Name", "Value")). + SetHeaderColumnReadOnly("Name"). + Build() + ) + + foreach ($variable in $ConfigurationData.Variables.GetEnumerator()) { + $gridView.Rows.Add($variable.Name, $variable.Value) | Out-Null + } + + $variablesTabPage.Controls.Add($gridView) + $tabControl.Controls.Add($variablesTabPage) + } +} diff --git a/Functions/Update-Treeview.ps1 b/Functions/Update-Treeview.ps1 index 69ae69a..df876d0 100644 --- a/Functions/Update-Treeview.ps1 +++ b/Functions/Update-Treeview.ps1 @@ -5,13 +5,23 @@ function Update-TreeView { if ($null -ne $ConfigurationData) { $tempBuilder = [TreeViewBuilder]::new() $tempBuilder.control = $treeView - $tempBuilder.LoadTemplate($ConfigurationData['Resources'], "Deployment") + if($ConfigurationData.ContainsKey("Resources")){ + $tempBuilder.LoadTemplate($ConfigurationData['Resources'], "Deployment") + }else{ + $treeView.Nodes.Clear() + $treeView.Nodes.Add("No resources found") | Out-Null + } $statusBar.SetText("Status", "Merged: Anzeige aktualisiert") $stateManager.SetState("isMerged", $true) + $stateManager.SetState("isResolved", $null -ne $script:ResolvedConfigurationData) $stateManager.UpdateAllButtons() # Parameter und Variablen Panel aktualisieren - Update-ParametersPanel -ConfigurationData $ConfigurationData + if($null -ne $script:MergedConfigurationData){ + Update-ParametersPanel -ConfigurationData $script:MergedConfigurationData + }else{ + Update-ParametersPanel -ConfigurationData $ConfigurationData + } } else { @@ -22,4 +32,4 @@ function Update-TreeView { # Panel ausblenden $parametersPanel.Visible = $false } -} \ No newline at end of file +} diff --git a/Templates/Environment/BGW-LAN.psd1 b/Templates/Environment/BGW-LAN.psd1 new file mode 100644 index 0000000..e390407 --- /dev/null +++ b/Templates/Environment/BGW-LAN.psd1 @@ -0,0 +1,13 @@ +@{ + Parameters = @{ + DomainLabel = @{ + Value = 'LAN' + } + DomainFQDN = @{ + Value = 'bgw-online.de' + } + DomainNetBIOS = @{ + Value = 'BGW-Online' + } + } +} \ No newline at end of file diff --git a/Templates/Environment/Environment.Default.psd1 b/Templates/Environment/Environment.Default.psd1 index e891779..e49d4a3 100644 --- a/Templates/Environment/Environment.Default.psd1 +++ b/Templates/Environment/Environment.Default.psd1 @@ -42,6 +42,89 @@ } } } + + ForestMode = @{ + Type = 'string' + DefaultValue = 'WinThreshold' + AllowedValues = @( + 'Win2012R2', + 'WinThreshold' + ) + Metadata = @{ + Description = @{ + 'de-DE' = 'Funktionsebene des Active-Directory-Forests.' + 'en-US' = 'Functional level of the Active Directory forest.' + } + } + } + + DomainMode = @{ + Type = 'string' + DefaultValue = 'WinThreshold' + AllowedValues = @( + 'Win2012R2', + 'WinThreshold' + ) + Metadata = @{ + Description = @{ + 'de-DE' = 'Funktionsebene der Active-Directory-Domaene.' + 'en-US' = 'Functional level of the Active Directory domain.' + } + } + } + + DefaultSiteName = @{ + Type = 'string' + DefaultValue = 'Default-First-Site-Name' + Required = $true + MinLength = 1 + MaxLength = 64 + Metadata = @{ + Description = @{ + 'de-DE' = 'Standard-AD-Sitename fuer Domaenencontroller und Subnetze.' + 'en-US' = 'Default AD site name for domain controllers and subnets.' + } + } + } + + DefaultSubnet = @{ + Type = 'string' + DefaultValue = '' + Required = $false + Pattern = '^$|^\d{1,3}(\.\d{1,3}){3}/\d{1,2}$' + Metadata = @{ + Description = @{ + 'de-DE' = 'Optionales Standard-Subnetz im CIDR-Format.' + 'en-US' = 'Optional default subnet in CIDR notation.' + } + } + } + + DomainAdministratorCredentialName = @{ + Type = 'string' + DefaultValue = 'DomainAdministrator' + Required = $true + Sensitive = $true + Metadata = @{ + Description = @{ + 'de-DE' = 'Name der Credential-Referenz fuer den Domaenenadministrator.' + 'en-US' = 'Name of the credential reference for the domain administrator.' + } + } + } + + SafeModeAdministratorPasswordSecretName = @{ + Type = 'string' + DefaultValue = 'SafeModeAdministratorPassword' + Required = $true + Sensitive = $true + Metadata = @{ + Description = @{ + 'de-DE' = 'Name der Secret-Referenz fuer das Safe-Mode-Administrator-Kennwort.' + 'en-US' = 'Name of the secret reference for the safe mode administrator password.' + } + } + } } Resources = @{ @@ -158,4 +241,4 @@ } } } -} \ No newline at end of file +}