54 Commits

Author SHA1 Message Date
fierke 1f73238216 [chore:] adapt button enabeling to existance of PersonErrors 2026-06-09 12:38:20 +02:00
fierke 1d0876fa40 [feat:] descriptive info on address-set-functions 2026-06-09 12:26:54 +02:00
fierke db6624e5bc [chore:] basic international pdf generating that fits DPs template better 2026-06-09 09:04:47 +02:00
fierke f8aab88a04 [chore:] added "PRESSE/ELN" text 2026-06-09 08:56:43 +02:00
fierke 4d71fb21ea {fix:] treeview was not scrollable 2026-06-09 08:49:06 +02:00
fierke fd1cf6c3e3 [chore:] better ui alignment (global settings) 2026-06-09 08:30:48 +02:00
fierke 9bbda4e2b9 [chore:] removed font-path support (since it was never implemented) 2026-06-09 08:26:32 +02:00
fierke 097e0c175b [feat:] refresh wiki nav tree manually (and file/folder-add icons) 2026-06-09 08:23:09 +02:00
fierke 1491f60791 [fix:] added unversioned file... 2026-06-08 15:31:41 +02:00
fierke 1ce0e2de8d [feat:] initial version of DP-compatible running sheets (germany) 2026-06-08 13:33:56 +02:00
fierke e62861a25b [fix:] international postcodes were trimmed as if they are german 2026-06-08 11:35:28 +02:00
fierke e3cdb61932 [feat:] international running sheet creation (unpolished, but therefore we need aditional information) 2026-06-08 11:35:03 +02:00
fierke a2d0b72899 [feat:] include Markdown.Avalonia for better rendering 2026-06-08 09:05:12 +02:00
fierke acaf0856ed [chore:] filter by germany for running-sheet creation 2026-06-08 08:52:46 +02:00
fierke 2da822e0e7 [chore:] added IsGermany()-function 2026-06-08 08:52:06 +02:00
fierke a4c7132756 [chore:] some log changes 2026-06-04 08:42:34 +02:00
fierke c32cd44184 [fix:] missing fields from the merge 2026-06-04 08:30:36 +02:00
fierke af3f8234c0 Merge branch 'running-sheets'
# Conflicts:
#	MainWindow.axaml.cs
#	Tasks/AddressCreation.cs
#	Tasks/PdfBuilder.cs
2026-06-04 08:28:52 +02:00
fierke c140a20549 [chore:] textbox-changements global save 2026-06-03 16:38:00 +02:00
fierke ac717c5345 [fix:] file handling 2026-06-03 16:36:36 +02:00
fierke 1580d30d72 [chore:] ui element disableing (customer settings) 2026-05-27 08:42:25 +02:00
fierke 0dacaf19b9 [chore:] control name 2026-05-27 08:41:42 +02:00
fierke 75b6b1dc4d [chore:] various tiny improvements 2026-05-20 08:00:20 +02:00
fierke 1161a437c4 [fix:] wiki preview reloading after saving changes 2026-05-19 09:44:14 +02:00
fierke 605ba95848 [fix:] message box center screen startup 2026-05-19 09:32:06 +02:00
fierke eb38bafd23 [feat:] delete address sets (FINALLY, this was so hard to implement, it took almost 2 minutes) 2026-05-19 09:31:35 +02:00
fierke e2d5ae2a70 Merge pull request '[fix?:] windows paths (ai-based since windows is boring)' (#57) from windows-paths into main
Reviewed-on: #57

since this still works on any linux machines and theoretical on windows machines, we're merging it to prevent wrong commits cause i configured something wrong
2026-05-19 07:24:01 +00:00
fierke b3ab21ae38 [fix?:] windows paths (ai-based since windows is boring) 2026-05-18 11:42:32 +02:00
fierke 67d007bb31 [fix:] inconsistency with config.json 2026-05-18 11:37:10 +02:00
fierke bf28ba1914 [chore:] logging for StableFontResolver.cs 2026-05-16 18:19:50 +02:00
fierke 40630dee35 [chore:] logging for PdfBuilder.cs 2026-05-16 18:19:36 +02:00
fierke c6baa6a187 [chore:] logging for MarkdownRenderer.cs 2026-05-16 18:19:27 +02:00
fierke 557052bbc7 [chore:] logging for EditorWindow.axaml.cs 2026-05-16 18:19:19 +02:00
fierke 696d0f8fcb [chore:] logging for DataImport.cs 2026-05-16 18:19:09 +02:00
fierke 201b19cbb5 [chore:] logging for CsvBuilder.cs 2026-05-16 18:18:58 +02:00
fierke d7d4b3b31b [file:] removing docs.tex since we're using a markdown wiki 2026-05-16 16:14:31 +00:00
fierke fa10b5c7d0 [chore:] logging for ResultWindow.axaml.cs 2026-05-16 15:10:55 +02:00
fierke 85685d95bb [chore:] logging for NamingWindow.axaml.cs 2026-05-16 15:10:49 +02:00
fierke 8a42f8dc7d [chore:] logging for CombineAddresses.cs 2026-05-16 15:09:55 +02:00
fierke cdc4fb70cd [chore:] logging for AddressShortener.cs 2026-05-16 15:09:50 +02:00
fierke 10dfd1e080 [chore:] logging for AddressRepair.cs 2026-05-16 15:09:45 +02:00
fierke 4b98f53881 [chore:] logging for AddressPatch.cs 2026-05-16 15:09:38 +02:00
fierke 5f79df55d2 [chore:] logging for AddressCreation.cs 2026-05-16 15:09:32 +02:00
fierke 2d33326bab [chore:] logging for AddressCheck.cs 2026-05-16 15:09:23 +02:00
fierke b48652910e [fix:] format errors 2026-05-16 14:44:38 +02:00
fierke a74a97559b [fix:] typo 2026-05-16 14:42:28 +02:00
fierke b5b6dc8de7 [chore:] basic saving logging 2026-05-16 14:41:28 +02:00
fierke 6dfab5e73a [chore:] basic logging 2026-05-16 14:41:16 +02:00
fierke 6f03a26c29 [fix:] console logging printed an array 👀 2026-05-16 14:41:06 +02:00
fierke 7c81920e84 [init:] logging system 2026-05-16 14:12:16 +02:00
fierke d337f94851 [fix?:] trying 2026-05-15 18:56:55 +02:00
fierke 1922b30ada [fix?:] will this work? 2026-05-15 18:41:45 +02:00
fierke 68541621d9 [fix?:] windows file path for label export? 2026-05-15 18:34:25 +02:00
fierke 474b628f0b [chore:] renaming address sets now gives the current name as a base 2026-05-15 17:51:35 +02:00
24 changed files with 2762 additions and 1714 deletions
+11
View File
@@ -180,6 +180,17 @@ public class KasPerson
public string used_plz { get; set; } = ""; public string used_plz { get; set; } = "";
public bool IsGermany()
{
var trimmedLand = (land ?? "").Trim();
var trimmedLowerLand = trimmedLand.ToLower();
var isGermany = trimmedLowerLand == "germany" || trimmedLowerLand == "ger" ||
trimmedLowerLand == "" || trimmedLowerLand == "de" ||
trimmedLowerLand == "deutschland";
return isGermany;
}
public static void SetUsedPLZ(int id, string plz) public static void SetUsedPLZ(int id, string plz)
{ {
foreach (var set in Settings._instance.addressSets.addresses) foreach (var set in Settings._instance.addressSets.addresses)
+26 -19
View File
@@ -12,8 +12,8 @@ public class Settings
public Customers customers = new(); public Customers customers = new();
public PdfExportSettings pdfExport { get; set; } = new(); public PdfExportSettings pdfExport { get; set; } = new();
public string settingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), // public string settingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient", "config.json"); // "logofclient", "config.json");
public Settings() public Settings()
{ {
@@ -23,31 +23,28 @@ public class Settings
public static void Save() public static void Save()
{ {
if (!Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), if (!Directory.Exists(Global._instance.config_path) && !File.Exists((Global._instance.config_path)))
"logofclient"))) Directory.CreateDirectory(Global._instance.config_path);
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), // if (!string.IsNullOrEmpty(Global._instance.config_path)) _instance.settingsPath = Global._instance.config_path;
"logofclient"));
if (!string.IsNullOrEmpty(Global._instance.config_path)) _instance.settingsPath = Global._instance.config_path;
var json = JsonConvert.SerializeObject(_instance); var json = JsonConvert.SerializeObject(_instance);
File.WriteAllText(_instance.settingsPath, json); File.WriteAllText(Path.Combine(Global._instance.config_path,"config.json"), json);
} }
public static void Load() public static void Load()
{ {
if (!string.IsNullOrEmpty(Global._instance.config_path)) _instance.settingsPath = Global._instance.config_path; //if (!string.IsNullOrEmpty(Global._instance.config_path)) _instance.settingsPath = Global._instance.config_path;
try try
{ {
var contents = File.ReadAllText(_instance.settingsPath); var contents = File.ReadAllText(Path.Combine(Global._instance.config_path, "config.json"));
_instance = JsonConvert.DeserializeObject<Settings>(contents); _instance = JsonConvert.DeserializeObject<Settings>(contents);
MainWindow._instance.RefreshCustomerItems(); MainWindow._instance.RefreshCustomerItems();
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(ex.Message); Logger.Log($"Error while reading settings. Generating new... {ex.Message}", Logger.LogType.Warning);
Console.WriteLine(ex.StackTrace);
Console.WriteLine("Error while reading settings. Generating new...");
_instance = new Settings(); _instance = new Settings();
} }
} }
@@ -86,9 +83,13 @@ public class Global
public string config_path { get; set; } = Path.Combine( public string config_path { get; set; } = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient", "logofclient");
"config.json");
public void SetConfigPath(string path)
{
if (!string.IsNullOrWhiteSpace(path))
config_path = PathUtilities.NormalizeFileSystemPath(path);
}
public string wiki_storage_path { get; set; } = Path.Combine( public string wiki_storage_path { get; set; } = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient", "logofclient",
@@ -122,17 +123,23 @@ public class Global
var contents = File.ReadAllText(Path.Combine( var contents = File.ReadAllText(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "logofclient", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "logofclient",
"global.config")); "global.config"));
_instance = JsonConvert.DeserializeObject<Global>(contents); _instance = JsonConvert.DeserializeObject<Global>(contents) ?? new Global();
_instance.NormalizePaths();
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(ex.Message); Logger.Log($"Error while reading global settings. Generating new... {ex.Message}", Logger.LogType.Warning);
Console.WriteLine(ex.StackTrace);
Console.WriteLine("Error while reading global settings. Generating new...");
_instance = new Global(); _instance = new Global();
Save(); Save();
} }
} }
private void NormalizePaths()
{
config_path = PathUtilities.NormalizeFileSystemPath(config_path);
wiki_storage_path = PathUtilities.NormalizeFileSystemPath(wiki_storage_path);
font_path = PathUtilities.NormalizeFileSystemPath(font_path);
}
} }
public class Customers public class Customers
+40
View File
@@ -0,0 +1,40 @@
using System;
using System.IO;
using Newtonsoft.Json;
namespace Logof_Client;
public static class Logger
{
public static void Log(string text, LogType logType = LogType.Info)
{
try
{
string config_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient");
if (!Directory.Exists(config_path))
Directory.CreateDirectory(config_path);
string log_path = Path.Combine(config_path, $"log-{DateTime.Now:dd-MM-yy}.log");
if(!File.Exists(log_path))
File.Create(log_path).Close();
string line = $"[{DateTime.Now:dd.MM.yyyy - hh:mm:ss}]: ({logType.ToString()}) {text}";
Console.WriteLine(line);
File.AppendAllLines(log_path, [line]);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public enum LogType
{
Error,
Warning,
Info
}
}
+1
View File
@@ -21,6 +21,7 @@
</PackageReference> </PackageReference>
<PackageReference Include="ISO3166" Version="1.0.4" /> <PackageReference Include="ISO3166" Version="1.0.4" />
<PackageReference Include="Lucide.Avalonia" Version="0.1.35" /> <PackageReference Include="Lucide.Avalonia" Version="0.1.35" />
<PackageReference Include="Markdown.Avalonia" Version="11.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="PdfSharp" Version="6.1.1" /> <PackageReference Include="PdfSharp" Version="6.1.1" />
</ItemGroup> </ItemGroup>
+72 -48
View File
@@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:md="https://github.com/whistyun/Markdown.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
MinWidth="1000" MinHeight="600" IsVisible="False" MinWidth="1000" MinHeight="600" IsVisible="False"
x:Class="Logof_Client.MainWindow" WindowState="Maximized" Icon="assets/icon.ico" x:Class="Logof_Client.MainWindow" WindowState="Maximized" Icon="assets/icon.ico"
@@ -78,7 +79,7 @@
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<MenuItem x:Name="MnIAdSetDelete" Click="MnIAdSetRename_OnClick" IsEnabled="False"> <MenuItem x:Name="MnIAdSetDelete" Click="MnIAdSetDelete_OnClick" IsEnabled="True">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="Trash" Width="12" Height="12" Size="12" /> <LucideIcon Kind="Trash" Width="12" Height="12" Size="12" />
@@ -103,52 +104,67 @@
<StackPanel Grid.Row="1" Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center" <StackPanel Grid.Row="1" Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center"
Margin="0,0,5,0"> Margin="0,0,5,0">
<Button Width="250" HorizontalContentAlignment="Center" <Button Width="250" HorizontalContentAlignment="Center"
Margin="0,0,0,10" IsEnabled="False" Margin="0,0,0,10" IsEnabled="False" VerticalAlignment="Stretch"
x:Name="BtnCheck" Click="BtnCheck_OnClick"> x:Name="BtnCheck" Click="BtnCheck_OnClick">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="SpellCheck" Width="36" Height="36" /> <LucideIcon Kind="SpellCheck" Width="36" Height="36" />
<Label Content="Prüfen" VerticalContentAlignment="Center" FontSize="15" <Label Content="Prüfen" VerticalContentAlignment="Center" FontSize="15"
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
<TextBlock TextWrapping="Wrap" FontSize="9" Text="Prüft alle Adressen auf Fehler." HorizontalAlignment="Stretch" TextAlignment="Left"></TextBlock>
</StackPanel>
</Button> </Button>
<Button Width="250" IsEnabled="False" <Button Width="250" IsEnabled="False"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Click="BtnCombine_OnClick" x:Name="BtnCombine" Click="BtnCombine_OnClick" x:Name="BtnCombine" VerticalAlignment="Stretch"
Margin="0,0,0,10"> Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="Combine" Width="36" Height="36" /> <LucideIcon Kind="Combine" Width="36" Height="36" />
<Label Content="Zusammenführen" VerticalContentAlignment="Center" FontSize="15" <Label Content="Zusammenführen" VerticalContentAlignment="Center" FontSize="15"
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
<TextBlock TextWrapping="Wrap" FontSize="9" Text="Führt mehrere Adress-Sets auf verschiedene Art und Weise zusammen." HorizontalAlignment="Stretch" TextAlignment="Left"></TextBlock>
</StackPanel>
</Button> </Button>
<Button Width="250" IsEnabled="False" Click="BtnShorten_OnClick" <Button Width="250" IsEnabled="False" Click="BtnShorten_OnClick"
HorizontalContentAlignment="Center" x:Name="BtnShorten" HorizontalContentAlignment="Center" x:Name="BtnShorten" VerticalAlignment="Stretch"
Margin="0,0,0,10"> Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="ListX" Width="36" Height="36" /> <LucideIcon Kind="ListX" Width="36" Height="36" />
<Label Content="Kürzen" VerticalContentAlignment="Center" FontSize="15" <Label Content="Kürzen" VerticalContentAlignment="Center" FontSize="15"
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
<TextBlock TextWrapping="Wrap" FontSize="9" Text="Entfernt alle Fehlerhaften Adressen (ggf. bitte vorher Reparieren). Setzt Prüfung voraus." HorizontalAlignment="Stretch" TextAlignment="Left"></TextBlock>
</StackPanel>
</Button> </Button>
<Button Width="250" IsEnabled="False" <Button Width="250" IsEnabled="False"
Click="BtnGenerateLabels_OnClick" Click="BtnGenerateLabels_OnClick"
HorizontalContentAlignment="Center" x:Name="BtnGenerateLabels" HorizontalContentAlignment="Center" x:Name="BtnGenerateLabels" VerticalAlignment="Stretch"
Margin="0,0,0,10"> Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="Tags" Width="36" Height="36" /> <LucideIcon Kind="Tags" Width="36" Height="36" />
<Label Content="Etiketten generieren" VerticalContentAlignment="Center" <Label Content="Etiketten generieren" VerticalContentAlignment="Center"
FontSize="15" FontSize="15"
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
<TextBlock TextWrapping="Wrap" FontSize="9" Text="Generiert Versandetiketten und Bundleitzettel" HorizontalAlignment="Stretch" TextAlignment="Left"></TextBlock>
</StackPanel>
</Button> </Button>
<Button Width="250" IsEnabled="False" <Button Width="250" IsEnabled="False"
HorizontalContentAlignment="Center" x:Name="BtnRepair" HorizontalContentAlignment="Center" x:Name="BtnRepair" VerticalAlignment="Stretch"
Margin="0,0,0,10"> Margin="0,0,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="Hammer" Width="36" Height="36" /> <LucideIcon Kind="Hammer" Width="36" Height="36" />
<Label Content="Reparieren" VerticalContentAlignment="Center" FontSize="15" <Label Content="Reparieren" VerticalContentAlignment="Center" FontSize="15"
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
<TextBlock TextWrapping="Wrap" FontSize="9" Text="Versucht, verschiedene Adressaspekte zu reparieren. Setzt Prüfung voraus." HorizontalAlignment="Stretch" TextAlignment="Left"></TextBlock>
</StackPanel>
</Button> </Button>
</StackPanel> </StackPanel>
<!-- </Grid> --> <!-- </Grid> -->
@@ -343,17 +359,31 @@
</TabItem.Header> </TabItem.Header>
<Grid ColumnDefinitions="300,*"> <Grid ColumnDefinitions="300,*">
<Border Grid.Column="0" Background="#FFF" BorderBrush="#DDD" BorderThickness="0,0,1,0"> <Border Grid.Column="0" Background="#FFF" BorderBrush="#DDD" BorderThickness="0,0,1,0">
<StackPanel> <Grid RowDefinitions="Auto,*">
<StackPanel Spacing="10" Orientation="Horizontal" Margin="10"> <StackPanel Spacing="10" Orientation="Horizontal" Margin="10">
<Button Content="+ Datei" x:Name="BtnWikiAddFile" <Button x:Name="BtnWikiAddFile"
Click="BtnWikiAddFile_OnClick" /> Click="BtnWikiAddFile_OnClick">
<Button Content="+ Ordner" x:Name="BtnWikiAddFolder" <StackPanel Orientation="Horizontal">
Click="BtnWikiAddFolder_OnClick" /> <LucideIcon Kind="Plus" Width="24" Height="24" />
<LucideIcon Kind="File" Width="24" Height="24" />
</StackPanel> </StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> </Button>
<TreeView Name="NavTree" Margin="10" /> <Button x:Name="BtnWikiAddFolder"
</ScrollViewer> Click="BtnWikiAddFolder_OnClick" >
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Plus" Width="24" Height="24" />
<LucideIcon Kind="Folder" Width="24" Height="24" />
</StackPanel> </StackPanel>
</Button>
<Button Click="BtnReloadWiki_OnClick" x:Name="BtnReloadWiki">
<LucideIcon Kind="RefreshCcw" Width="24" Height="24" />
</Button>
</StackPanel>
<TreeView Grid.Row="1" Name="NavTree"
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
</Grid>
</Border> </Border>
<Grid Grid.Column="1"> <Grid Grid.Column="1">
@@ -370,9 +400,7 @@
</StackPanel> </StackPanel>
<Border Grid.Row="1" Margin="8" BorderBrush="#DDD" BorderThickness="1" CornerRadius="4"> <Border Grid.Row="1" Margin="8" BorderBrush="#DDD" BorderThickness="1" CornerRadius="4">
<ScrollViewer> <md:MarkdownScrollViewer x:Name="MsvWikiView"/>
<StackPanel Name="PreviewPanel" Margin="8" />
</ScrollViewer>
</Border> </Border>
</Grid> </Grid>
</Grid> </Grid>
@@ -395,28 +423,25 @@
<StackPanel Orientation="Vertical" Spacing="10"> <StackPanel Orientation="Vertical" Spacing="10">
<Grid ColumnDefinitions="400,*"> <Grid ColumnDefinitions="400,*">
<Label Grid.Column="0">config-Datei</Label> <Label Grid.Column="0">config-Datei</Label>
<StackPanel Grid.Column="1" Orientation="Vertical" Spacing="5"> <Grid Grid.Column="1" ColumnDefinitions="*,150">
<StackPanel Orientation="Horizontal" Spacing="5"> <TextBox x:Name="TbConfigPath" HorizontalAlignment="Stretch" TextChanged="Tb_OnTextChanged"
<TextBox x:Name="TbConfigPath" HorizontalAlignment="Stretch" Watermark="/home/username/.config/logofclient/" />
Watermark="/home/username/.config/logofclient/config.json" /> <Button Grid.Column="1" Margin="5,0,0,0" x:Name="BtnConfigPath" HorizontalAlignment="Stretch">
<Button x:Name="BtnConfigPath" HorizontalAlignment="Right">
<Button.Content> <Button.Content>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="File" Width="16" Height="16" Size="16" /> <LucideIcon Kind="Folder" Width="16" Height="16" Size="16" />
<Label Content="Öffnen..." VerticalContentAlignment="Center" /> <Label Content="Öffnen..." VerticalContentAlignment="Center" />
</StackPanel> </StackPanel>
</Button.Content> </Button.Content>
</Button> </Button>
</StackPanel> </Grid>
</StackPanel>
</Grid> </Grid>
<Grid ColumnDefinitions="400,*"> <Grid ColumnDefinitions="400,*">
<Label Grid.Column="0">Wiki-Pfad</Label> <Label Grid.Column="0">Wiki-Pfad</Label>
<StackPanel Grid.Column="1" Orientation="Vertical" Spacing="5"> <Grid Grid.Column="1" ColumnDefinitions="*,150">
<StackPanel Orientation="Horizontal" Spacing="5"> <TextBox x:Name="TbWikiPath" HorizontalAlignment="Stretch" TextChanged="Tb_OnTextChanged"
<TextBox x:Name="TbWikiPath" HorizontalAlignment="Stretch"
Watermark="/home/username/.config/logofclient/wiki" /> Watermark="/home/username/.config/logofclient/wiki" />
<Button IsEnabled="True" x:Name="BtnWikiPath" HorizontalAlignment="Right"> <Button Grid.Column="1" Margin="5,0,0,0" IsEnabled="True" x:Name="BtnWikiPath" HorizontalAlignment="Stretch">
<Button.Content> <Button.Content>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<LucideIcon Kind="Folder" Width="16" Height="16" Size="16" /> <LucideIcon Kind="Folder" Width="16" Height="16" Size="16" />
@@ -424,26 +449,25 @@
</StackPanel> </StackPanel>
</Button.Content> </Button.Content>
</Button> </Button>
</StackPanel>
</StackPanel>
</Grid> </Grid>
<Grid ColumnDefinitions="400,*">
<Label Grid.Column="0">Font-Pfad</Label>
<StackPanel Grid.Column="1" Orientation="Vertical" Spacing="5">
<StackPanel Orientation="Horizontal" Spacing="5">
<TextBox x:Name="TbFontPath" HorizontalAlignment="Stretch"
Watermark="[App-Direcotry]/assets/fonts/" />
<Button IsEnabled="True" x:Name="BtnFontPath" HorizontalAlignment="Right">
<Button.Content>
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Folder" Width="16" Height="16" Size="16" />
<Label Content="Öffnen..." VerticalContentAlignment="Center" />
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
</StackPanel>
</Grid> </Grid>
<!-- <Grid ColumnDefinitions="400,*"> -->
<!-- <Label Grid.Column="0">Font-Pfad</Label> -->
<!-- <StackPanel Grid.Column="1" Orientation="Vertical" Spacing="5"> -->
<!-- <StackPanel Orientation="Horizontal" Spacing="5"> -->
<!-- <TextBox x:Name="TbFontPath" HorizontalAlignment="Stretch" TextChanged="Tb_OnTextChanged" -->
<!-- Watermark="[App-Direcotry]/assets/fonts/" /> -->
<!-- <Button IsEnabled="True" x:Name="BtnFontPath" HorizontalAlignment="Right"> -->
<!-- <Button.Content> -->
<!-- <StackPanel Orientation="Horizontal"> -->
<!-- <LucideIcon Kind="Folder" Width="16" Height="16" Size="16" /> -->
<!-- <Label Content="Öffnen..." VerticalContentAlignment="Center" /> -->
<!-- </StackPanel> -->
<!-- </Button.Content> -->
<!-- </Button> -->
<!-- </StackPanel> -->
<!-- </StackPanel> -->
<!-- </Grid> -->
</StackPanel> </StackPanel>
</TabItem> </TabItem>
<TabItem> <TabItem>
@@ -494,7 +518,7 @@
TextChanged="TbSettingsCustomerSenderAddress_OnTextChanged" TextChanged="TbSettingsCustomerSenderAddress_OnTextChanged"
x:Name="TbSettingsCustomerSenderAddress" /> x:Name="TbSettingsCustomerSenderAddress" />
</Grid> </Grid>
<Grid ColumnDefinitions="150,*,Auto"> <Grid ColumnDefinitions="150,*,Auto" x:Name="GrdCSVDividerButtonsAndTb">
<Label Content="CSV-Trennzeichen" /> <Label Content="CSV-Trennzeichen" />
<TextBox Grid.Column="1" Watermark="," <TextBox Grid.Column="1" Watermark=","
HorizontalAlignment="Stretch" Margin="0,0,5,0" HorizontalAlignment="Stretch" Margin="0,0,5,0"
+270 -87
View File
@@ -24,7 +24,11 @@ public partial class MainWindow : Window
public MainWindow() public MainWindow()
{ {
Logger.Log("Welcome to logofclient");
Logger.Log($"Session on {DateTime.Now:G}");
Logger.Log("Initializing...");
InitializeComponent(); InitializeComponent();
SetSettingsCustomerEnabledState(false);
//Hide(); //Hide();
var s = new StartupWindow(); var s = new StartupWindow();
@@ -32,14 +36,21 @@ public partial class MainWindow : Window
_instance = this; _instance = this;
WindowState = WindowState.Maximized; WindowState = WindowState.Maximized;
Logger.Log("Loading settings...");
Global.Load(); Global.Load();
Settings.Load(); Settings.Load();
if (!string.IsNullOrWhiteSpace(Global._instance.config_path))
TbConfigPath.Text = PathUtilities.NormalizeFileSystemPath(Global._instance.config_path);
LoadPdfExportOptions(); LoadPdfExportOptions();
HookPdfExportOptionEvents(); HookPdfExportOptionEvents();
RefreshCountryView(); RefreshCountryView();
// Initialize wiki integration // Initialize wiki integration
Logger.Log("Building wiki...");
_wikiService = new WikiService(); _wikiService = new WikiService();
try try
{ {
@@ -52,24 +63,27 @@ public partial class MainWindow : Window
try try
{ {
if (!string.IsNullOrWhiteSpace(Global._instance.wiki_storage_path)) if (!string.IsNullOrWhiteSpace(Global._instance.wiki_storage_path))
TbWikiPath.Text = Global._instance.wiki_storage_path; TbWikiPath.Text = PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path);
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while setting paths: {ex.Message}", Logger.LogType.Error);
} }
try try
{ {
BtnWikiPath.Click += BtnWikiPath_Click; BtnWikiPath.Click += BtnWikiPath_Click;
BtnFontPath.Click += BtnFontPath_Click; //BtnFontPath.Click += BtnFontPath_Click;
BtnConfigPath.Click += BtnConfigPath_Click; BtnConfigPath.Click += BtnConfigPath_Click;
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while adding click functions?: {ex.Message}", Logger.LogType.Error);
} }
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while doing wiki stuff: {ex.Message}", Logger.LogType.Error);
} }
//Thread.Sleep(3000); //Thread.Sleep(3000);
@@ -121,26 +135,11 @@ public partial class MainWindow : Window
//await MessageBox.Show(_instance, $"{result.Count} Einträge fehlerhaft.", "Fertig"); //await MessageBox.Show(_instance, $"{result.Count} Einträge fehlerhaft.", "Fertig");
} }
// private async void StartAddressRepair(Uri path)
// {
// var addresses = DataImport.ImportKasAddressList(path); // Ihr Code hier
// var progressWindow = new ProgressWindow();
//
// progressWindow.Show(_instance);
//
// var processor = new AddressRepair(progressWindow);
// //var result = await processor.Perform(addresses.Item2, errors);
//
//
// progressWindow.Close();
//
//
// //new ResultWindow(result, addresses.Item2).Show();
// //await MessageBox.Show(_instance, $"{result.Count} Einträge fehlerhaft.", "Fertig");
// }
private void MnuExit_OnClick(object? sender, RoutedEventArgs e) private void MnuExit_OnClick(object? sender, RoutedEventArgs e)
{ {
Settings.Save();
Global.Save();
Environment.Exit(0); Environment.Exit(0);
} }
@@ -156,7 +155,7 @@ public partial class MainWindow : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Fehler beim Öffnen des Links: {ex.Message}"); Logger.Log($"Error while starting process: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -172,7 +171,7 @@ public partial class MainWindow : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Fehler beim Öffnen des Links: {ex.Message}"); Logger.Log($"Error while starting process: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -188,7 +187,7 @@ public partial class MainWindow : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Fehler beim Öffnen des Links: {ex.Message}"); Logger.Log($"Error while starting process: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -221,23 +220,29 @@ public partial class MainWindow : Window
private async void NavTree_SelectionChanged(object? sender, SelectionChangedEventArgs e) private async void NavTree_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
ReloadWikiItem();
}
private async void ReloadWikiItem()
{ {
if (NavTree.SelectedItem is TreeViewItem t && t.Tag is WikiItem item && !item.IsFolder) if (NavTree.SelectedItem is TreeViewItem t && t.Tag is WikiItem item && !item.IsFolder)
{ {
_selectedWikiFilePath = item.Path; _selectedWikiFilePath = item.Path;
var text = await _wikiService.LoadFileContentAsync(item.Path); var text = await _wikiService.LoadFileContentAsync(item.Path);
try MsvWikiView.Markdown = text;
{ // try
PreviewPanel.Children.Clear(); // {
var rendered = MarkdownRenderer.Render(text ?? string.Empty); // PreviewPanel.Children.Clear();
PreviewPanel.Children.Add(rendered); // var rendered = MarkdownRenderer.Render(text ?? string.Empty);
} // PreviewPanel.Children.Add(rendered);
catch // }
{ // catch (Exception ex)
// fallback: plain text // {
PreviewPanel.Children.Clear(); // Logger.Log($"Error while rendering markdown: {ex.Message}", Logger.LogType.Error);
PreviewPanel.Children.Add(new TextBlock { Text = text ?? string.Empty }); // PreviewPanel.Children.Clear();
} // PreviewPanel.Children.Add(new TextBlock { Text = text ?? string.Empty });
// }
EditButton.IsEnabled = true; EditButton.IsEnabled = true;
} }
@@ -249,6 +254,8 @@ public partial class MainWindow : Window
} }
public void PopulateNavTree(string? expandToPath = null, string? selectPath = null) public void PopulateNavTree(string? expandToPath = null, string? selectPath = null)
{
try
{ {
var roots = _wikiService.GetRootItems(); var roots = _wikiService.GetRootItems();
var nodes = new List<TreeViewItem>(); var nodes = new List<TreeViewItem>();
@@ -262,6 +269,12 @@ public partial class MainWindow : Window
ExpandAndFindNode(nodes, selectPath, out var selectedNode) && ExpandAndFindNode(nodes, selectPath, out var selectedNode) &&
selectedNode != null) selectedNode != null)
NavTree.SelectedItem = selectedNode; NavTree.SelectedItem = selectedNode;
ReloadWikiItem();
}catch (Exception ex)
{
Logger.Log($"Error while populating nav tree: {ex.Message}", Logger.LogType.Error);
}
} }
private TreeViewItem BuildNode(WikiItem item) private TreeViewItem BuildNode(WikiItem item)
@@ -276,7 +289,9 @@ public partial class MainWindow : Window
private string GetSelectedWikiTargetDirectory() private string GetSelectedWikiTargetDirectory()
{ {
var wikiRoot = Global._instance.wiki_storage_path; try
{
var wikiRoot = PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path);
if (NavTree.SelectedItem is TreeViewItem treeItem && treeItem.Tag is WikiItem selectedItem) if (NavTree.SelectedItem is TreeViewItem treeItem && treeItem.Tag is WikiItem selectedItem)
{ {
if (selectedItem.IsFolder) return selectedItem.Path; if (selectedItem.IsFolder) return selectedItem.Path;
@@ -284,12 +299,20 @@ public partial class MainWindow : Window
var parentDir = Path.GetDirectoryName(selectedItem.Path); var parentDir = Path.GetDirectoryName(selectedItem.Path);
if (!string.IsNullOrWhiteSpace(parentDir)) return parentDir; if (!string.IsNullOrWhiteSpace(parentDir)) return parentDir;
} }
return wikiRoot; return wikiRoot;
}catch (Exception ex)
{
Logger.Log($"Error while getting selected wiki target directory: {ex.Message}", Logger.LogType.Error);
}
return null;
} }
private static bool PathsEqual(string left, string right) private static bool PathsEqual(string left, string right)
{ {
left = PathUtilities.NormalizeFileSystemPath(left);
right = PathUtilities.NormalizeFileSystemPath(right);
var normalizedLeft = Path.GetFullPath(left) var normalizedLeft = Path.GetFullPath(left)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
var normalizedRight = Path.GetFullPath(right) var normalizedRight = Path.GetFullPath(right)
@@ -333,7 +356,7 @@ public partial class MainWindow : Window
private void OpenFolderButton_Click(object? sender, RoutedEventArgs e) private void OpenFolderButton_Click(object? sender, RoutedEventArgs e)
{ {
var path = Global._instance.wiki_storage_path; var path = PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path);
if (!Directory.Exists(path)) return; if (!Directory.Exists(path)) return;
try try
@@ -344,8 +367,9 @@ public partial class MainWindow : Window
UseShellExecute = true UseShellExecute = true
}); });
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while starting process: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -359,9 +383,9 @@ public partial class MainWindow : Window
}); });
if (folder == null || folder.Count == 0) return; if (folder == null || folder.Count == 0) return;
var chosen = folder[0].Path; var chosen = PathUtilities.NormalizeFileSystemPath(folder[0].Path);
TbWikiPath.Text = chosen.ToString(); TbWikiPath.Text = chosen;
Global._instance.wiki_storage_path = chosen.ToString(); Global._instance.wiki_storage_path = chosen;
Global.Save(); Global.Save();
// reinit wiki service and reload tree // reinit wiki service and reload tree
@@ -379,9 +403,9 @@ public partial class MainWindow : Window
}); });
if (folder == null || folder.Count == 0) return; if (folder == null || folder.Count == 0) return;
var chosen = folder[0].Path; var chosen = PathUtilities.NormalizeFileSystemPath(folder[0].Path);
TbFontPath.Text = chosen.ToString(); //TbFontPath.Text = chosen;
Global._instance.font_path = chosen.ToString(); Global._instance.font_path = chosen;
Global.Save(); Global.Save();
} }
@@ -395,9 +419,9 @@ public partial class MainWindow : Window
}); });
if (folder == null || folder.Count == 0) return; if (folder == null || folder.Count == 0) return;
var chosen = folder[0].Path; var chosen = PathUtilities.NormalizeFileSystemPath(folder[0].Path);
TbConfigPath.Text = chosen.ToString(); Global._instance.SetConfigPath(chosen);
Global._instance.config_path = chosen.ToString(); TbConfigPath.Text = Global._instance.config_path;
Global.Save(); Global.Save();
MessageBox.Show(this, "Bitte starten Sie das Programm neu, um die Änderungen wirksam zu machen.", "Achtung"); MessageBox.Show(this, "Bitte starten Sie das Programm neu, um die Änderungen wirksam zu machen.", "Achtung");
@@ -436,6 +460,7 @@ public partial class MainWindow : Window
TbSettingsCustomerDescription.Text = ""; TbSettingsCustomerDescription.Text = "";
TbSettingsCustomerName.Text = ""; TbSettingsCustomerName.Text = "";
TbSettingsCustomerPatchInfo.Text = ""; TbSettingsCustomerPatchInfo.Text = "";
TbSettingsCustomerName.Focus();
Settings.Save(); Settings.Save();
RefreshCustomerItems(); RefreshCustomerItems();
@@ -443,8 +468,9 @@ public partial class MainWindow : Window
{ {
LstSettingsCustomers.SelectedIndex = LstSettingsCustomers.Items.Count - 1; LstSettingsCustomers.SelectedIndex = LstSettingsCustomers.Items.Count - 1;
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while setting selected item: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -460,6 +486,7 @@ public partial class MainWindow : Window
private void LstSettingsCustomers_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) private void LstSettingsCustomers_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{ {
SetSettingsCustomerEnabledState(false);
if (LstSettingsCustomers.SelectedIndex < 0) return; if (LstSettingsCustomers.SelectedIndex < 0) return;
Settings._instance.customers.current = Settings._instance.customers.current =
((Customer)LstSettingsCustomers.SelectedItems[0]); ((Customer)LstSettingsCustomers.SelectedItems[0]);
@@ -474,9 +501,19 @@ public partial class MainWindow : Window
TbSettingsCustomerPatchInfo.Text = Settings._instance.customers.current.patch.ToString(); TbSettingsCustomerPatchInfo.Text = Settings._instance.customers.current.patch.ToString();
else else
TbSettingsCustomerPatchInfo.Text = ""; TbSettingsCustomerPatchInfo.Text = "";
SetSettingsCustomerEnabledState();
//} //}
} }
private void SetSettingsCustomerEnabledState(bool enable = true)
{
List<Object> nboom = new() { BtnSettingsImportCustomerAddressPatch, GrdCSVDividerButtonsAndTb, TbSettingsCustomerDescription, TbSettingsCustomerName, BtnDeleteCustomer, TbSettingsCustomerSenderAddress};
foreach (var obj in nboom)
{
(obj as Control).IsEnabled = enable;
}
}
private async void EditButton_Click(object? sender, RoutedEventArgs e) private async void EditButton_Click(object? sender, RoutedEventArgs e)
{ {
if (string.IsNullOrWhiteSpace(_selectedWikiFilePath)) if (string.IsNullOrWhiteSpace(_selectedWikiFilePath))
@@ -485,7 +522,13 @@ public partial class MainWindow : Window
return; return;
} }
var editedWikiFilePath = _selectedWikiFilePath;
EditorWindow ew = new(_selectedWikiFilePath); EditorWindow ew = new(_selectedWikiFilePath);
ew.Closed += (_, _) =>
{
if (!string.IsNullOrWhiteSpace(editedWikiFilePath) && File.Exists(editedWikiFilePath))
PopulateNavTree(editedWikiFilePath, editedWikiFilePath);
};
ew.Show(); ew.Show();
//await MessageBox.Show(this, "Edit feature is currently disabled.", "Edit Disabled"); //await MessageBox.Show(this, "Edit feature is currently disabled.", "Edit Disabled");
@@ -515,17 +558,25 @@ public partial class MainWindow : Window
{ {
LstSettingsCustomers.SelectedIndex = index; LstSettingsCustomers.SelectedIndex = index;
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while setting selected index: {ex.Message}", Logger.LogType.Error);
} }
} }
private void TbSettingsCustomerDescription_OnTextChanged(object? sender, TextChangedEventArgs e) private void TbSettingsCustomerDescription_OnTextChanged(object? sender, TextChangedEventArgs e)
{
try
{ {
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return; if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
foreach (var customer in Settings._instance.customers.customers) foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == Settings._instance.customers.current.ID) if (customer.ID == Settings._instance.customers.current.ID)
customer.description = TbSettingsCustomerDescription.Text; customer.description = TbSettingsCustomerDescription.Text;
} catch (Exception ex)
{
Logger.Log($"Error while changing customer description: {ex.Message}", Logger.LogType.Error);
}
//Settings.Save(); //Settings.Save();
} }
@@ -544,6 +595,8 @@ public partial class MainWindow : Window
} }
private async void BtnCustomerAddressSetImport_OnClick(object? sender, RoutedEventArgs e) private async void BtnCustomerAddressSetImport_OnClick(object? sender, RoutedEventArgs e)
{
try
{ {
MakeCalcManVisible(); MakeCalcManVisible();
var opts = new FilePickerOpenOptions(); var opts = new FilePickerOpenOptions();
@@ -602,6 +655,13 @@ public partial class MainWindow : Window
Settings.Save(); Settings.Save();
}
catch (Exception ex)
{
Logger.Log($"Error while importing: {ex.Message}", Logger.LogType.Error);
}
} }
public void RefreshAddressSetListItems(int customer_id) public void RefreshAddressSetListItems(int customer_id)
@@ -638,14 +698,29 @@ public partial class MainWindow : Window
BtnCheck.IsEnabled = true; BtnCheck.IsEnabled = true;
BtnCombine.IsEnabled = true; BtnCombine.IsEnabled = true;
BtnGenerateLabels.IsEnabled = true; BtnGenerateLabels.IsEnabled = true;
BtnShorten.IsEnabled = true;
// check for existing errors, otherwise disable the features
foreach(KasPerson pers in (LstCustomerAdressSets.SelectedItem as KasAddressList).KasPersons)
if (pers.PersonError != null)
{
BtnShorten.IsEnabled = true;
// BtnRepair.IsEnabled = true; // BtnRepair.IsEnabled = true;
// BtnShorten.IsEnabled = true; break;
}
else
{
BtnShorten.IsEnabled = false;
BtnRepair.IsEnabled = false;
}
} }
} }
private async void BtnSettingsImportCustomerAddressPatch_OnClick(object? sender, RoutedEventArgs e) private async void BtnSettingsImportCustomerAddressPatch_OnClick(object? sender, RoutedEventArgs e)
{
try
{ {
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return; if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
@@ -672,6 +747,11 @@ public partial class MainWindow : Window
Settings.Save(); Settings.Save();
} catch (Exception ex)
{
Logger.Log($"Error while importing customer address patch: {ex.Message}", Logger.LogType.Error);
}
} }
private void TbSettingsCustomerCsvSeparator_OnTextChanged(object? sender, TextChangedEventArgs e) private void TbSettingsCustomerCsvSeparator_OnTextChanged(object? sender, TextChangedEventArgs e)
@@ -689,11 +769,14 @@ public partial class MainWindow : Window
catch (FormatException ex) catch (FormatException ex)
{ {
MessageBox.Show(this, "Error while converting: " + ex.Message, "Could not parse"); MessageBox.Show(this, "Error while converting: " + ex.Message, "Could not parse");
Logger.Log($"Error while converting: {ex.Message}", Logger.LogType.Error);
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(this, "Unknown Error: " + ex.Message, "Error"); MessageBox.Show(this, "Unknown Error: " + ex.Message, "Error");
Logger.Log($"Error while converting: {ex.Message}", Logger.LogType.Error);
} }
} }
private void BtnCombineDifference_OnClick(object? sender, RoutedEventArgs e) private void BtnCombineDifference_OnClick(object? sender, RoutedEventArgs e)
@@ -705,9 +788,9 @@ public partial class MainWindow : Window
{ {
StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "difference", GetCombiningTyp()); StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "difference", GetCombiningTyp());
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while combining (difference): {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -720,9 +803,9 @@ public partial class MainWindow : Window
{ {
StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "union", GetCombiningTyp()); StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "union", GetCombiningTyp());
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while combining (union): {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -738,7 +821,7 @@ public partial class MainWindow : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Error while trying to start intersection: " + ex.Message); Logger.Log($"Error while combining (intersection): {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -773,36 +856,69 @@ public partial class MainWindow : Window
} }
private async void BtnStartGenerateLabels_OnClick(object? sender, RoutedEventArgs e) private async void BtnStartGenerateLabels_OnClick(object? sender, RoutedEventArgs e)
{
try
{ {
SavePdfExportOptions(); SavePdfExportOptions();
var saveDialog = new SaveFileDialog var saveDialog = new SaveFileDialog
{ {
DefaultExtension = "pdf", DefaultExtension = "pdf",
Filters = { new FileDialogFilter { Name = "PDF-Dateien", Extensions = { "pdf" } } } Filters =
{
new FileDialogFilter
{
Name = "PDF-Dateien",
Extensions = { "pdf" }
}
}
}; };
var filePath = await saveDialog.ShowAsync(this); var filePath = await saveDialog.ShowAsync(this);
if (!string.IsNullOrEmpty(filePath)) Logger.Log($"RAW: {filePath}");
if (!string.IsNullOrWhiteSpace(filePath))
{ {
filePath = PathUtilities.NormalizeFileSystemPath(filePath);
Logger.Log($"PATH: {filePath}");
var builder = new PdfBuilder(Settings._instance.pdfExport); var builder = new PdfBuilder(Settings._instance.pdfExport);
builder.CreateAddressLabelPdfFromAddressSetWithPlaceholder(( builder.CreateAddressLabelPdfFromAddressSetWithPlaceholder(
(KasAddressList)LstCustomerAdressSets.SelectedItem).ID, ((KasAddressList)LstCustomerAdressSets.SelectedItem).ID,
"Company Logo/Info", "Company Logo/Info",
filePath filePath
); );
//return true;
Logger.Log("PDF OK");
}
}
catch (Exception ex)
{
Logger.Log($"Error while generating labels: {ex.Message}", Logger.LogType.Error);
} }
} }
private void HookPdfExportOptionEvents() private void HookPdfExportOptionEvents()
{
try
{ {
var controls = GetPdfExportControls(); var controls = GetPdfExportControls();
foreach (var control in controls) control.ValueChanged += PdfExportOption_OnValueChanged; foreach (var control in controls) control.ValueChanged += PdfExportOption_OnValueChanged;
} }
catch (Exception ex)
{
Logger.Log($"Error while hooking pdf export margins: {ex.Message}", Logger.LogType.Error);
}
}
private void LoadPdfExportOptions() private void LoadPdfExportOptions()
{
try
{ {
var options = Settings._instance.pdfExport ?? new PdfExportSettings(); var options = Settings._instance.pdfExport ?? new PdfExportSettings();
@@ -821,6 +937,12 @@ public partial class MainWindow : Window
NudExpMargFontSize.Value = (decimal)options.fontSize; NudExpMargFontSize.Value = (decimal)options.fontSize;
NudExpMargSmallFontSize.Value = (decimal)options.smallFontSize; NudExpMargSmallFontSize.Value = (decimal)options.smallFontSize;
} }
catch (Exception ex)
{
Logger.Log($"Error while loading PDF Export Options: {ex.Message}", Logger.LogType.Error);
}
}
private void SavePdfExportOptions() private void SavePdfExportOptions()
{ {
@@ -900,6 +1022,7 @@ public partial class MainWindow : Window
public void RefreshCountryView() public void RefreshCountryView()
{ {
if (_suppressCountryRefresh) return; if (_suppressCountryRefresh) return;
try try
{ {
@@ -914,8 +1037,9 @@ public partial class MainWindow : Window
{ {
CountryList.Items.Clear(); CountryList.Items.Clear();
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while clearing country list: {ex.Message}", Logger.LogType.Error);
} }
foreach (var c in Global._instance.countries) CountryList.Items.Add(c.name); foreach (var c in Global._instance.countries) CountryList.Items.Add(c.name);
@@ -923,17 +1047,19 @@ public partial class MainWindow : Window
{ {
CountryList.SelectedIndex = country_index; CountryList.SelectedIndex = country_index;
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while setting selected item: {ex.Message}", Logger.LogType.Error);
} }
try try
{ {
_selectedCountry = Country.GetByName(CountryList.SelectedItems[0].ToString()); _selectedCountry = Country.GetByName(CountryList.SelectedItems[0].ToString());
} }
catch catch (Exception ex)
{ {
_selectedCountry = null; _selectedCountry = null;
Logger.Log($"Error while getting country: {ex.Message}", Logger.LogType.Error);
} }
if (_selectedCountry == null) return; if (_selectedCountry == null) return;
@@ -947,8 +1073,9 @@ public partial class MainWindow : Window
{ {
LbSettingsAlternatives.SelectedIndex = alt_index; LbSettingsAlternatives.SelectedIndex = alt_index;
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while setting selected item: {ex.Message}", Logger.LogType.Error);
} }
} }
finally finally
@@ -964,9 +1091,9 @@ public partial class MainWindow : Window
{ {
_selectedCountry.alternatives.Remove(selected.ToString()); _selectedCountry.alternatives.Remove(selected.ToString());
} }
catch catch (Exception ex)
{ {
Console.WriteLine("Error while removing country alternative"); Logger.Log($"Error while removing alternatives: {ex.Message}", Logger.LogType.Error);
} }
RefreshCountryView(); RefreshCountryView();
@@ -1027,11 +1154,18 @@ public partial class MainWindow : Window
result = result.Trim(); result = result.Trim();
if (!result.EndsWith(".md", StringComparison.OrdinalIgnoreCase)) result += ".md"; if (!result.EndsWith(".md", StringComparison.OrdinalIgnoreCase)) result += ".md";
if (!Directory.Exists(Global._instance.wiki_storage_path)) var wikiRoot = PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path);
Directory.CreateDirectory(Global._instance.wiki_storage_path); if (!Directory.Exists(wikiRoot))
Directory.CreateDirectory(wikiRoot);
try try
{ {
if (PathUtilities.HasInvalidFileNameChars(result))
{
MessageBox.Show(this, "Der Dateiname enthält ungültige Zeichen.", "Fehler");
return;
}
var targetDirectory = GetSelectedWikiTargetDirectory(); var targetDirectory = GetSelectedWikiTargetDirectory();
Directory.CreateDirectory(targetDirectory); Directory.CreateDirectory(targetDirectory);
var newFilePath = Path.Combine(targetDirectory, result); var newFilePath = Path.Combine(targetDirectory, result);
@@ -1041,6 +1175,7 @@ public partial class MainWindow : Window
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(this, ex.StackTrace, "Fehler"); MessageBox.Show(this, ex.StackTrace, "Fehler");
Logger.Log($"Error while adding wiki file: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -1051,11 +1186,18 @@ public partial class MainWindow : Window
result = result.Trim(); result = result.Trim();
if (!Directory.Exists(Global._instance.wiki_storage_path)) var wikiRoot = PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path);
Directory.CreateDirectory(Global._instance.wiki_storage_path); if (!Directory.Exists(wikiRoot))
Directory.CreateDirectory(wikiRoot);
try try
{ {
if (PathUtilities.HasInvalidFileNameChars(result))
{
MessageBox.Show(this, "Der Ordnername enthält ungültige Zeichen.", "Fehler");
return;
}
var targetDirectory = GetSelectedWikiTargetDirectory(); var targetDirectory = GetSelectedWikiTargetDirectory();
var newFolderPath = Path.Combine(targetDirectory, result); var newFolderPath = Path.Combine(targetDirectory, result);
Directory.CreateDirectory(newFolderPath); Directory.CreateDirectory(newFolderPath);
@@ -1064,34 +1206,39 @@ public partial class MainWindow : Window
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(this, ex.StackTrace, "Fehler"); MessageBox.Show(this, ex.StackTrace, "Fehler");
Logger.Log($"Error while adding wiki folder: {ex.Message}", Logger.LogType.Error);
} }
} }
private async void MnIAdSetRename_OnClick(object? sender, RoutedEventArgs e) private async void MnIAdSetRename_OnClick(object? sender, RoutedEventArgs e)
{ {
if (LstCustomerAdressSets.SelectedItems.Count > 0) var id = (LstCustomerAdressSets.SelectedItems[0] as KasAddressList).ID;
try
{
var result = await NamingWindow.Show(this);
if (result != null)
{
var id = KasAddressList.GetIDByAddressSetListItem(LstCustomerAdressSets.SelectedItems[0]
.ToString());
var cus_id = ((Customer)LstCustomers.SelectedItems[0]).ID; var cus_id = ((Customer)LstCustomers.SelectedItems[0]).ID;
var curr_set = new KasAddressList("");
foreach (var set in Settings._instance.addressSets.addresses) foreach (var set in Settings._instance.addressSets.addresses)
if (set.ID == id) if (set.ID == id)
{ {
set.Name = result; curr_set = set;
}
if (LstCustomerAdressSets.SelectedItems.Count > 0)
try
{
var result = await NamingWindow.Show(this, curr_set.Name);
if (result != null)
{
curr_set.Name = result;
Settings.Save(); Settings.Save();
RefreshAddressSetListItems(cus_id); RefreshAddressSetListItems(cus_id);
break;
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(this, ex.StackTrace, "Fehler"); MessageBox.Show(this, ex.StackTrace, "Fehler");
Logger.Log($"Error while renaming address set: {ex.Message}", Logger.LogType.Error);
} }
} }
@@ -1105,6 +1252,7 @@ public partial class MainWindow : Window
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(this, "Unknown Error: " + ex.Message, "Error"); MessageBox.Show(this, "Unknown Error: " + ex.Message, "Error");
Logger.Log($"Error while deleting customer: {ex.Message}", Logger.LogType.Error);
} }
RefreshCustomerItems(); RefreshCustomerItems();
} }
@@ -1131,10 +1279,45 @@ public partial class MainWindow : Window
TbSettingsCustomerCsvSeparator.Text = div; TbSettingsCustomerCsvSeparator.Text = div;
Settings.Save(); Settings.Save();
} }
catch catch (Exception ex)
{ {
Console.WriteLine("Error while parsing"); Logger.Log($"Error while changing CSV divider: {ex.Message}", Logger.LogType.Error);
} }
} }
private async void MnIAdSetDelete_OnClick(object? sender, RoutedEventArgs e)
{
if(await MessageBox.Show(this,"Wirklich löschen?","",MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
var cus_id = ((Customer)LstCustomers.SelectedItems[0]).ID;
var id = (LstCustomerAdressSets.SelectedItems[0] as KasAddressList).ID;
try
{
foreach (var set in Settings._instance.addressSets.addresses)
if (set.ID == id)
{
Settings._instance.addressSets.addresses.Remove(set);
Settings.Save();
RefreshAddressSetListItems(cus_id);
break;
}
}
catch (Exception ex)
{
MessageBox.Show(this, ex.StackTrace, "Fehler");
Logger.Log($"Error while deleting address set: {ex.Message}", Logger.LogType.Error);
}}
}
private void Tb_OnTextChanged(object? sender, TextChangedEventArgs e)
{
Global.Save();
}
private void BtnReloadWiki_OnClick(object? sender, RoutedEventArgs e)
{
PopulateNavTree();
}
} }
+1 -1
View File
@@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" SizeToContent="WidthAndHeight" mc:Ignorable="d" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen"
x:Class="Logof_Client.MessageBox" Icon="assets/icon.ico" x:Class="Logof_Client.MessageBox" Icon="assets/icon.ico"
Title="MessageBox"> Title="MessageBox">
<StackPanel> <StackPanel>
+1 -1
View File
@@ -52,7 +52,7 @@ public partial class NamingWindow : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Error while showing naming window: " + ex.Message); Logger.Log("Error while showing naming window: " + ex.Message, Logger.LogType.Warning);
return Task.FromResult<string>(null!); return Task.FromResult<string>(null!);
} }
} }
+57
View File
@@ -0,0 +1,57 @@
using System;
using System.IO;
namespace Logof_Client;
public static class PathUtilities
{
private static readonly char[] WindowsInvalidFileNameChars =
{
'<', '>', ':', '"', '/', '\\', '|', '?', '*'
};
private static readonly string[] WindowsReservedFileNames =
{
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
};
public static string NormalizeFileSystemPath(string path)
{
if (string.IsNullOrWhiteSpace(path)) return path;
if (Uri.TryCreate(path, UriKind.Absolute, out var uri) && uri.IsFile)
return uri.LocalPath;
return path;
}
public static string NormalizeFileSystemPath(Uri path)
{
return path.IsFile ? path.LocalPath : path.ToString();
}
public static bool HasInvalidFileNameChars(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName)) return true;
if (fileName.EndsWith(' ') || fileName.EndsWith('.')) return true;
if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) return true;
if (fileName.IndexOfAny(WindowsInvalidFileNameChars) >= 0) return true;
var nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
foreach (var reservedName in WindowsReservedFileNames)
{
if (string.Equals(fileName, reservedName, StringComparison.OrdinalIgnoreCase) ||
string.Equals(nameWithoutExtension, reservedName, StringComparison.OrdinalIgnoreCase))
return true;
}
foreach (var c in fileName)
{
if (char.IsControl(c)) return true;
}
return false;
}
}
+24
View File
@@ -28,6 +28,10 @@ public partial class ResultWindow : Window
private void GenerateView(List<KasPerson> result) private void GenerateView(List<KasPerson> result)
{ {
try
{
// Filter to only show persons with errors // Filter to only show persons with errors
var result_with_errors = result.Where(p => p.PersonError != null).ToList(); var result_with_errors = result.Where(p => p.PersonError != null).ToList();
LblResultCount.Content = $"{result_with_errors.Count}/{ur_result.Count} Ergebnisse"; LblResultCount.Content = $"{result_with_errors.Count}/{ur_result.Count} Ergebnisse";
@@ -39,6 +43,11 @@ public partial class ResultWindow : Window
// StkResults.Children.Clear(); // StkResults.Children.Clear();
// foreach (var person in result_with_errors) StkResults.Children.Add(CreatePersonGrid(person)); // foreach (var person in result_with_errors) StkResults.Children.Add(CreatePersonGrid(person));
} }
catch (Exception ex)
{
Logger.Log("Error while generating result view: " + ex.Message, Logger.LogType.Warning);
}
}
private Grid CreatePersonGrid(KasPerson person) private Grid CreatePersonGrid(KasPerson person)
{ {
@@ -105,6 +114,8 @@ public partial class ResultWindow : Window
} }
private void Load(List<KasPerson> result) private void Load(List<KasPerson> result)
{
try
{ {
var knownErrors = new List<AddressCheck.ErrorTypes>(); var knownErrors = new List<AddressCheck.ErrorTypes>();
var knownWarnings = new List<AddressCheck.WarningTypes>(); var knownWarnings = new List<AddressCheck.WarningTypes>();
@@ -145,12 +156,20 @@ public partial class ResultWindow : Window
GenerateView(result); GenerateView(result);
} }
catch (Exception ex)
{
Logger.Log("Error while showing naming window: " + ex.Message, Logger.LogType.Warning);
}
}
private void BtnUpdateFilter_OnClick(object? sender, RoutedEventArgs e) private void BtnUpdateFilter_OnClick(object? sender, RoutedEventArgs e)
{ {
} }
private void UpdateFilter() private void UpdateFilter()
{
try
{ {
var temp_result = new List<KasPerson>(); var temp_result = new List<KasPerson>();
@@ -211,6 +230,11 @@ public partial class ResultWindow : Window
// foreach (var person in temp_result) TbResults.Text += person.PersonError.GetString() +"\n"; // foreach (var person in temp_result) TbResults.Text += person.PersonError.GetString() +"\n";
// StkResults.Children.Clear(); // StkResults.Children.Clear();
// foreach (var person in temp_result) StkResults.Children.Add(CreatePersonGrid(person)); // foreach (var person in temp_result) StkResults.Children.Add(CreatePersonGrid(person));
} catch (Exception ex)
{
Logger.Log("Error while updating filter: " + ex.Message, Logger.LogType.Warning);
}
} }
+15 -2
View File
@@ -38,6 +38,8 @@ public class AddressCheck
} }
public async Task<List<KasPerson>> Perform(int id) public async Task<List<KasPerson>> Perform(int id)
{
try
{ {
// Find the index of the address set with the given id // Find the index of the address set with the given id
var adset_index = -1; var adset_index = -1;
@@ -238,7 +240,8 @@ public class AddressCheck
// Directly set PersonError in the address set // Directly set PersonError in the address set
var person_index = adset.KasPersons.IndexOf(person); var person_index = adset.KasPersons.IndexOf(person);
if (person_index >= 0) if (person_index >= 0)
Settings._instance.addressSets.addresses[adset_index].KasPersons[person_index].PersonError = Settings._instance.addressSets.addresses[adset_index].KasPersons[person_index]
.PersonError =
new KasPersonError((errors, warnings)); new KasPersonError((errors, warnings));
} }
@@ -248,7 +251,8 @@ public class AddressCheck
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
{ {
if (hasFaults) if (hasFaults)
_progress.AddToLog($"Person mit id {person.id} ist fehlerhaft", Convert.ToInt32(percent).ToString()); _progress.AddToLog($"Person mit id {person.id} ist fehlerhaft",
Convert.ToInt32(percent).ToString());
_progress.ChangePercentage(percent); _progress.ChangePercentage(percent);
}); });
@@ -261,5 +265,14 @@ public class AddressCheck
return Settings._instance.addressSets.addresses[adset_index].KasPersons return Settings._instance.addressSets.addresses[adset_index].KasPersons
.Where(p => p.PersonError != null) .Where(p => p.PersonError != null)
.ToList(); .ToList();
} }
catch (Exception ex)
{
Logger.Log($"Error while performing address check: {ex.Message}", Logger.LogType.Error);
}
return null;
}
} }
+27 -7
View File
@@ -64,12 +64,8 @@ public static class AddressCreator
// let's get started: we start from the bottom // let's get started: we start from the bottom
// if the country is not Germany, set it; try to map via Global countries alternatives -> translation // if the country is not Germany, set it; try to map via Global countries alternatives -> translation
var trimmedLand = (address.land ?? "").Trim(); var trimmedLand = (address.land ?? "").Trim();
var trimmedLowerLand = trimmedLand.ToLower();
var isGermany = trimmedLowerLand == "germany" || trimmedLowerLand == "ger" ||
trimmedLowerLand == "" || trimmedLowerLand == "de" ||
trimmedLowerLand == "deutschland";
if (!isGermany) if (!address.IsGermany())
{ {
var countryToShow = trimmedLand; // default: use raw land value var countryToShow = trimmedLand; // default: use raw land value
@@ -104,7 +100,9 @@ public static class AddressCreator
// Alternative A: pplz valid and city existing // Alternative A: pplz valid and city existing
if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.pplz, address.land)) if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.pplz, address.land))
{ {
string pplz = NormalizeGermanPLZ(address.pplz); string pplz = address.pplz;
if (address.IsGermany()) pplz = NormalizeGermanPLZ(address.pplz);
KasPerson.SetUsedPLZ(id, pplz); KasPerson.SetUsedPLZ(id, pplz);
string_address = pplz + " " + address.ort + "\n" + string_address; string_address = pplz + " " + address.ort + "\n" + string_address;
address_line_count++; address_line_count++;
@@ -152,7 +150,10 @@ public static class AddressCreator
} // Alternative B: plz valid and city existing } // Alternative B: plz valid and city existing
else if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.plz, address.land)) else if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.plz, address.land))
{ {
string plz = NormalizeGermanPLZ(address.plz); string plz = address.plz;
if (address.IsGermany()) plz = NormalizeGermanPLZ(address.plz);
KasPerson.SetUsedPLZ(id, plz); KasPerson.SetUsedPLZ(id, plz);
string_address = plz + " " + address.ort + "\n" + string_address; string_address = plz + " " + address.ort + "\n" + string_address;
address_line_count++; address_line_count++;
@@ -204,6 +205,8 @@ public static class AddressCreator
public static string CreateNameLine(string anredezus, string anrede, string titel, string vorname, string adel, public static string CreateNameLine(string anredezus, string anrede, string titel, string vorname, string adel,
string name, string namezus) string name, string namezus)
{
try
{ {
if (!string.IsNullOrWhiteSpace(anredezus)) if (!string.IsNullOrWhiteSpace(anredezus))
return string.Join(" ", return string.Join(" ",
@@ -219,6 +222,13 @@ public static class AddressCreator
) )
+ (string.IsNullOrWhiteSpace(namezus) ? "" : $" ({namezus.Trim()})"); + (string.IsNullOrWhiteSpace(namezus) ? "" : $" ({namezus.Trim()})");
} }
catch (Exception ex)
{
Logger.Log($"Error while performing address name line creation: {ex.Message}", Logger.LogType.Error);
}
return null;
}
/// <summary> /// <summary>
/// Returns true if a plz (or pplz) is valid /// Returns true if a plz (or pplz) is valid
@@ -227,6 +237,8 @@ public static class AddressCreator
/// <param name="land">country, to check the plz</param> /// <param name="land">country, to check the plz</param>
/// <returns>true or faslse, depending on result :+1:</returns> /// <returns>true or faslse, depending on result :+1:</returns>
public static bool CheckPLZ(string plz, string land) public static bool CheckPLZ(string plz, string land)
{
try
{ {
if (string.IsNullOrWhiteSpace(plz)) return false; if (string.IsNullOrWhiteSpace(plz)) return false;
@@ -253,6 +265,14 @@ public static class AddressCreator
// For non-German countries, accept any non-empty postal code // For non-German countries, accept any non-empty postal code
return true; return true;
} }
catch (Exception ex)
{
Logger.Log($"Error while performing address plz check: {ex.Message}", Logger.LogType.Error);
}
return false;
}
public static string NormalizeGermanPLZ(string plz) public static string NormalizeGermanPLZ(string plz)
{ {
+22
View File
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Logof_Client;
public class AddressPatch public class AddressPatch
{ {
@@ -57,6 +58,8 @@ public class AddressPatch
public bool has_funktionad { get; set; } public bool has_funktionad { get; set; }
public static AddressPatch Import(Uri filename) public static AddressPatch Import(Uri filename)
{
try
{ {
var patch = new AddressPatch(); var patch = new AddressPatch();
@@ -92,9 +95,20 @@ public class AddressPatch
return patch; return patch;
} }
catch (Exception ex)
{
Logger.Log($"Error while importing address patch: {ex.Message}", Logger.LogType.Error);
}
return null;
}
public override string ToString() public override string ToString()
{
try
{ {
var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
var stringProps = properties.Where(p => p.PropertyType == typeof(string) && p.Name.EndsWith("_is")); var stringProps = properties.Where(p => p.PropertyType == typeof(string) && p.Name.EndsWith("_is"));
@@ -115,4 +129,12 @@ public class AddressPatch
return lines.ToString().TrimEnd(); return lines.ToString().TrimEnd();
} }
catch (Exception ex)
{
Logger.Log($"Error while parsing: {ex.Message}", Logger.LogType.Error);
}
return "Error while parsing";
}
} }
+11 -9
View File
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Logof_Client; namespace Logof_Client;
@@ -9,15 +10,16 @@ public class AddressRepair(ProgressWindow progressWindow)
public KasAddressList Perform(KasAddressList all_addresses, public KasAddressList Perform(KasAddressList all_addresses,
List<(int, List<AddressCheck.ErrorTypes>)> failed_addresses) List<(int, List<AddressCheck.ErrorTypes>)> failed_addresses)
{ {
// foreach (var k in all_addresses.KasPersons) try
// foreach (var p in failed_addresses) {
// {
// if (k.refsid != p.Item1) continue; }
// catch (Exception ex)
// if (p.Item1.Contains(AddressCheck.WarningTypes.DoubledRefsid)) {
// { Logger.Log($"Error while performing address repair: {ex.Message}", Logger.LogType.Error);
// } }
// }
return null;
return null; return null;
} }
+7 -2
View File
@@ -12,7 +12,8 @@ public class AddressShortener(ProgressWindow progressWindow)
public async Task Perform(KasAddressList list) public async Task Perform(KasAddressList list)
{ {
// find doubled addresses by refsid try
{
List<int> doubled_ids = new List<int>(); List<int> doubled_ids = new List<int>();
for (int i = 0; i < list.KasPersons.Count; i++) for (int i = 0; i < list.KasPersons.Count; i++)
{ {
@@ -73,7 +74,11 @@ public class AddressShortener(ProgressWindow progressWindow)
// does this remove both of the doubled addresses? // does this remove both of the doubled addresses?
list.KasPersons.Remove(list.KasPersons.Find(x => x.id == id)); list.KasPersons.Remove(list.KasPersons.Find(x => x.id == id));
} }
}
catch (Exception ex)
{
Logger.Log($"Error while performing address shortener: {ex.Message}", Logger.LogType.Error);
}
//return null;
} }
} }
+61
View File
@@ -25,6 +25,8 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> Perform(List<KasAddressList> address_lists, string type, CombineType comb_type, public async Task<(KasAddressList, KasAddressList)> Perform(List<KasAddressList> address_lists, string type, CombineType comb_type,
bool? exportUnused, bool? deleteOld) bool? exportUnused, bool? deleteOld)
{
try
{ {
var result = await Execute(address_lists,type,comb_type,exportUnused); var result = await Execute(address_lists,type,comb_type,exportUnused);
@@ -37,11 +39,21 @@ public class CombineAddresses
} }
return result; return result;
}
catch (Exception ex)
{
Logger.Log($"Error while performing address combining: {ex.Message}", Logger.LogType.Error);
}
return (null,null);
} }
private async Task<(KasAddressList, KasAddressList)> Execute(List<KasAddressList> address_lists, string type, CombineType comb_type, private async Task<(KasAddressList, KasAddressList)> Execute(List<KasAddressList> address_lists, string type, CombineType comb_type,
bool? exportUnused) bool? exportUnused)
{
try
{ {
if (type == "difference") return await Difference(address_lists, comb_type, exportUnused); if (type == "difference") return await Difference(address_lists, comb_type, exportUnused);
if (type == "union") return await Union(address_lists, comb_type, exportUnused); if (type == "union") return await Union(address_lists, comb_type, exportUnused);
@@ -49,6 +61,14 @@ public class CombineAddresses
if (type == "symdiff") return await SymmetricDifference(address_lists, comb_type, exportUnused); if (type == "symdiff") return await SymmetricDifference(address_lists, comb_type, exportUnused);
return (null, null); return (null, null);
} }
catch (Exception ex)
{
Logger.Log($"Error while executing address combining: {ex.Message}", Logger.LogType.Error);
}
return (null,null);
}
/// <summary> /// <summary>
@@ -60,6 +80,7 @@ public class CombineAddresses
/// <returns></returns> /// <returns></returns>
public bool CompareAddresses(KasPerson first, KasPerson second, CombineType comb_type) public bool CompareAddresses(KasPerson first, KasPerson second, CombineType comb_type)
{ {
// A refsid of 0 means "missing", so it must not collapse unrelated entries. // A refsid of 0 means "missing", so it must not collapse unrelated entries.
if(comb_type == CombineType.refsid) if(comb_type == CombineType.refsid)
if (first.refsid != 0 && second.refsid != 0 && first.refsid == second.refsid) return true; if (first.refsid != 0 && second.refsid != 0 && first.refsid == second.refsid) return true;
@@ -95,6 +116,8 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> Difference(List<KasAddressList> address_lists, CombineType comb_type, public async Task<(KasAddressList, KasAddressList)> Difference(List<KasAddressList> address_lists, CombineType comb_type,
bool? return_unused, bool? return_unused,
Progress? progress = null) Progress? progress = null)
{
try
{ {
if (address_lists == null || address_lists.Count == 0) if (address_lists == null || address_lists.Count == 0)
return (new KasAddressList(await KasAddressList.GenerateName("difference")), null); return (new KasAddressList(await KasAddressList.GenerateName("difference")), null);
@@ -133,10 +156,20 @@ public class CombineAddresses
if (return_unused == true) return (result, second_result); if (return_unused == true) return (result, second_result);
return (result, null); return (result, null);
} }
catch (Exception ex)
{
Logger.Log($"Error while performing difference-combining: {ex.Message}", Logger.LogType.Error);
}
return (null,null);
}
public async Task<(KasAddressList, KasAddressList)> Union(List<KasAddressList> address_lists, CombineType comb_type, bool? return_unused, public async Task<(KasAddressList, KasAddressList)> Union(List<KasAddressList> address_lists, CombineType comb_type, bool? return_unused,
Progress progress = null) Progress progress = null)
{
try
{ {
var result = new KasAddressList(await KasAddressList.GenerateName("union")); var result = new KasAddressList(await KasAddressList.GenerateName("union"));
var second_result = new KasAddressList("none"); var second_result = new KasAddressList("none");
@@ -172,6 +205,14 @@ public class CombineAddresses
if (return_unused == true) return (result, second_result); if (return_unused == true) return (result, second_result);
return (result, null); return (result, null);
} }
catch (Exception ex)
{
Logger.Log($"Error while performing union-combining: {ex.Message}", Logger.LogType.Error);
}
return (null,null);
}
public async Task<KasAddressList> MoveDuplicatesToNew() public async Task<KasAddressList> MoveDuplicatesToNew()
@@ -181,6 +222,8 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> Intersection(List<KasAddressList> address_lists, CombineType comb_type, public async Task<(KasAddressList, KasAddressList)> Intersection(List<KasAddressList> address_lists, CombineType comb_type,
bool? return_unused, Progress progress = null) bool? return_unused, Progress progress = null)
{
try
{ {
var result = new KasAddressList(await KasAddressList.GenerateName("intersection")); var result = new KasAddressList(await KasAddressList.GenerateName("intersection"));
var second_result = new KasAddressList("none"); var second_result = new KasAddressList("none");
@@ -225,10 +268,20 @@ public class CombineAddresses
if (return_unused == true) return (result, second_result); if (return_unused == true) return (result, second_result);
return (result, null); return (result, null);
} }
catch (Exception ex)
{
Logger.Log($"Error while performing intersection-combining: {ex.Message}", Logger.LogType.Error);
}
return (null,null);
}
public async Task<(KasAddressList, KasAddressList)> SymmetricDifference(List<KasAddressList> address_lists, CombineType comb_type, public async Task<(KasAddressList, KasAddressList)> SymmetricDifference(List<KasAddressList> address_lists, CombineType comb_type,
bool? return_unused, Progress progress = null) bool? return_unused, Progress progress = null)
{
try
{ {
var result = new KasAddressList(await KasAddressList.GenerateName("symmetric_difference")); var result = new KasAddressList(await KasAddressList.GenerateName("symmetric_difference"));
var second_result = new KasAddressList("none"); var second_result = new KasAddressList("none");
@@ -284,6 +337,14 @@ public class CombineAddresses
if (return_unused == true) return (result, second_result); if (return_unused == true) return (result, second_result);
return (result, null); return (result, null);
} }
catch (Exception ex)
{
Logger.Log($"Error while performing symdiff-combining: {ex.Message}", Logger.LogType.Error);
}
return (null,null);
}
} }
+11
View File
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -64,6 +65,8 @@ public class CsvBuilder
} }
private string EscapeCsvField(string? value) private string EscapeCsvField(string? value)
{
try
{ {
var field = value ?? string.Empty; var field = value ?? string.Empty;
var mustQuote = field.Contains(Separator) || field.Contains('"') || field.Contains('\r') || field.Contains('\n'); var mustQuote = field.Contains(Separator) || field.Contains('"') || field.Contains('\r') || field.Contains('\n');
@@ -72,4 +75,12 @@ public class CsvBuilder
return "\"" + field.Replace("\"", "\"\"") + "\""; return "\"" + field.Replace("\"", "\"\"") + "\"";
} }
catch (Exception ex)
{
Logger.Log($"Error while escapting csv field: {ex.Message}",Logger.LogType.Warning);
}
return "";
}
} }
+29 -2
View File
@@ -19,6 +19,8 @@ public class DataImport
} }
private static async Task<(bool, KasAddressList)> ImportKasAddressListWithoutPatch(Uri pathToCsv, char separator) private static async Task<(bool, KasAddressList)> ImportKasAddressListWithoutPatch(Uri pathToCsv, char separator)
{
try
{ {
if (!File.Exists(pathToCsv.LocalPath)) if (!File.Exists(pathToCsv.LocalPath))
{ {
@@ -83,7 +85,7 @@ public class DataImport
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error while parsing line: {line} - {ex.Message}"); Logger.Log($"Error while creating new kas person (import): {ex.Message}",Logger.LogType.Error);
Console.WriteLine(ex.StackTrace); Console.WriteLine(ex.StackTrace);
return (false, null); return (false, null);
} }
@@ -91,9 +93,18 @@ public class DataImport
return (true, imported); return (true, imported);
} }
catch (Exception ex)
{
Logger.Log($"Error while importing kas address list without patch: {ex.Message}",Logger.LogType.Error);
}
return (false, null);
}
private static async Task<(bool, KasAddressList)> ImportKasAddressListWithPatch(Uri pathToCsv, AddressPatch patch, private static async Task<(bool, KasAddressList)> ImportKasAddressListWithPatch(Uri pathToCsv, AddressPatch patch,
char separator) char separator)
{
try
{ {
if (!File.Exists(pathToCsv.LocalPath)) if (!File.Exists(pathToCsv.LocalPath))
{ {
@@ -217,13 +228,19 @@ public class DataImport
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error while parsing line: {line} - {ex.Message}"); Logger.Log($"Error while creating kas person (import, patch): {ex.Message}",Logger.LogType.Error);
Console.WriteLine(ex.StackTrace); Console.WriteLine(ex.StackTrace);
return (false, null); return (false, null);
} }
} }
return (true, imported); return (true, imported);
}
catch (Exception ex)
{
Logger.Log($"Error while importing kas address list with patch: {ex.Message}",Logger.LogType.Error);
}
// int GenerateNewRefsid() // int GenerateNewRefsid()
// { // {
@@ -236,6 +253,7 @@ public class DataImport
// last_refsid = biggest + 1; // last_refsid = biggest + 1;
// return last_refsid; // return last_refsid;
// } // }
return (false, null);
} }
@@ -245,6 +263,8 @@ public class DataImport
} }
private static string[] ParseCsvLine(string line, char separator) private static string[] ParseCsvLine(string line, char separator)
{
try
{ {
var fields = new List<string>(); var fields = new List<string>();
var current = new StringBuilder(); var current = new StringBuilder();
@@ -280,4 +300,11 @@ public class DataImport
fields.Add(current.ToString().Trim()); fields.Add(current.ToString().Trim());
return fields.ToArray(); return fields.ToArray();
} }
catch (Exception ex)
{
Logger.Log($"Error while persing csv line: {ex.Message}",Logger.LogType.Error);
}
return [];
}
} }
+702 -52
View File
@@ -17,6 +17,8 @@ public class PdfBuilder
private readonly XFont _smallFont; private readonly XFont _smallFont;
public PdfBuilder(PdfExportSettings? settings = null) public PdfBuilder(PdfExportSettings? settings = null)
{
try
{ {
EnsureFontResolverRegistered(); EnsureFontResolverRegistered();
_settings = settings ?? new PdfExportSettings(); _settings = settings ?? new PdfExportSettings();
@@ -32,8 +34,9 @@ public class PdfBuilder
chosenFamily = StripStyleSuffix(Path.GetFileNameWithoutExtension(first)) ?? chosenFamily; chosenFamily = StripStyleSuffix(Path.GetFileNameWithoutExtension(first)) ?? chosenFamily;
} }
} }
catch catch (Exception ex)
{ {
Logger.Log($"Error while searching for fonts: {ex.Message}",Logger.LogType.Error);
chosenFamily = "Arial"; chosenFamily = "Arial";
} }
@@ -41,15 +44,32 @@ public class PdfBuilder
_regularFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Regular); _regularFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Regular);
_smallFont = new XFont(chosenFamily, _settings.smallFontSize, XFontStyleEx.Regular); _smallFont = new XFont(chosenFamily, _settings.smallFontSize, XFontStyleEx.Regular);
} }
catch (Exception ex)
{
Logger.Log($"Error while font resolving: {ex.Message}",Logger.LogType.Error);
}
}
private static void EnsureFontResolverRegistered() private static void EnsureFontResolverRegistered()
{
try
{ {
if (GlobalFontSettings.FontResolver != null) return; if (GlobalFontSettings.FontResolver != null) return;
//var fontsDir = Path.Combine(AppContext.BaseDirectory, "fonts"); //var fontsDir = Path.Combine(AppContext.BaseDirectory, "fonts");
GlobalFontSettings.FontResolver = new StableFontResolver(Global._instance.font_path); GlobalFontSettings.FontResolver = new StableFontResolver(Global._instance.font_path);
} }
catch (Exception ex)
{
Logger.Log($"Error while ensuring font resolver register state: {ex.Message}",Logger.LogType.Error);
}
}
private static string StripStyleSuffix(string name) private static string StripStyleSuffix(string name)
{
try
{ {
if (string.IsNullOrEmpty(name)) return name; if (string.IsNullOrEmpty(name)) return name;
var idx = name.IndexOf('-'); var idx = name.IndexOf('-');
@@ -58,6 +78,14 @@ public class PdfBuilder
return name.Substring(0, idx); return name.Substring(0, idx);
return name; return name;
} }
catch (Exception ex)
{
Logger.Log($"Error while stripping style suffix: {ex.Message}",Logger.LogType.Error);
}
return null;
}
/// <summary> /// <summary>
@@ -68,6 +96,8 @@ public class PdfBuilder
/// <param name="outputPath">Path where the PDF should be saved</param> /// <param name="outputPath">Path where the PDF should be saved</param>
public void CreateAddressLabelPdfFromAddressSetWithPlaceholder(int addressSetId, string placeholderText, public void CreateAddressLabelPdfFromAddressSetWithPlaceholder(int addressSetId, string placeholderText,
string outputPath) string outputPath)
{
try
{ {
// Find the AddressSet by ID // Find the AddressSet by ID
var addressSet = Settings._instance.addressSets.GetAddressSetByID(addressSetId); var addressSet = Settings._instance.addressSets.GetAddressSetByID(addressSetId);
@@ -115,6 +145,13 @@ public class PdfBuilder
{ {
ExportRunningSheets(addressSetId, outputPath); ExportRunningSheets(addressSetId, outputPath);
} }
CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath);
}
catch (Exception ex)
{
Logger.Log($"Error while creating address label pdf from address set with placeholder: {ex.Message}",Logger.LogType.Error);
}
} }
/// <summary> /// <summary>
@@ -124,6 +161,8 @@ public class PdfBuilder
/// <param name="placeholderText">Text for the first cell (top-left)</param> /// <param name="placeholderText">Text for the first cell (top-left)</param>
/// <param name="outputPath">Path where the PDF should be saved</param> /// <param name="outputPath">Path where the PDF should be saved</param>
public void CreateAddressLabelPdfWithPlaceholder(List<string> addresses, string placeholderText, string outputPath) public void CreateAddressLabelPdfWithPlaceholder(List<string> addresses, string placeholderText, string outputPath)
{
try
{ {
if (addresses == null || addresses.Count == 0) if (addresses == null || addresses.Count == 0)
throw new ArgumentException("Addresses array cannot be null or empty"); throw new ArgumentException("Addresses array cannot be null or empty");
@@ -146,6 +185,12 @@ public class PdfBuilder
document.Save(outputPath); document.Save(outputPath);
} }
catch (Exception ex)
{
Logger.Log($"Error while creating address label pdf with placeholder: {ex.Message}",Logger.LogType.Error);
}
}
private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex) private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex)
{ {
@@ -168,6 +213,8 @@ public class PdfBuilder
private void DrawPageWithPlaceholder(XGraphics gfx, List<string> addresses, ref int addressIndex, private void DrawPageWithPlaceholder(XGraphics gfx, List<string> addresses, ref int addressIndex,
ref bool isFirstCell, string placeholderText) ref bool isFirstCell, string placeholderText)
{
try
{ {
for (var row = 0; row < _settings.rowsPerPage; row++) for (var row = 0; row < _settings.rowsPerPage; row++)
for (var col = 0; col < _settings.columnsPerPage; col++) for (var col = 0; col < _settings.columnsPerPage; col++)
@@ -192,8 +239,16 @@ public class PdfBuilder
} }
} }
} }
catch (Exception ex)
{
Logger.Log($"Error while drawing page with placholder: {ex.Message}",Logger.LogType.Error);
}
}
private void DrawCell(XGraphics gfx, double x, double y, string? address) private void DrawCell(XGraphics gfx, double x, double y, string? address)
{
try
{ {
var cellWidthPoints = MmToPoints(GetCellWidthMm()); var cellWidthPoints = MmToPoints(GetCellWidthMm());
var cellHeightPoints = MmToPoints(GetCellHeightMm()); var cellHeightPoints = MmToPoints(GetCellHeightMm());
@@ -205,8 +260,16 @@ public class PdfBuilder
// Draw address content if available // Draw address content if available
if (!string.IsNullOrEmpty(address)) DrawMarkdownText(gfx, address, x, y, cellWidthPoints, cellHeightPoints); if (!string.IsNullOrEmpty(address)) DrawMarkdownText(gfx, address, x, y, cellWidthPoints, cellHeightPoints);
} }
catch (Exception ex)
{
Logger.Log($"Error while drawing cell: {ex.Message}",Logger.LogType.Error);
}
}
private void DrawEmptyCell(XGraphics gfx, double x, double y) private void DrawEmptyCell(XGraphics gfx, double x, double y)
{
try
{ {
var cellWidthPoints = MmToPoints(GetCellWidthMm()); var cellWidthPoints = MmToPoints(GetCellWidthMm());
var cellHeightPoints = MmToPoints(GetCellHeightMm()); var cellHeightPoints = MmToPoints(GetCellHeightMm());
@@ -214,8 +277,16 @@ public class PdfBuilder
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints); var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
gfx.DrawRectangle(XPens.Black, rect); gfx.DrawRectangle(XPens.Black, rect);
} }
catch (Exception ex)
{
Logger.Log($"Error while drawing empty cell: {ex.Message}",Logger.LogType.Error);
}
}
private void DrawMarkdownText(XGraphics gfx, string text, double x, double y, double cellWidth, double cellHeight) private void DrawMarkdownText(XGraphics gfx, string text, double x, double y, double cellWidth, double cellHeight)
{
try
{ {
var paddingLeftPoints = MmToPoints(_settings.cellPaddingLeftMm); var paddingLeftPoints = MmToPoints(_settings.cellPaddingLeftMm);
var paddingRightPoints = MmToPoints(_settings.cellPaddingRightMm); var paddingRightPoints = MmToPoints(_settings.cellPaddingRightMm);
@@ -250,8 +321,16 @@ public class PdfBuilder
currentY += lineHeight; currentY += lineHeight;
} }
} }
catch (Exception ex)
{
Logger.Log($"Error while drawing markdown text: {ex.Message}",Logger.LogType.Error);
}
}
private void DrawLineWithMarkdown(XGraphics gfx, string line, double x, double y, double maxWidth) private void DrawLineWithMarkdown(XGraphics gfx, string line, double x, double y, double maxWidth)
{
try
{ {
if (string.IsNullOrWhiteSpace(line)) return; if (string.IsNullOrWhiteSpace(line)) return;
var currentX = x; var currentX = x;
@@ -341,8 +420,16 @@ public class PdfBuilder
i = textEnd; i = textEnd;
} }
} }
catch (Exception ex)
{
Logger.Log($"Error while drawing markdown line: {ex.Message}",Logger.LogType.Error);
}
}
private string TruncateTextToWidth(XGraphics gfx, string text, XFont font, double maxWidth) private string TruncateTextToWidth(XGraphics gfx, string text, XFont font, double maxWidth)
{
try
{ {
if (string.IsNullOrEmpty(text)) if (string.IsNullOrEmpty(text))
return text; return text;
@@ -357,6 +444,13 @@ public class PdfBuilder
return string.Empty; return string.Empty;
} }
catch (Exception ex)
{
Logger.Log($"Error while truncating text to width: {ex.Message}",Logger.LogType.Error);
}
return null;
}
/// <summary> /// <summary>
/// Converts millimeters to points (1 mm = 2.834645669 points) /// Converts millimeters to points (1 mm = 2.834645669 points)
@@ -400,21 +494,27 @@ public class PdfBuilder
public void ExportRunningSheets(int setID, string path) public void ExportRunningSheets(int setID, string path)
{ {
string international_path = path;
if (path.EndsWith(".pdf")) if (path.EndsWith(".pdf"))
{ {
path = path.Substring(0, path.Length - 4); path = path.Substring(0, path.Length - 4);
international_path = path;
path = path + "-Laufzettel.pdf"; path = path + "-Laufzettel.pdf";
international_path = international_path + "-Laufzettel-International.pdf";
} }
else else
{ {
path = path + "-Laufzettel.pdf"; path = path + "-Laufzettel.pdf";
international_path = international_path + "-Laufzettel-International.pdf";
} }
CreateRunningSheets(setID, path); CreateGermanyRunningSheets(setID, path);
CreateInternationalRunningSheets(setID, international_path);
} }
public void CreateRunningSheets(int setID, string path)
public void CreateGermanyRunningSheets(int setID, string path)
{ {
KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID); KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID);
var document = new PdfDocument(); var document = new PdfDocument();
@@ -422,60 +522,94 @@ public class PdfBuilder
document.Info.Subject = "powered by logofclient"; document.Info.Subject = "powered by logofclient";
document.Info.Author = "logofclient"; document.Info.Author = "logofclient";
int margin = 50; var grouped_nums = GroupAddresses(setID).ToList();
var grouped_nums = GroupAddresses(setID); // Zwei Tabellen pro A4-Seite
int sheets = (grouped_nums.Count + 1) / 2;
foreach (var result in grouped_nums) // Layout
double marginX = 20;
double marginY = 20;
double gapY = 12;
for (int pageIndex = 0; pageIndex < sheets; pageIndex++)
{ {
var page = document.AddPage(); var page = document.AddPage();
page.Size = PageSize.A4; page.Size = PageSize.A4;
var gfx = XGraphics.FromPdfPage(page); var gfx = XGraphics.FromPdfPage(page);
var width = page.Width.Point-margin; double pageW = page.Width.Point;
var height = page.Height.Point-margin; double pageH = page.Height.Point;
gfx.DrawLine(XPens.Black, margin, margin, margin, height);
gfx.DrawLine(XPens.Black, margin, margin, width, margin);
gfx.DrawLine(XPens.Black, width, margin, width, height);
gfx.DrawLine(XPens.Black, margin, height, width, height);
var boldfont = new XFont("Cantarell", 11, XFontStyleEx.Bold); double usableW = pageW - 2 * marginX;
var font = new XFont("Cantarell", 11, XFontStyleEx.Regular); double usableH = pageH - 2 * marginY;
var bigboldfont = new XFont("Cantarell", 35, XFontStyleEx.Bold); double tableH = (usableH - gapY) / 2.0;
// Versandinfo double top1 = marginY;
gfx.DrawString($"Versand {list.Name}", boldfont, XBrushes.Black, double top2 = marginY + tableH + gapY;
new XRect(margin+5, margin, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Start: ", font, XBrushes.Black,
new XRect(margin+5, margin+25, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{result.Item3}", font, XBrushes.Black,
new XRect(margin+75, margin+25, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Ende: ", font, XBrushes.Black,
new XRect(margin+5, margin+40, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{result.Item4}", font, XBrushes.Black,
new XRect(margin+75, margin+40, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Kunde: ", font, XBrushes.Black,
new XRect(margin+5, margin+55, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{Customer.GetCustomerByID(list.owner_id).name}", font, XBrushes.Black,
new XRect(margin+75, margin+55, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Absender: ", font, XBrushes.Black,
new XRect(margin+5, margin+70, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{Customer.GetCustomerByID(list.owner_id).sender_address}", font, XBrushes.Black,
new XRect(margin+75, margin+70, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Anzahl: ", font, XBrushes.Black,
new XRect(margin+5, margin+85, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{result.Item5}", font, XBrushes.Black,
new XRect(margin+75, margin+85, width-margin, 25), XStringFormats.CenterLeft);
// logofclient ad var fontLabel = new XFont("Arial", 6, XFontStyleEx.Bold);
gfx.DrawString($"powered by logofclient", font, XBrushes.Black, var fontText = new XFont("Arial", 6, XFontStyleEx.Regular);
new XRect(margin+5, height-55, width-margin, 25), XStringFormats.CenterLeft); var fontBig = new XFont("Arial", 30, XFontStyleEx.Bold);
gfx.DrawString($"(c) 2026 MyPapertown", font, XBrushes.Black,
new XRect(margin+5, height-40, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"mypapercloud.de/logof", font, XBrushes.Black,
new XRect(margin+5, height-25, width-margin, 25), XStringFormats.CenterLeft);
int firstIndex = pageIndex * 2;
DrawGermanyRunningSheet(
gfx,
marginX,
top1,
usableW,
tableH,
list,
grouped_nums[firstIndex],
grouped_nums,
fontLabel,
fontText,
fontBig
);
if (firstIndex + 1 < grouped_nums.Count)
{
DrawGermanyRunningSheet(
gfx,
marginX,
top2,
usableW,
tableH,
list,
grouped_nums[firstIndex + 1],
grouped_nums,
fontLabel,
fontText,
fontBig
);
}
}
document.Save(path);
}
private void DrawGermanyRunningSheet(
XGraphics gfx,
double x,
double y,
double w,
double h,
KasAddressList list,
dynamic result,
List<(int,string,string,string,int)> grouped_nums,
XFont fontLabel,
XFont fontText,
XFont fontBig)
{
double line = 1.0;
string sender = Customer.GetCustomerByID(list.owner_id)?.sender_address ?? "[Absender]";
string customerName = Customer.GetCustomerByID(list.owner_id)?.name ?? "[Kunde]";
string start = result.Item3?.ToString() ?? "[Start]";
string end = result.Item4?.ToString() ?? "[Ende]";
string amount = result.Item5?.ToString() ?? "[Anzahl]";
string groupNo = result.Item2?.ToString() ?? "[PLZ]";
string fraction = result.Item1?.ToString() ?? "[Fraktion]";
int total_frac = 0; int total_frac = 0;
foreach (var item in grouped_nums) foreach (var item in grouped_nums)
@@ -483,15 +617,495 @@ public class PdfBuilder
if (item.Item2 == result.Item2) total_frac++; if (item.Item2 == result.Item2) total_frac++;
} }
// group number // Outer border
gfx.DrawString($"{result.Item2}", bigboldfont, XBrushes.Black, gfx.DrawRectangle(XPens.Black, x, y, w, h);
new XRect(margin, margin, width-margin, (height-margin)/2), XStringFormats.Center);
gfx.DrawString($"Fraktion {result.Item1}/{total_frac}", font, XBrushes.Black, // Row heights
new XRect(margin, margin, width-margin, (height-margin)/2 + 50), XStringFormats.Center); double r1 = h * 0.1;
double r2 = h * 0.1;
double r3 = h * 0.54;
double r4 = h * 0.30;
// Main horizontal lines
gfx.DrawLine(XPens.Black, x, y + r1, x + w, y + r1);
gfx.DrawLine(XPens.Black, x, y + r1 + r2, x + w, y + r1 + r2);
gfx.DrawLine(XPens.Black, x, y + r1 + r2 + r3, x + w, y + r1 + r2 + r3);
// Top row columns
double c1 = w * 0.39;
double c2 = w * 0.20;
double c3 = w * 0.26;
double c4 = w * 0.15;
gfx.DrawLine(XPens.Black, x + c1, y, x + c1, y + r1);
gfx.DrawLine(XPens.Black, x + c1 + c2, y, x + c1 + c2, y + r1);
gfx.DrawLine(XPens.Black, x + c1 + c2 + c3, y, x + c1 + c2 + c3, y + r1);
// Second row columns
gfx.DrawLine(XPens.Black, x + c1, y + r1, x + c1, y + r1 + r2);
gfx.DrawLine(XPens.Black, x + c1 + c2, y + r1, x + c1 + c2, y + r1 + r2);
gfx.DrawLine(XPens.Black, x + c1 + c2 + c3, y + r1, x + c1 + c2 + c3, y + r1 + r2);
// Middle large area split
double midSplit = x + w * 0.55;
gfx.DrawLine(XPens.Black, midSplit, y + r1 + r2, midSplit, y + r1 + r2 + r3);
// Bottom section split
double leftBottomW = w * 0.42;
gfx.DrawLine(XPens.Black, x + leftBottomW, y + r1 + r2 + r3, x + leftBottomW, y + h);
// Bottom left rows
double blY1 = y + r1 + r2 + r3 + (r4 * 0.14);
double blY2 = y + r1 + r2 + r3 + (r4 * 0.28);
double blY3 = y + r1 + r2 + r3 + (r4 * 0.42);
double blY4 = y + r1 + r2 + r3 + (r4 * 0.56);
double blY5 = y + r1 + r2 + r3 + (r4 * 0.70);
gfx.DrawLine(XPens.Black, x, blY1, x + leftBottomW, blY1);
gfx.DrawLine(XPens.Black, x, blY2, x + leftBottomW, blY2);
gfx.DrawLine(XPens.Black, x, blY3, x + leftBottomW, blY3);
gfx.DrawLine(XPens.Black, x, blY4, x + leftBottomW, blY4);
gfx.DrawLine(XPens.Black, x, blY5, x + leftBottomW, blY5);
// Labels top row
gfx.DrawString("Absender:", fontLabel, XBrushes.Black, new XRect(x + 5, y + 4, c1 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Kunden-Nr. Absender:", fontLabel, XBrushes.Black, new XRect(x + c1 + 5, y + 4, c2 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("ZKZ/Titel:", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + 4, c3 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Anzahl Sendungen:", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + 4, c4 - 10, 14), XStringFormats.TopLeft);
// Values top row
gfx.DrawString(sender, fontText, XBrushes.Black, new XRect(x + 5, y + 20, c1 - 10, r1 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Kunden-Nr. Absender]", fontText, XBrushes.Black, new XRect(x + c1 + 5, y + 20, c2 - 10, r1 - 22), XStringFormats.TopLeft);
gfx.DrawString("[ZKZ/Titel]", fontText, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + 20, c3 - 10, r1 - 22), XStringFormats.TopLeft);
gfx.DrawString(amount, fontText, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + 20, c4 - 10, r1 - 22), XStringFormats.TopLeft);
// Second row labels
gfx.DrawString("Einlieferer:", fontLabel, XBrushes.Black, new XRect(x + 5, y + r1 + 4, c1 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Kunden-Nr. Einlieferer:", fontLabel, XBrushes.Black, new XRect(x + c1 + 5, y + r1 + 4, c2 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Interne Vermerke:", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + r1 + 4, c3 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Laufzeit", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + r1 + 4, c4 - 10, 14), XStringFormats.TopLeft);
// Second row values
gfx.DrawString(customerName, fontText, XBrushes.Black, new XRect(x + 5, y + r1 + 20, c1 - 10, r2 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Kunden-Nr. Einlieferer]", fontText, XBrushes.Black, new XRect(x + c1 + 5, y + r1 + 20, c2 - 10, r2 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Interne Vermerke]", fontText, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + r1 + 20, c3 - 10, r2 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Laufzeit]", fontText, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + r1 + 20, c4 - 10, r2 - 22), XStringFormats.TopLeft);
// Middle area
gfx.DrawString(groupNo, fontBig, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + 5, w * 0.50 - 10, r3 - 10),
XStringFormats.Center);
gfx.DrawString("PRESSE/ELN", fontBig, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + 5, w * 0.50 - 10, r3 - 90),
XStringFormats.Center);
gfx.DrawString($"Fraktion {fraction}/{total_frac}", fontText, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + r3 - 18, w * 0.50 - 10, 14),
XStringFormats.CenterLeft);
gfx.DrawString("Bereich für postalische Zwecke:", fontLabel, XBrushes.Black,
new XRect(midSplit + 5, y + r1 + r2 + 4, w - (midSplit - x) - 10, 14),
XStringFormats.TopLeft);
// Bottom left labels
// Bottom left labels
gfx.DrawString("Einlieferungsdatum:", fontLabel, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + r3 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("AM-Auftragsnummer:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY1 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Bundgewicht:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY2 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Paletten-Nr.:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY3 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Bund-Nr./Bunde auf Palette:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY4 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Bund-Nr. von Gesamtanzahl:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY5 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
// Bottom placeholders rechts daneben, gleiche Zeile
double valueX = x + leftBottomW * 0.55;
double valueW = leftBottomW - (valueX - x) - 5;
gfx.DrawString("[Einlieferungsdatum]", fontText, XBrushes.Black,
new XRect(valueX, y + r1 + r2 + r3 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[AM-Auftragsnummer]", fontText, XBrushes.Black,
new XRect(valueX, blY1 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Bundgewicht]", fontText, XBrushes.Black,
new XRect(valueX, blY2 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Paletten-Nr.]", fontText, XBrushes.Black,
new XRect(valueX, blY3 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Bund-Nr./Bunde auf Palette]", fontText, XBrushes.Black,
new XRect(valueX, blY4 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Bund-Nr. von Gesamtanzahl]", fontText, XBrushes.Black,
new XRect(valueX, blY5 + 4, valueW, 14),
XStringFormats.TopRight);
// Right bottom postal area label
gfx.DrawString("Feld für Palettenlabel/NVE:", fontLabel, XBrushes.Black,
new XRect(x + leftBottomW + 5, y + r1 + r2 + r3 + 4, w - leftBottomW - 10, 14),
XStringFormats.TopLeft);
}
// public void CreateInternationalRunningSheets(int setID, string path)
// {
// KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID);
// var document = new PdfDocument();
// document.Info.Title = $"Laufzettel für {list.Name}";
// document.Info.Subject = "powered by logofclient";
// document.Info.Author = "logofclient";
//
// int margin = 50;
//
// var grouped_nums = GroupAddressesInternational(setID);
//
// foreach (var result in grouped_nums)
// {
// var page = document.AddPage();
// page.Size = PageSize.A4;
//
// var gfx = XGraphics.FromPdfPage(page);
//
// var width = page.Width.Point-margin;
// var height = page.Height.Point-margin;
// gfx.DrawLine(XPens.Black, margin, margin, margin, height);
// gfx.DrawLine(XPens.Black, margin, margin, width, margin);
// gfx.DrawLine(XPens.Black, width, margin, width, height);
// gfx.DrawLine(XPens.Black, margin, height, width, height);
//
// var boldfont = new XFont("Cantarell", 11, XFontStyleEx.Bold);
// var font = new XFont("Cantarell", 11, XFontStyleEx.Regular);
// var bigboldfont = new XFont("Cantarell", 35, XFontStyleEx.Bold);
//
// // Versandinfo
// gfx.DrawString($"Versand {list.Name}", boldfont, XBrushes.Black,
// new XRect(margin+5, margin, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"Start: ", font, XBrushes.Black,
// new XRect(margin+5, margin+25, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"{result.Item3}", font, XBrushes.Black,
// new XRect(margin+75, margin+25, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"Ende: ", font, XBrushes.Black,
// new XRect(margin+5, margin+40, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"{result.Item4}", font, XBrushes.Black,
// new XRect(margin+75, margin+40, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"Kunde: ", font, XBrushes.Black,
// new XRect(margin+5, margin+55, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"{Customer.GetCustomerByID(list.owner_id).name}", font, XBrushes.Black,
// new XRect(margin+75, margin+55, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"Absender: ", font, XBrushes.Black,
// new XRect(margin+5, margin+70, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"{Customer.GetCustomerByID(list.owner_id).sender_address}", font, XBrushes.Black,
// new XRect(margin+75, margin+70, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"Anzahl: ", font, XBrushes.Black,
// new XRect(margin+5, margin+85, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"{result.Item5}", font, XBrushes.Black,
// new XRect(margin+75, margin+85, width-margin, 25), XStringFormats.CenterLeft);
//
// // logofclient ad
// gfx.DrawString($"powered by logofclient", font, XBrushes.Black,
// new XRect(margin+5, height-55, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"(c) 2026 MyPapertown", font, XBrushes.Black,
// new XRect(margin+5, height-40, width-margin, 25), XStringFormats.CenterLeft);
// gfx.DrawString($"mypapercloud.de/logof", font, XBrushes.Black,
// new XRect(margin+5, height-25, width-margin, 25), XStringFormats.CenterLeft);
//
//
// int total_frac = 0;
// foreach (var item in grouped_nums)
// {
// if (item.Item2 == result.Item2) total_frac++;
// }
//
// // group number
// gfx.DrawString($"{result.Item2}", bigboldfont, XBrushes.Black,
// new XRect(margin, margin, width-margin, (height-margin)/2), XStringFormats.Center);
// gfx.DrawString($"Fraktion {result.Item1}/{total_frac}", font, XBrushes.Black,
// new XRect(margin, margin, width-margin, (height-margin)/2 + 50), XStringFormats.Center);
// }
//
// if (document.PageCount > 0)
// {
// document.Save(path);
// }
//
// }
public void CreateInternationalRunningSheets(int setID, string path)
{
KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID);
var document = new PdfDocument();
document.Info.Title = $"Laufzettel für {list.Name}";
document.Info.Subject = "powered by logofclient";
document.Info.Author = "logofclient";
var grouped_nums = GroupAddressesInternational(setID).ToList();
int sheets = (grouped_nums.Count + 1) / 2;
double marginX = 20;
double marginY = 20;
double gapY = 12;
for (int pageIndex = 0; pageIndex < sheets; pageIndex++)
{
var page = document.AddPage();
page.Size = PageSize.A4;
var gfx = XGraphics.FromPdfPage(page);
double pageW = page.Width.Point;
double pageH = page.Height.Point;
double usableW = pageW - 2 * marginX;
double usableH = pageH - 2 * marginY;
double tableH = (usableH - gapY) / 2.0;
double top1 = marginY;
double top2 = marginY + tableH + gapY;
var fontLabel = new XFont("Arial", 6, XFontStyleEx.Bold);
var fontText = new XFont("Arial", 6, XFontStyleEx.Regular);
var fontBig = new XFont("Arial", 30, XFontStyleEx.Bold);
int firstIndex = pageIndex * 2;
DrawInternationalRunningSheet(
gfx,
marginX,
top1,
usableW,
tableH,
list,
grouped_nums[firstIndex],
grouped_nums,
fontLabel,
fontText,
fontBig
);
if (firstIndex + 1 < grouped_nums.Count)
{
DrawInternationalRunningSheet(
gfx,
marginX,
top2,
usableW,
tableH,
list,
grouped_nums[firstIndex + 1],
grouped_nums,
fontLabel,
fontText,
fontBig
);
}
} }
document.Save(path); document.Save(path);
} }
private void DrawInternationalRunningSheet(
XGraphics gfx,
double x,
double y,
double w,
double h,
KasAddressList list,
dynamic result,
List<(int,string,string,string,int)> grouped_nums,
XFont fontLabel,
XFont fontText,
XFont fontBig)
{
double line = 1.0;
string sender = Customer.GetCustomerByID(list.owner_id)?.sender_address ?? "[Absender]";
string customerName = Customer.GetCustomerByID(list.owner_id)?.name ?? "[Kunde]";
string start = result.Item3?.ToString() ?? "[Start]";
string end = result.Item4?.ToString() ?? "[Ende]";
string amount = result.Item5?.ToString() ?? "[Anzahl]";
string groupNo = result.Item2?.ToString() ?? "[PLZ]";
string fraction = result.Item1?.ToString() ?? "[Fraktion]";
int total_frac = 0;
foreach (var item in grouped_nums)
{
if (item.Item2 == result.Item2) total_frac++;
}
// Outer border
gfx.DrawRectangle(XPens.Black, x, y, w, h);
// Row heights
double r1 = h * 0.1;
double r2 = h * 0.1;
double r3 = h * 0.54;
double r4 = h * 0.30;
// Main horizontal lines
gfx.DrawLine(XPens.Black, x, y + r1, x + w, y + r1);
gfx.DrawLine(XPens.Black, x, y + r1 + r2, x + w, y + r1 + r2);
gfx.DrawLine(XPens.Black, x, y + r1 + r2 + r3, x + w, y + r1 + r2 + r3);
// Top row columns
double c1 = w * 0.39;
double c2 = w * 0.20;
double c3 = w * 0.26;
double c4 = w * 0.15;
gfx.DrawLine(XPens.Black, x + c1, y, x + c1, y + r1);
gfx.DrawLine(XPens.Black, x + c1 + c2, y, x + c1 + c2, y + r1);
gfx.DrawLine(XPens.Black, x + c1 + c2 + c3, y, x + c1 + c2 + c3, y + r1);
// Second row columns
gfx.DrawLine(XPens.Black, x + c1, y + r1, x + c1, y + r1 + r2);
gfx.DrawLine(XPens.Black, x + c1 + c2, y + r1, x + c1 + c2, y + r1 + r2);
gfx.DrawLine(XPens.Black, x + c1 + c2 + c3, y + r1, x + c1 + c2 + c3, y + r1 + r2);
// Middle large area split
double midSplit = x + w * 0.55;
gfx.DrawLine(XPens.Black, midSplit, y + r1 + r2, midSplit, y + r1 + r2 + r3);
// Bottom section split
double leftBottomW = w * 0.42;
gfx.DrawLine(XPens.Black, x + leftBottomW, y + r1 + r2 + r3, x + leftBottomW, y + h);
// Bottom left rows
double blY1 = y + r1 + r2 + r3 + (r4 * 0.14);
double blY2 = y + r1 + r2 + r3 + (r4 * 0.28);
double blY3 = y + r1 + r2 + r3 + (r4 * 0.42);
double blY4 = y + r1 + r2 + r3 + (r4 * 0.56);
double blY5 = y + r1 + r2 + r3 + (r4 * 0.70);
gfx.DrawLine(XPens.Black, x, blY1, x + leftBottomW, blY1);
gfx.DrawLine(XPens.Black, x, blY2, x + leftBottomW, blY2);
gfx.DrawLine(XPens.Black, x, blY3, x + leftBottomW, blY3);
gfx.DrawLine(XPens.Black, x, blY4, x + leftBottomW, blY4);
gfx.DrawLine(XPens.Black, x, blY5, x + leftBottomW, blY5);
// Labels top row
gfx.DrawString("Absender:", fontLabel, XBrushes.Black, new XRect(x + 5, y + 4, c1 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Kunden-Nr. Absender:", fontLabel, XBrushes.Black, new XRect(x + c1 + 5, y + 4, c2 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("ZKZ/Titel:", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + 4, c3 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Anzahl Sendungen:", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + 4, c4 - 10, 14), XStringFormats.TopLeft);
// Values top row
gfx.DrawString(sender, fontText, XBrushes.Black, new XRect(x + 5, y + 20, c1 - 10, r1 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Kunden-Nr. Absender]", fontText, XBrushes.Black, new XRect(x + c1 + 5, y + 20, c2 - 10, r1 - 22), XStringFormats.TopLeft);
gfx.DrawString("[ZKZ/Titel]", fontText, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + 20, c3 - 10, r1 - 22), XStringFormats.TopLeft);
gfx.DrawString(amount, fontText, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + 20, c4 - 10, r1 - 22), XStringFormats.TopLeft);
// Second row labels
gfx.DrawString("Einlieferer:", fontLabel, XBrushes.Black, new XRect(x + 5, y + r1 + 4, c1 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Kunden-Nr. Einlieferer:", fontLabel, XBrushes.Black, new XRect(x + c1 + 5, y + r1 + 4, c2 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Interne Vermerke:", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + r1 + 4, c3 - 10, 14), XStringFormats.TopLeft);
gfx.DrawString("Laufzeit", fontLabel, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + r1 + 4, c4 - 10, 14), XStringFormats.TopLeft);
// Second row values
gfx.DrawString(customerName, fontText, XBrushes.Black, new XRect(x + 5, y + r1 + 20, c1 - 10, r2 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Kunden-Nr. Einlieferer]", fontText, XBrushes.Black, new XRect(x + c1 + 5, y + r1 + 20, c2 - 10, r2 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Interne Vermerke]", fontText, XBrushes.Black, new XRect(x + c1 + c2 + 5, y + r1 + 20, c3 - 10, r2 - 22), XStringFormats.TopLeft);
gfx.DrawString("[Laufzeit]", fontText, XBrushes.Black, new XRect(x + c1 + c2 + c3 + 5, y + r1 + 20, c4 - 10, r2 - 22), XStringFormats.TopLeft);
// Middle area
gfx.DrawString(groupNo, fontBig, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + 5, w * 0.50 - 10, r3 - 10),
XStringFormats.Center);
gfx.DrawString("PRESSE/ELN", fontBig, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + 5, w * 0.50 - 10, r3 - 90),
XStringFormats.Center);
gfx.DrawString($"Fraktion {fraction}/{total_frac}", fontText, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + r3 - 18, w * 0.50 - 10, 14),
XStringFormats.CenterLeft);
gfx.DrawString("Bereich für postalische Zwecke:", fontLabel, XBrushes.Black,
new XRect(midSplit + 5, y + r1 + r2 + 4, w - (midSplit - x) - 10, 14),
XStringFormats.TopLeft);
// Bottom left labels
// Bottom left labels
gfx.DrawString("Einlieferungsdatum:", fontLabel, XBrushes.Black,
new XRect(x + 5, y + r1 + r2 + r3 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("AM-Auftragsnummer:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY1 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Bundgewicht:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY2 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Paletten-Nr.:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY3 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Bund-Nr./Bunde auf Palette:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY4 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
gfx.DrawString("Bund-Nr. von Gesamtanzahl:", fontLabel, XBrushes.Black,
new XRect(x + 5, blY5 + 4, leftBottomW - 10, 14),
XStringFormats.TopLeft);
// Bottom placeholders rechts daneben, gleiche Zeile
double valueX = x + leftBottomW * 0.55;
double valueW = leftBottomW - (valueX - x) - 5;
gfx.DrawString("[Einlieferungsdatum]", fontText, XBrushes.Black,
new XRect(valueX, y + r1 + r2 + r3 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[AM-Auftragsnummer]", fontText, XBrushes.Black,
new XRect(valueX, blY1 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Bundgewicht]", fontText, XBrushes.Black,
new XRect(valueX, blY2 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Paletten-Nr.]", fontText, XBrushes.Black,
new XRect(valueX, blY3 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Bund-Nr./Bunde auf Palette]", fontText, XBrushes.Black,
new XRect(valueX, blY4 + 4, valueW, 14),
XStringFormats.TopRight);
gfx.DrawString("[Bund-Nr. von Gesamtanzahl]", fontText, XBrushes.Black,
new XRect(valueX, blY5 + 4, valueW, 14),
XStringFormats.TopRight);
// Right bottom postal area label
gfx.DrawString("Feld für Palettenlabel/NVE:", fontLabel, XBrushes.Black,
new XRect(x + leftBottomW + 5, y + r1 + r2 + r3 + 4, w - leftBottomW - 10, 14),
XStringFormats.TopLeft);
}
/// <summary> /// <summary>
/// Calculates address groups to summarize for the single pages of the running sheets. /// Calculates address groups to summarize for the single pages of the running sheets.
@@ -510,7 +1124,7 @@ public class PdfBuilder
List<IGrouping<string, KasPerson>> sorted_list = list.KasPersons List<IGrouping<string, KasPerson>> sorted_list = list.KasPersons
.Where(x => !string.IsNullOrEmpty(x?.used_plz) && .Where(x => !string.IsNullOrEmpty(x?.used_plz) &&
x.used_plz.Length >= stpoint) x.used_plz.Length >= stpoint && x.IsGermany())
.OrderBy(x => x.used_plz) .OrderBy(x => x.used_plz)
.GroupBy(x => x.used_plz.Substring(0, stpoint)) .GroupBy(x => x.used_plz.Substring(0, stpoint))
.ToList(); .ToList();
@@ -535,4 +1149,40 @@ public class PdfBuilder
return output; return output;
} }
public List<(int, string, string, string, int)> GroupAddressesInternational(int setID)
{
int grpcount = Settings._instance.pdfExport.rsNumGrouped; // Amount of addresses per group
KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID);
if (list == null)
throw new Exception("AddressSet nicht gefunden");
List<(int, string, string, string, int)> output = new();
List<IGrouping<string, KasPerson>> sorted_list = list.KasPersons
.Where(x => !string.IsNullOrEmpty(x?.used_plz) && !x.IsGermany())
.OrderBy(x => x.used_plz)
.GroupBy(x => x.land)
.ToList();
foreach (var group in sorted_list)
{
string start = group.Key;
int fraktion = 0;
for (int count = 0; count < group.Count(); count += grpcount)
{
fraktion++;
int currentGroupSize = Math.Min(grpcount, group.Count() - count);
string first = group.ElementAt(count).used_plz;
string last = group.ElementAt(count + currentGroupSize - 1).used_plz;
output.Add((fraktion, start, first, last, currentGroupSize));
}
}
return output;
}
} }
+29 -2
View File
@@ -62,13 +62,15 @@ public class StableFontResolver : IFontResolver
} }
} }
} }
catch catch (Exception ex)
{ {
// ignore resolver init errors Logger.Log($"Error while initializing FontResolver: {ex.Message}",Logger.LogType.Error);
} }
} }
private static string NormalizeStyle(string s) private static string NormalizeStyle(string s)
{
try
{ {
if (string.IsNullOrEmpty(s)) return "Regular"; if (string.IsNullOrEmpty(s)) return "Regular";
s = s.ToLowerInvariant(); s = s.ToLowerInvariant();
@@ -78,8 +80,17 @@ public class StableFontResolver : IFontResolver
if (s.Contains("regular") || s == "r") return "Regular"; if (s.Contains("regular") || s == "r") return "Regular";
return CultureInfo.InvariantCulture.TextInfo.ToTitleCase(s); return CultureInfo.InvariantCulture.TextInfo.ToTitleCase(s);
} }
catch (Exception ex)
{
Logger.Log($"Error while normalizing style: {ex.Message}",Logger.LogType.Error);
}
return null;
}
public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic) public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
{
try
{ {
// If requested family exists, pick corresponding style if available // If requested family exists, pick corresponding style if available
string familyToUse = null; string familyToUse = null;
@@ -100,8 +111,17 @@ public class StableFontResolver : IFontResolver
// Face name format: Family#Style // Face name format: Family#Style
return new FontResolverInfo($"{familyToUse}#{style}"); return new FontResolverInfo($"{familyToUse}#{style}");
} }
catch (Exception ex)
{
Logger.Log($"Error while resolving typeface: {ex.Message}",Logger.LogType.Error);
}
return null;
}
public byte[] GetFont(string faceName) public byte[] GetFont(string faceName)
{
try
{ {
if (string.IsNullOrEmpty(faceName)) return null; if (string.IsNullOrEmpty(faceName)) return null;
@@ -133,4 +153,11 @@ public class StableFontResolver : IFontResolver
return null; return null;
} }
catch (Exception ex)
{
Logger.Log($"Error while getting font: {ex.Message}",Logger.LogType.Error);
}
return [];
}
} }
+12 -6
View File
@@ -10,20 +10,24 @@ public partial class EditorWindow : Window
public string filename = ""; public string filename = "";
public EditorWindow(string filename = "") public EditorWindow(string filename = "")
{
try
{ {
InitializeComponent(); InitializeComponent();
this.filename = filename; this.filename = PathUtilities.NormalizeFileSystemPath(filename);
if (!string.IsNullOrWhiteSpace(filename) && File.Exists(filename)) if (!string.IsNullOrWhiteSpace(this.filename) && File.Exists(this.filename))
{ {
var content = TbContent; var content = TbContent;
if (content != null) content.Text = File.ReadAllText(this.filename); if (content != null) content.Text = File.ReadAllText(this.filename);
Title = "Wiki Editor - " + filename; Title = "Wiki Editor - " + filename;
} }
else if (!string.IsNullOrWhiteSpace(filename)) else if (!string.IsNullOrWhiteSpace(this.filename))
{ {
MessageBox.Show(null, "Die Datei existiert nicht", "Fehler"); MessageBox.Show(null, "Die Datei existiert nicht", "Fehler");
Close(); Close();
} }
} catch (Exception ex) { Logger.Log($"Error while : {ex.Message}",Logger.LogType.Error);}
} }
private void BtnSave_OnClick(object? sender, RoutedEventArgs e) private void BtnSave_OnClick(object? sender, RoutedEventArgs e)
@@ -31,20 +35,22 @@ public partial class EditorWindow : Window
try try
{ {
File.WriteAllText(filename, TbContent.Text); File.WriteAllText(filename, TbContent.Text);
MainWindow._instance.PopulateNavTree(); MainWindow._instance.PopulateNavTree(filename, filename);
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(null, MessageBox.Show(null,
"Es ist ein Fehler aufgetreten. Bitte senden Sie ihn über git.mypapercloud.de/fierke/logofclient ein:\n" + "Es ist ein Fehler aufgetreten. Bitte senden Sie ihn über git.mypapercloud.de/fierke/logofclient ein:\n" +
ex.StackTrace, "Fehler"); ex.StackTrace, "Fehler");
Logger.Log($"Error while : {ex.Message}",Logger.LogType.Error);
} }
} }
private void BtnSaveAs_OnClick(object? sender, RoutedEventArgs e) private void BtnSaveAs_OnClick(object? sender, RoutedEventArgs e)
{ {
MessageBox.Show(null, MessageBox.Show(null,
"Feature noch nicht implemetiert.\nErstelle neue Dateien unter " + Global._instance.wiki_storage_path, "Feature noch nicht implemetiert.\nErstelle neue Dateien unter " +
PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path),
"Fehler"); "Fehler");
} }
@@ -55,7 +61,7 @@ public partial class EditorWindow : Window
try try
{ {
File.Delete(filename); File.Delete(filename);
} catch {} } catch (Exception ex) { Logger.Log($"Error while : {ex.Message}",Logger.LogType.Error);}
MainWindow._instance.PopulateNavTree(); MainWindow._instance.PopulateNavTree();
Close(); Close();
+127 -116
View File
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media; using Avalonia.Media;
@@ -10,120 +11,130 @@ namespace Logof_Client.Wiki;
public static class MarkdownRenderer public static class MarkdownRenderer
{ {
public static Control Render(string markdown) // public static Control Render(string markdown)
{ // {
var panel = new StackPanel { Spacing = 6 }; // try
if (string.IsNullOrWhiteSpace(markdown)) return panel; // {
// var panel = new StackPanel { Spacing = 6 };
var doc = Markdown.Parse(markdown); // if (string.IsNullOrWhiteSpace(markdown)) return panel;
//
foreach (var block in doc) // var doc = Markdown.Parse(markdown);
{ //
switch (block) // foreach (var block in doc)
{ // {
case HeadingBlock hb: // switch (block)
{ // {
var text = GetInlineText(hb.Inline); // case HeadingBlock hb:
var tb = new TextBlock // {
{ // var text = GetInlineText(hb.Inline);
Text = text, // var tb = new TextBlock
FontWeight = FontWeight.Bold, // {
Margin = new Avalonia.Thickness(0, hb.Level == 1 ? 6 : 2, 0, 2) // Text = text,
}; // FontWeight = FontWeight.Bold,
tb.FontSize = hb.Level switch { 1 => 22, 2 => 18, 3 => 16, _ => 14 }; // Margin = new Avalonia.Thickness(0, hb.Level == 1 ? 6 : 2, 0, 2)
panel.Children.Add(tb); // };
break; // tb.FontSize = hb.Level switch { 1 => 22, 2 => 18, 3 => 16, _ => 14 };
} // panel.Children.Add(tb);
// break;
case ParagraphBlock pb: // }
{ //
var text = GetInlineText(pb.Inline); // case ParagraphBlock pb:
var tb = new TextBlock { Text = text, TextWrapping = Avalonia.Media.TextWrapping.Wrap }; // {
panel.Children.Add(tb); // var text = GetInlineText(pb.Inline);
break; // var tb = new TextBlock { Text = text, TextWrapping = Avalonia.Media.TextWrapping.Wrap };
} // panel.Children.Add(tb);
// break;
case FencedCodeBlock cb: // }
{ //
var sb = new StringBuilder(); // case FencedCodeBlock cb:
foreach (var line in cb.Lines.Lines) // {
{ // var sb = new StringBuilder();
sb.Append(line.ToString()); // foreach (var line in cb.Lines.Lines)
} // {
var codeBox = new TextBox // sb.Append(line.ToString());
{ // }
Text = sb.ToString(), // var codeBox = new TextBox
FontFamily = "Consolas, monospace", // {
IsReadOnly = true, // Text = sb.ToString(),
AcceptsReturn = true // FontFamily = "Consolas, monospace",
}; // IsReadOnly = true,
panel.Children.Add(codeBox); // AcceptsReturn = true
break; // };
} // panel.Children.Add(codeBox);
// break;
case ListBlock lb: // }
{ //
var sp = new StackPanel { Spacing = 2 }; // case ListBlock lb:
var number = 1; // {
foreach (var item in lb) // var sp = new StackPanel { Spacing = 2 };
{ // var number = 1;
if (item is ListItemBlock lib) // foreach (var item in lb)
{ // {
var itemText = new StringBuilder(); // if (item is ListItemBlock lib)
foreach (var sub in lib) // {
{ // var itemText = new StringBuilder();
if (sub is ParagraphBlock pp) // foreach (var sub in lib)
itemText.Append(GetInlineText(pp.Inline)); // {
} // if (sub is ParagraphBlock pp)
var tb = new TextBlock { Text = (lb.IsOrdered ? (number++ + ". ") : "• ") + itemText.ToString() }; // itemText.Append(GetInlineText(pp.Inline));
sp.Children.Add(tb); // }
} // var tb = new TextBlock { Text = (lb.IsOrdered ? (number++ + ". ") : "• ") + itemText.ToString() };
} // sp.Children.Add(tb);
panel.Children.Add(sp); // }
break; // }
} // panel.Children.Add(sp);
// break;
default: // }
{ //
// fallback: raw text // default:
panel.Children.Add(new TextBlock { Text = block.ToString() }); // {
break; // // fallback: raw text
} // panel.Children.Add(new TextBlock { Text = block.ToString() });
} // break;
} // }
// }
return panel; // }
} //
// return panel;
private static string GetInlineText(ContainerInline? container) // } catch (Exception ex) { Logger.Log($"Error while : {ex.Message}",Logger.LogType.Error);}
{ //
if (container == null) return string.Empty; // return new Panel();
var sb = new StringBuilder(); // }
foreach (var inline in container) //
{ // private static string GetInlineText(ContainerInline? container)
switch (inline) // {
{ // try
case LiteralInline li: // {
sb.Append(li.Content.ToString()); // if (container == null) return string.Empty;
break; // var sb = new StringBuilder();
case EmphasisInline ei: // foreach (var inline in container)
sb.Append(GetInlineText(ei)); // {
break; // switch (inline)
case CodeInline ci: // {
sb.Append(ci.Content); // case LiteralInline li:
break; // sb.Append(li.Content.ToString());
case LinkInline li: // break;
sb.Append(GetInlineText(li)); // case EmphasisInline ei:
break; // sb.Append(GetInlineText(ei));
case LineBreakInline: // break;
sb.Append("\n"); // case CodeInline ci:
break; // sb.Append(ci.Content);
default: // break;
sb.Append(inline.ToString()); // case LinkInline li:
break; // sb.Append(GetInlineText(li));
} // break;
} // case LineBreakInline:
// sb.Append("\n");
return sb.ToString(); // break;
} // default:
// sb.Append(inline.ToString());
// break;
// }
// }
//
// return sb.ToString();
// } catch (Exception ex) { Logger.Log($"Error while : {ex.Message}",Logger.LogType.Error);}
//
// return null;
// }
} }
+5 -2
View File
@@ -13,7 +13,7 @@ public class WikiService
// prefer global wiki storage path if configured // prefer global wiki storage path if configured
if (Global._instance != null && !string.IsNullOrWhiteSpace(Global._instance.wiki_storage_path)) if (Global._instance != null && !string.IsNullOrWhiteSpace(Global._instance.wiki_storage_path))
{ {
var cfg = Global._instance.wiki_storage_path; var cfg = PathUtilities.NormalizeFileSystemPath(Global._instance.wiki_storage_path);
WikiRootFullPath = Path.IsPathRooted(cfg) WikiRootFullPath = Path.IsPathRooted(cfg)
? cfg ? cfg
: Path.Combine(Directory.GetCurrentDirectory(), cfg); : Path.Combine(Directory.GetCurrentDirectory(), cfg);
@@ -25,8 +25,11 @@ public class WikiService
wikiRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), wikiRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient", "logofclient",
"wiki"); "wiki");
wikiRoot = PathUtilities.NormalizeFileSystemPath(wikiRoot);
WikiRoot = wikiRoot; WikiRoot = wikiRoot;
WikiRootFullPath = Path.Combine(Directory.GetCurrentDirectory(), wikiRoot); WikiRootFullPath = Path.IsPathRooted(wikiRoot)
? wikiRoot
: Path.Combine(Directory.GetCurrentDirectory(), wikiRoot);
} }
} }
-157
View File
@@ -1,157 +0,0 @@
\documentclass[a4paper]{article}
\usepackage{graphicx}
\usepackage[left=3cm,right=3cm,top=3cm, bottom=3cm]{geometry}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage[headsepline, footsepline]{scrlayer-scrpage}
\usepackage{enumerate}
\usepackage{dsfont}
\usepackage[]{mathtools}
\usepackage[]{mathbbol}
\usepackage{multicol}
\usepackage{enumitem}
\usepackage[hidelinks]{hyperref}
\usepackage[]{circuitikz}
\usepackage{tcolorbox} % Für schöne Boxen
\usetikzlibrary{circuits.logic.IEC}
\usepackage{tikz}
\usepackage{tkz-graph}
\usepackage{listings}
\usepackage{xcolor}
\setlist{itemsep=0.3em, topsep=0.5em, parsep=0pt}
\newcommand{\bpf}[1]{%
\par\vspace{0.8\baselineskip}% Abstand vor der Überschrift
\noindent\textbf{#1}% Fettgedruckte Überschrift
\par\vspace{0.3\baselineskip}% Abstand nach der Überschrift
}
\renewcommand{\contentsname}{Inhaltsverzeichnis}
\renewcommand{\figurename}{Grafik}
\renewcommand{\partname}{Teil}
\renewcommand{\epsilon}{\varepsilon}
\definecolor{darkgrey}{HTML}{232327}
% Zählerdefinition mit AUTOMATISCHEM SUBSECTION-RESET
\newcounter{commoncounter}[subsection]
\renewcommand{\thecommoncounter}{\thesubsection.\arabic{commoncounter}}
% Zähler direkt bei Dokumentstart initialisieren
\AtBeginDocument{\setcounter{commoncounter}{0}}
% BOX-DEFINITIONEN mit korrigierter Zählerlogik
\newtcolorbox{definitionbox}[1][]{
before title={\refstepcounter{commoncounter}}, % KRITISCH: vor dem Titel!
title={Definition \thecommoncounter: #1},
colback=white,
colframe=white!75!darkgrey,
fonttitle=\bfseries,
boxrule=0.6mm,
coltitle=black,
rounded corners,
before skip=10pt,
after skip=10pt
}
\newtcolorbox{examplebox}[1][]{
before title={\refstepcounter{commoncounter}}, % KRITISCH: vor dem Titel!
title={Beispiel \thecommoncounter: #1},
colback=white,
colframe=white!75!orange,
fonttitle=\bfseries,
boxrule=0.6mm,
coltitle=black,
rounded corners,
before skip=10pt,
after skip=10pt
}
\newtcolorbox{satzbox}[1][]{
before title={\refstepcounter{commoncounter}}, % KRITISCH: vor dem Titel!
title={Satz \thecommoncounter: #1},
colback=white,
colframe=white!75!blue,
fonttitle=\bfseries,
boxrule=0.6mm,
coltitle=black,
rounded corners,
before skip=10pt,
after skip=10pt
}
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codeblue}{rgb}{0,0,0.8}
\definecolor{codered}{rgb}{0.8,0,0}
\definecolor{lightgray}{rgb}{0.95,0.95,0.95}
\lstdefinestyle{CSharpStyle}{
language=Python,
basicstyle=\ttfamily\small, % Monospace-Schrift
keywordstyle=\color{blue}\bfseries, % Schlüsselwörter fett und blau
stringstyle=\color{red}, % Strings rot
commentstyle=\color{codegreen}, % Kommentare grün
backgroundcolor=\color{lightgray}, % Hintergrundfarbe
numbers=left, % Zeilennummern links
numbersep=10px, % Abstand zwischen Zeilennummern und Code
numberstyle=\color{gray}\texttt,
stepnumber=1, % Zeilennummerierung Schrittweite 1
frame=single, % Rahmen um den Code
tabsize=4, % Tabulatorgröße
breaklines=true, % Zeilenumbruch aktivieren
captionpos=none,
showstringspaces=false,
xleftmargin=15pt, % Linker Rand für den Code (verschiebt alles nach rechts)
}
% Umgebung für Listings mit Titel und Zähler
\newenvironment{codeexample}[1][]{
\refstepcounter{commoncounter} % Zähler erhöhen
\lstset{
style=CSharpStyle,
caption={Listing \thecommoncounter: #1}, % Titel mit Zähler
label={listing:\thecommoncounter}
}
}{}
\setlength{\parindent}{0pt}
\title{\includegraphics[width=0.3\textwidth]{../assets/icon.png}\vspace{15pt}\\Logof Client\\
Handbuch}
\author{Elias Fierke}
\pagestyle{scrheadings}
\date{Oktober 2025}
\begin{document}
\ohead{Oktober 2025}
\ofoot{Seite {\pagemark} von \pageref{LastPage}}
\ihead{Logof Client Handbuch}
\maketitle
\tableofcontents
\newpage
\part{Einführung}
\newpage
\part{Installation}
\newpage
\part{Adress-Verwaltung}
\label{LastPage}
\end{document}