From 846dccf468cfce6501c5ce5fd84df006d374a833 Mon Sep 17 00:00:00 2001 From: Torsten Brendgen Date: Sat, 27 Jun 2026 23:18:34 +0200 Subject: [PATCH] clean dev commit --- Compiler.Core.ps1 | 3813 ++++++++++++++++ Compiler.ps1 | 3824 +---------------- Deployments/merged_config.psd1 | 93 - Templates/Environment/Contoso.psd1 | 14 - .../Environment/Environment.Default.psd1 | 161 + .../Service/SharePointServer.Default.psd1 | 200 + Templates/Service/SharePointServer.psd1 | 142 - 7 files changed, 4189 insertions(+), 4058 deletions(-) create mode 100644 Compiler.Core.ps1 delete mode 100644 Deployments/merged_config.psd1 delete mode 100644 Templates/Environment/Contoso.psd1 create mode 100644 Templates/Environment/Environment.Default.psd1 create mode 100644 Templates/Service/SharePointServer.Default.psd1 delete mode 100644 Templates/Service/SharePointServer.psd1 diff --git a/Compiler.Core.ps1 b/Compiler.Core.ps1 new file mode 100644 index 0000000..050c4ac --- /dev/null +++ b/Compiler.Core.ps1 @@ -0,0 +1,3813 @@ + using namespace System.Windows.Forms + using assembly System.Windows.Forms + using assembly System.Drawing + 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([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 + + $ast = [System.Management.Automation.Language.Parser]::ParseFile( + $TemplatePath, + [ref]$tokens, + [ref]$errors + ) + + $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($HashtableAst){ + + # Verwende OrderedDictionary statt [ordered]@{} + $ordered = New-Object System.Collections.Specialized.OrderedDictionary + + # Sortiere KeyValuePairs nach ihrer Position im Quelltext + $sortedKvps = $HashtableAst.KeyValuePairs | Sort-Object { $_.Item1.Extent.StartOffset } + + foreach ($kvp in $sortedKvps) { + # Schlüssel extrahieren + $key = $kvp.Item1.Extent.Text -replace '[''"]', '' + + # Wert verarbeiten + $valueAst = $kvp.Item2 + + # Suche nach HashtableAst in PipelineAst + $hashtable = $null + if ($valueAst -is [System.Management.Automation.Language.HashtableAst]) { + $hashtable = $valueAst + } + elseif ($valueAst -is [System.Management.Automation.Language.PipelineAst]) { + # Suche HashtableAst innerhalb der Pipeline + $hashtable = $valueAst.Find({ + $args[0] -is [System.Management.Automation.Language.HashtableAst] + }, $false) + } + + if ($hashtable) { + $value = $this.ConvertToOrderedHashtable($hashtable) + } + elseif ($valueAst -is [System.Management.Automation.Language.ArrayLiteralAst]) { + $value = @() + foreach ($element in $valueAst.Elements) { + if ($element -is [System.Management.Automation.Language.HashtableAst]) { + $value += $this.ConvertToOrderedHashtable($element) + } + else { + $value += Invoke-Expression $element.Extent.Text + } + } + } + else { + try { + $value = Invoke-Expression $valueAst.Extent.Text + } + catch { + $value = $valueAst.Extent.Text + } + } + + $ordered.Add($key, $value) + } + + 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{ + [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 + + $settingsManager = [SettingsManager]::new("DSC Tool") + + # Verwendung + $logManager = [LogManager]::new("DSC Tool") + $logManager.Info("Anwendung gestartet") + + [BaseComponent]::InitializeShared($settingsManager, $logManager) + + foreach($function in $(Get-ChildItem -Path $settingsManager.Get("FunctionsPath") -Recurse -Filter "*.ps1" -File)){ + $logManager.Info("Lade Funktion: $($function.FullName)") + try{ + . $function.FullName + }catch{ + $logManager.Error("Fehler beim Laden: $_") + } + } + + $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() diff --git a/Compiler.ps1 b/Compiler.ps1 index b87e362..f932d05 100644 --- a/Compiler.ps1 +++ b/Compiler.ps1 @@ -1,3814 +1,20 @@ - 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([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 - - $ast = [System.Management.Automation.Language.Parser]::ParseFile( - $TemplatePath, - [ref]$tokens, - [ref]$errors - ) - - $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($HashtableAst){ - - # Verwende OrderedDictionary statt [ordered]@{} - $ordered = New-Object System.Collections.Specialized.OrderedDictionary - - # Sortiere KeyValuePairs nach ihrer Position im Quelltext - $sortedKvps = $HashtableAst.KeyValuePairs | Sort-Object { $_.Item1.Extent.StartOffset } - - foreach ($kvp in $sortedKvps) { - # Schlüssel extrahieren - $key = $kvp.Item1.Extent.Text -replace '[''"]', '' - - # Wert verarbeiten - $valueAst = $kvp.Item2 - - # Suche nach HashtableAst in PipelineAst - $hashtable = $null - if ($valueAst -is [System.Management.Automation.Language.HashtableAst]) { - $hashtable = $valueAst - } - elseif ($valueAst -is [System.Management.Automation.Language.PipelineAst]) { - # Suche HashtableAst innerhalb der Pipeline - $hashtable = $valueAst.Find({ - $args[0] -is [System.Management.Automation.Language.HashtableAst] - }, $false) - } - - if ($hashtable) { - $value = $this.ConvertToOrderedHashtable($hashtable) - } - elseif ($valueAst -is [System.Management.Automation.Language.ArrayLiteralAst]) { - $value = @() - foreach ($element in $valueAst.Elements) { - if ($element -is [System.Management.Automation.Language.HashtableAst]) { - $value += $this.ConvertToOrderedHashtable($element) - } - else { - $value += Invoke-Expression $element.Extent.Text - } - } - } - else { - try { - $value = Invoke-Expression $valueAst.Extent.Text - } - catch { - $value = $valueAst.Extent.Text - } - } - - $ordered.Add($key, $value) - } - - 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{ - [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 - +$formsType = 'System.Windows.Forms.Form' -as [type] +if ($null -eq $formsType) { Add-Type -AssemblyName System.Windows.Forms +} + +$drawingType = 'System.Drawing.Color' -as [type] +if ($null -eq $drawingType) { Add-Type -AssemblyName System.Drawing +} - $settingsManager = [SettingsManager]::new("DSC Tool") - - # Verwendung - $logManager = [LogManager]::new("DSC Tool") - $logManager.Info("Anwendung gestartet") - - [BaseComponent]::InitializeShared($settingsManager, $logManager) - - foreach($function in $(Get-ChildItem -Path $settingsManager.Get("FunctionsPath") -Recurse -Filter "*.ps1" -File)){ - $logManager.Info("Lade Funktion: $($function.FullName)") - try{ - . $function.FullName - }catch{ - $logManager.Error("Fehler beim Laden: $_") - } +if ([System.Threading.Thread]::CurrentThread.GetApartmentState() -ne [System.Threading.ApartmentState]::STA) { + $powershell = (Get-Command powershell.exe -ErrorAction SilentlyContinue).Source + if ($powershell) { + & $powershell -NoProfile -ExecutionPolicy Bypass -STA -File $PSCommandPath @args + exit $LASTEXITCODE } +} - $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() \ No newline at end of file +$coreScript = Join-Path -Path $PSScriptRoot -ChildPath 'Compiler.Core.ps1' +& $coreScript @args \ No newline at end of file diff --git a/Deployments/merged_config.psd1 b/Deployments/merged_config.psd1 deleted file mode 100644 index 6df11f3..0000000 --- a/Deployments/merged_config.psd1 +++ /dev/null @@ -1,93 +0,0 @@ -@{ - Resources = @{ - NonNodeData = @{ - Services = @{ - SharePoint = @{ - Farm = @{ - Passphrase = 'Use-SecureString-Or-KeyVault' - ConfigDatabaseName = 'SharePoint_Farm_Config' - ServiceApplications = @{ - AppManagementService = @{ - DatabaseName = 'SharePoint_Services_AppManagement' - Provision = 'True' - } - StateService = @{ - DatabaseName = 'SharePoint_Services_StateService' - Provision = 'True' - } - SubscriptionSettingsService = @{ - DatabaseName = 'SharePoint_Services_SubscriptionSettings' - Provision = 'True' - } - ManagedMetadataService = @{ - DatabaseName = 'SharePoint_Services_ManagedMetadata' - Name = 'Managed Metadata Service' - ApplicationPool = 'SharePoint Service Applications' - Provision = 'True' - } - SearchService = @{ - DatabaseName = 'SharePoint_Services_Search' - Name = 'Search Service Application' - ApplicationPool = 'SharePoint Service Applications' - Provision = 'True' - } - UsageAndHealthService = @{ - DatabaseName = 'SharePoint_Services_UsageAndHealth' - Provision = 'True' - } - SecureStoreService = @{ - DatabaseName = 'SharePoint_Services_SecureStore' - Name = 'Secure Store Service' - ApplicationPool = 'SharePoint Service Applications' - Provision = 'True' - } - UserProfileService = @{ - SyncDBName = 'SharePoint_Services_UserProfile_SyncDB' - ApplicationPool = 'SharePoint User Profile Services' - Provision = 'True' - Name = 'User Profile Service' - SocialDBName = 'SharePoint_Services_UserProfile_SocialDB' - ProfileDBName = 'SharePoint_Services_UserProfile_ProfileDB' - } - } - CentralAdminAuth = 'NTLM' - CentralAdminPort = '2016' - AdminContentDatabase = 'SharePoint_Farm_AdminContent' - ServiceApplicationPools = @{ - Default = @{ - Account = 'CONTOSO\sp_services' - Name = 'SharePoint Service Applications' - } - UserProfile = @{ - Account = 'CONTOSO\sp_ups' - Name = 'SharePoint User Profile Services' - } - } - } - Database = @{ - SQLAlias = @{ - SQLServer = @{ - InstanceName = '' - ServerName = '' - TcpPort = '0' - } - } - } - General = @{ - ProductKey = '0000-0000-0000-0000-0000' - } - Windows = @{ - Registry = @{ - DisableLoopbackCheck = @{ - Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' - Name = 'DisableLoopbackCheck' - Value = '1' - Type = 'DWord' - } - } - } - } - } - } - } -} diff --git a/Templates/Environment/Contoso.psd1 b/Templates/Environment/Contoso.psd1 deleted file mode 100644 index 9c6d041..0000000 --- a/Templates/Environment/Contoso.psd1 +++ /dev/null @@ -1,14 +0,0 @@ -@{ - Resources = @{ - NonNodeData = @{ - Services = @{ - ActiveDirectory = @{ - Domain = @{ - FQDN = "contoso.local" - NetBIOS = "Contoso" - } - } - } - } - } -} \ No newline at end of file diff --git a/Templates/Environment/Environment.Default.psd1 b/Templates/Environment/Environment.Default.psd1 new file mode 100644 index 0000000..e891779 --- /dev/null +++ b/Templates/Environment/Environment.Default.psd1 @@ -0,0 +1,161 @@ +@{ + Parameters = @{ + DomainLabel = @{ + Type = 'string' + DefaultValue = '' + Required = $false + MinLength = 2 + MaxLength = 32 + Pattern = '^[A-Za-z][A-Za-z0-9_-]*$' + Metadata = @{ + Description = @{ + 'de-DE' = 'Kurzer logischer Bezeichner der Umgebung oder Domaene.' + 'en-US' = 'Short logical identifier for the environment or domain.' + } + } + } + + DomainFQDN = @{ + Type = 'string' + DefaultValue = '' + Required = $true + Pattern = '^[A-Za-z0-9.-]+$' + Metadata = @{ + Description = @{ + 'de-DE' = 'Vollqualifizierter DNS-Name der Active-Directory-Domaene.' + 'en-US' = 'Fully qualified DNS name of the Active Directory domain.' + } + } + } + + DomainNetBIOS = @{ + Type = 'string' + DefaultValue = '' + Required = $true + MinLength = 1 + MaxLength = 15 + Pattern = '^[A-Za-z0-9_-]+$' + Metadata = @{ + Description = @{ + 'de-DE' = 'NetBIOS-Name der Active-Directory-Domaene.' + 'en-US' = 'NetBIOS name of the Active Directory domain.' + } + } + } + } + + Resources = @{ + NonNodeData = @{ + RequiredModules = @( + @{ + Name = 'ActiveDirectoryDsc' + Version = '6.7.1' + } + ) + + Services = @{ + ActiveDirectory = @{ + Domain = @{ + Ensure = 'Present' + + FQDN = "[parameters('DomainFQDN')]" + NetBIOS = "[parameters('DomainNetBIOS')]" + + ForestMode = "[parameters('ForestMode')]" + DomainMode = "[parameters('DomainMode')]" + + DnsDelegation = $false + + Credentials = @{ + DomainAdministrator = @{ + CredentialName = "[parameters('DomainAdministratorCredentialName')]" + } + + SafeModeAdministrator = @{ + SecretName = "[parameters('SafeModeAdministratorPasswordSecretName')]" + } + } + } + + DomainControllers = @( + @{ + NodeName = '*' + Ensure = 'Present' + InstallDns = $true + IsGlobalCatalog = $true + SiteName = "[parameters('DefaultSiteName')]" + } + ) + + Sites = @( + @{ + Name = "[parameters('DefaultSiteName')]" + Ensure = 'Present' + } + ) + + Subnets = @( + @{ + Name = "[parameters('DefaultSubnet')]" + SiteName = "[parameters('DefaultSiteName')]" + Ensure = 'Present' + } + ) + + OrganizationalUnits = @( + @{ + Name = 'Servers' + Path = "[concat('DC=', replace(parameters('DomainFQDN'), '.', ',DC='))]" + Ensure = 'Present' + ProtectedFromAccidentalDeletion = $true + } + + @{ + Name = 'Service Accounts' + Path = "[concat('DC=', replace(parameters('DomainFQDN'), '.', ',DC='))]" + Ensure = 'Present' + ProtectedFromAccidentalDeletion = $true + } + + @{ + Name = 'Groups' + Path = "[concat('DC=', replace(parameters('DomainFQDN'), '.', ',DC='))]" + Ensure = 'Present' + ProtectedFromAccidentalDeletion = $true + } + ) + + Groups = @( + @{ + GroupName = 'GG-SharePoint-Admins' + Path = "[concat('OU=Groups,DC=', replace(parameters('DomainFQDN'), '.', ',DC='))]" + Scope = 'Global' + Category = 'Security' + Ensure = 'Present' + Members = @() + } + ) + + Users = @( + @{ + UserName = 'SVC_SHP_Setup' + Path = "[concat('OU=Service Accounts,DC=', replace(parameters('DomainFQDN'), '.', ',DC='))]" + Ensure = 'Present' + Enabled = $true + Password = @{ + SecretName = 'SVC_SHP_Setup' + } + } + ) + + Trusts = @() + + Dns = @{ + Forwarders = @() + ReverseLookupZones = @() + } + } + } + } +} +} \ No newline at end of file diff --git a/Templates/Service/SharePointServer.Default.psd1 b/Templates/Service/SharePointServer.Default.psd1 new file mode 100644 index 0000000..7732d84 --- /dev/null +++ b/Templates/Service/SharePointServer.Default.psd1 @@ -0,0 +1,200 @@ +@{ + Parameters = @{ + DatabasePrefix = @{ + Type = 'string' + Value = 'SharePoint' + DefaultValue = 'SharePoint' + Metadata = @{ + Description = @{ + 'de-DE' = 'Praefix fuer alle von der SharePoint-Farm angelegten Datenbanken.' + 'en-US' = 'Prefix for all databases created by the SharePoint farm.' + } + } + } + ServiceDatabaseSegment = @{ + Type = 'string' + DefaultValue = 'Services' + Metadata = @{ + Description = @{ + 'de-DE' = 'Namenssegment fuer SharePoint-Service-Datenbanken innerhalb des Datenbanknamens.' + 'en-US' = 'Name segment used for SharePoint service databases within the database name.' + } + } + } + ContentDatabaseSegment = @{ + Type = 'string' + DefaultValue = 'Content' + Metadata = @{ + Description = @{ + 'de-DE' = 'Namenssegment fuer SharePoint-Content-Datenbanken innerhalb des Datenbanknamens.' + 'en-US' = 'Name segment used for SharePoint content databases within the database name.' + } + } + } + ServiceApplicationPoolDefault = @{ + Type = 'string' + DefaultValue = 'SharePoint Service Applications' + Metadata = @{ + Description = @{ + 'de-DE' = 'Anzeigename des Standard-Application-Pools fuer SharePoint-Serviceanwendungen.' + 'en-US' = 'Display name of the default application pool for SharePoint service applications.' + } + } + } + ServiceApplicationPoolUserProfileService = @{ + Type = 'string' + DefaultValue = 'SharePoint User Profile Services' + Metadata = @{ + Description = @{ + 'de-DE' = 'Anzeigename des Application-Pools fuer den SharePoint User Profile Service.' + 'en-US' = 'Display name of the application pool for the SharePoint User Profile Service.' + } + } + } + ServiceApplicationPoolDefaultAccount = @{ + Type = 'string' + DefaultValue = 'SVC_SHP_SAP' + Metadata = @{ + Description = @{ + 'de-DE' = 'Kontoname fuer den Standard-Application-Pool der SharePoint-Serviceanwendungen.' + 'en-US' = 'Account name used by the default application pool for SharePoint service applications.' + } + } + } + WebApplicationPoolDefault = @{ + Type = 'string' + DefaultValue = 'SharePoint Web Applications' + Metadata = @{ + Description = @{ + 'de-DE' = 'Anzeigename des Standard-Application-Pools fuer SharePoint-Webanwendungen.' + 'en-US' = 'Display name of the default application pool for SharePoint web applications.' + } + } + } + WebApplicationPoolDefaultAccount = @{ + Type = 'string' + DefaultValue = 'SVC_SHP_WAP' + Metadata = @{ + Description = @{ + 'de-DE' = 'Kontoname fuer den Standard-Application-Pool der SharePoint-Webanwendungen.' + 'en-US' = 'Account name used by the default application pool for SharePoint web applications.' + } + } + } + DatabaseInstanceName = @{ + Type = 'string' + DefaultValue = 'SQL_Server' + Metadata = @{ + Description = @{ + 'de-DE' = 'Standard-SQL-Instanzname fuer SharePoint-Datenbankverbindungen und Aliase.' + 'en-US' = 'Default SQL instance name used for SharePoint database connections and aliases.' + } + } + } + } + Variables = @{ + ServiceDbPrefix = "[concat(parameters('DatabasePrefix'),'_',parameters('ServiceDatabaseSegment'),'_')]" + ContentDbPrefix = "[concat(parameters('DatabasePrefix'),'_',parameters('ContentDatabaseSegment'),'_')]" + ConfigDbName = "[concat(parameters('DatabasePrefix'),'_','Farm_Config')]" + AdminDbName = "[concat(parameters('DatabasePrefix'),'_','Farm_AdminContent')]" + } + Resources = @{ + NonNodeData = @{ + Services = @{ + SharePoint = @{ + General = @{ + ProductKey = '0000-0000-0000-0000-0000' + } + Windows = @{ + Registry = @{ + DisableLoopbackCheck = @{ + Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' + Name = 'DisableLoopbackCheck' + Type = 'DWord' + Value = 1 + } + } + } + Database = @{ + SQLAlias = @{ + SQLServer = @{ + ServerName = '' + InstanceName = "[parameters('DatabaseInstanceName')]" + TcpPort = 0 + } + } + } + Farm = @{ + Passphrase = 'Use-SecureString-Or-KeyVault' + ConfigDatabaseName = "[variables('ConfigDbName')]" + AdminContentDatabase = "[variables('AdminDbName')]" + CentralAdminPort = 2016 + CentralAdminAuth = 'NTLM' # oder Kerberos + ServiceApplicationPools = @{ + Default = @{ + Name = "[parameters('ServiceApplicationPoolDefault')]" + Account = 'CONTOSO\sp_services' + } + + UserProfile = @{ + Name = "[parameters('ServiceApplicationPoolUserProfileService')]" + Account = 'CONTOSO\sp_ups' + } + } + ServiceApplications = @{ + ManagedMetadataService = @{ + Provision = $true + Name = 'Managed Metadata Service' + ApplicationPool = 'SharePoint Service Applications' + DatabaseName = "[concat(variables('ServiceDbPrefix'), 'ManagedMetadata')]" + } + + UserProfileService = @{ + Provision = $true + Name = 'User Profile Service' + ApplicationPool = 'SharePoint User Profile Services' + ProfileDBName = "[concat(variables('ServiceDbPrefix'), 'UserProfile_ProfileDB')]" + SocialDBName = "[concat(variables('ServiceDbPrefix'), 'UserProfile_SocialDB')]" + SyncDBName = "[concat(variables('ServiceDbPrefix'), 'UserProfile_SyncDB')]" + } + + SearchService = @{ + Provision = $true + Name = 'Search Service Application' + ApplicationPool = 'SharePoint Service Applications' + DatabaseName = "[concat(variables('ServiceDbPrefix'),'Search')]" + } + + StateService = @{ + Provision = $true + DatabaseName = "[concat(variables('ServiceDbPrefix'),'StateService')]" + } + + UsageAndHealthService = @{ + Provision = $true + DatabaseName = "[concat(variables('ServiceDbPrefix'),'UsageAndHealth')]" + } + + AppManagementService = @{ + Provision = $true + DatabaseName = "[concat(variables('ServiceDbPrefix'),'AppManagement')]" + } + + SubscriptionSettingsService = @{ + Provision = $true + DatabaseName = "[concat(variables('ServiceDbPrefix'),'SubscriptionSettings')]" + } + + SecureStoreService = @{ + Provision = $true + Name = 'Secure Store Service' + ApplicationPool = 'SharePoint Service Applications' + DatabaseName = "[concat(variables('ServiceDbPrefix'),'SecureStore')]" + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Templates/Service/SharePointServer.psd1 b/Templates/Service/SharePointServer.psd1 deleted file mode 100644 index 1ecba6f..0000000 --- a/Templates/Service/SharePointServer.psd1 +++ /dev/null @@ -1,142 +0,0 @@ -@{ - Parameters = @{ - DatabasePrefix = @{ - Type = 'string' - Value = 'SharePoint' - DefaultValue = 'SP' - Metadata = @{ - Description = 'Prefix für alle Datenbanknamen' - } - } - ServiceDatabasePrefix = @{ - Type = 'string' - DefaultValue = 'Services' - } - ContentDatabasePrefix = @{ - Type = 'string' - DefaultValue = 'Content' - } - ServiceApplicationPoolDefault = @{ - Type = 'string' - DefaultValue = 'SharePoint Service Applications' - } - ServiceApplicationPoolUserProfileService = @{ - Type = 'string' - DefaultValue = 'SharePoint User Profile Services' - } - DatbaseInstanceName = @{ - Type = 'string' - DefaultValue = 'mssqlserver' - Metadata = @{ - Description = 'Instanz Name für die Standart Instanz' - } - } - } - Variables = @{ - ServiceDbPrefix = "[Concat(Parameter('DatabasePrefix'),'_',Parameter('ServiceDatabasePrefix'),'_')]" - ContentDbPrefix = "[Concat(Parameter('DatabasePrefix'),'_',Parameter('ServiceDatabasePrefix'),'_')]" - ConfigDbName = "[Concat(Parameter('DatabasePrefix'),'_','Farm_Config')]" - AdminDbName = "[Concat(Parameter('DatabasePrefix'),'_','Farm_AdminContent')]" - HZDTest = "[Substring(Parameter('DatbaseInstanceName'),0,5)]" - Test = "[ToUpper(Parameter('DatbaseInstanceName'),0,5)]" - } - Resources = @{ - NonNodeData = @{ - Services = @{ - SharePoint = @{ - General = @{ - ProductKey = '0000-0000-0000-0000-0000' - } - Windows = @{ - Registry = @{ - DisableLoopbackCheck = @{ - Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' - Name = 'DisableLoopbackCheck' - Type = 'DWord' - Value = 1 - } - } - } - Database = @{ - SQLAlias = @{ - SQLServer = @{ - ServerName = '' - InstanceName = '' - TcpPort = 0 - } - } - } - Farm = @{ - Passphrase = 'Use-SecureString-Or-KeyVault' - ConfigDatabaseName = "[Variable('ConfigDbName')]" - AdminContentDatabase = "[Variable('AdminDbName')]" - CentralAdminPort = 2016 - CentralAdminAuth = 'NTLM' # oder Kerberos - ServiceApplicationPools = @{ - Default = @{ - Name = "[Parameter('ServiceApplicationPoolDefault')]" - Account = 'CONTOSO\sp_services' - } - - UserProfile = @{ - Name = "[Parameter('ServiceApplicationPoolUserProfileService')]" - Account = 'CONTOSO\sp_ups' - } - } - ServiceApplications = @{ - ManagedMetadataService = @{ - Provision = $true - Name = 'Managed Metadata Service' - ApplicationPool = 'SharePoint Service Applications' - DatabaseName = "[Concat(Variable('ServiceDbPrefix'), 'ManagedMetadata')]" - } - - UserProfileService = @{ - Provision = $true - Name = 'User Profile Service' - ApplicationPool = 'SharePoint User Profile Services' - ProfileDBName = "[Concat(Variable('ServiceDbPrefix'), 'UserProfile_ProfileDB')]" - SocialDBName = "[Concat(Variable('ServiceDbPrefix'), 'UserProfile_SocialDB')]" - SyncDBName = "[Concat(Variable('ServiceDbPrefix'), 'UserProfile_SyncDB')]" - } - - SearchService = @{ - Provision = $true - Name = 'Search Service Application' - ApplicationPool = 'SharePoint Service Applications' - DatabaseName = "[Concat(Variable('ServiceDbPrefix'),'Search')]" - } - - StateService = @{ - Provision = $true - DatabaseName = "[Concat(Variable('ServiceDbPrefix'),'StateService')]" - } - - UsageAndHealthService = @{ - Provision = $true - DatabaseName = "[Concat(Variable('ServiceDbPrefix'),'UsageAndHealth')]" - } - - AppManagementService = @{ - Provision = $true - DatabaseName = "[Concat(Variable('ServiceDbPrefix'),'AppManagement')]" - } - - SubscriptionSettingsService = @{ - Provision = $true - DatabaseName = "[Concat(Variable('ServiceDbPrefix'),'SubscriptionSettings')]" - } - - SecureStoreService = @{ - Provision = $true - Name = 'Secure Store Service' - ApplicationPool = 'SharePoint Service Applications' - DatabaseName = "[Concat(Variable('ServiceDbPrefix'),'SecureStore')]" - } - } - } - } - } - } - } -} \ No newline at end of file