19 Commits

Author SHA1 Message Date
fierke df6c187a00 [chore:] combining export margin options gui with settings and PdfBuilder.cs 2026-04-23 12:30:35 +02:00
fierke 98b5198f6f [chore:] added smallFontSize and fixed usage of fontSize and smallFontSize 2026-04-23 09:03:25 +02:00
fierke 1a6459d60b [chore:] grid visibility (calc man :D) 2026-04-23 09:03:00 +02:00
fierke 43e6c35beb [gui:] export margin options gui 2026-04-23 09:02:45 +02:00
fierke 9777c6b5a2 [fix:] naming window showed nothing 2026-04-22 08:09:28 +02:00
fierke 9ad378c800 [fix:] temporarily fiex application crash if no customer is selected when start combining (more than union, which was fixed before) 2026-04-16 13:29:59 +02:00
fierke 5ccd4a4e99 [fix:] csv-import now recognizes quotation marks 2026-04-16 12:49:45 +02:00
fierke ac7b23cc28 [fix:] temporarily fixed application crash if no customer is seleceted when starting 2026-04-16 12:49:10 +02:00
fierke 16ed64dbf4 [chore:] there was a space missing that triggered my monk 2026-04-16 11:44:10 +02:00
fierke cc48c0ae2c [chore:] separator option (it's better like that :D) 2026-03-19 14:39:54 +01:00
fierke ba640c602a [file:] better folder structuring 2026-03-19 14:34:36 +01:00
fierke e8738a2eab [fix:] now, they get unique id's when importing 2026-03-19 14:20:59 +01:00
Elias Fierke afbb4626a0 [feat:] implemented renaming functionality 2026-01-19 16:25:33 +01:00
Elias Fierke ee83aca490 [feat:] included context menu for Address-SetListBox 2026-01-19 16:25:20 +01:00
Elias Fierke b40ddfbf2e [fix:] NamingWindow.axaml had a wrong size 2026-01-19 16:17:06 +01:00
Elias Fierke 5172de332c [feat:] added "new file" button for wiki and therefore
implemented the usage of NamingWindow
2026-01-18 16:15:25 +01:00
Elias Fierke d478fd5129 [feat:] simple MessageBox-lik naming window 2026-01-18 16:14:37 +01:00
Elias Fierke 5dcb44aa2a [fix:] added default config- and wiki-paths 2026-01-18 16:13:40 +01:00
Elias Fierke ea31637bdb [feat:] implemented a basic editor for the wiki 2026-01-18 14:36:52 +01:00
14 changed files with 661 additions and 236 deletions
-60
View File
@@ -1,60 +0,0 @@
using System.Collections.Generic;
using System.Text;
namespace Logof_Client;
public class CsvBuilder
{
private readonly string Header;
private readonly List<object> Instances;
private readonly KasAddressList KasAddressList;
public CsvBuilder(string header, List<object> instances)
{
Header = header;
Instances = instances;
}
public CsvBuilder(string header, KasAddressList instances)
{
Header = header;
KasAddressList = instances;
}
public string? BuildKas()
{
var result = new StringBuilder();
result.AppendLine(Header);
foreach (var l in KasAddressList.KasPersons)
result.AppendLine(
l.refsid + "," +
l.anrede + "," +
l.titel + "," +
l.vorname + "," +
l.adel + "," +
l.name + "," +
l.namezus + "," +
l.anredzus + "," +
l.strasse + "," +
l.strasse2 + "," +
l.plz + "," +
l.ort + "," +
l.land + "," +
l.pplz + "," +
l.postfach + "," +
l.name1 + "," +
l.name2 + "," +
l.name3 + "," +
l.name4 + "," +
l.name5 + "," +
l.funktion + "," +
l.funktion2 + "," +
l.abteilung + "," +
l.funktionad);
// weitere Cases
return result.ToString();
}
}
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
namespace Logof_Client; namespace Logof_Client;
@@ -32,11 +33,16 @@ public class KasAddressList //Address-Set
this.owner_id = owner_id; this.owner_id = owner_id;
} }
public static string GenerateName(string basic_type, bool? is_rest = false) public static async Task<string> GenerateName(string basic_type, bool? is_rest = false)
{ {
string pre = "";
if (is_rest == true) if (is_rest == true)
return basic_type + " - " + DateTime.Now.ToShortDateString() + " - Rest"; return basic_type + " - " + DateTime.Now.ToShortDateString() + " - Rest";
return basic_type + " - " + DateTime.Now.ToShortDateString(); pre = basic_type + " - " + DateTime.Now.ToShortDateString();
var result = await NamingWindow.Show(MainWindow._instance, pre);
return string.IsNullOrWhiteSpace(result) ? pre : result;
} }
// public void UpdateErrorList(List<KasPersonError> errorList) // public void UpdateErrorList(List<KasPersonError> errorList)
@@ -169,13 +175,18 @@ public class KasPerson
public static int GenerateNewID(int base_id) public static int GenerateNewID(int base_id)
{ {
var newid = 100000 + base_id; //var newid = 100000 + base_id;
int highest = 0;
foreach (var set in Settings._instance.addressSets.addresses) foreach (var set in Settings._instance.addressSets.addresses)
foreach (var add in set.KasPersons) {
if (add.id >= newid) foreach (var add in set.KasPersons)
newid = add.id + 1; {
if(add.id >= highest) highest = add.id+1;
}
}
return newid; return highest + base_id + 1;
} }
} }
@@ -201,4 +212,4 @@ public class KasPersonError
return output; return output;
} }
} }
+31 -3
View File
@@ -10,6 +10,7 @@ public class Settings
public static Settings _instance = new(); public static Settings _instance = new();
public AddressSets addressSets = new(); public AddressSets addressSets = new();
public Customers customers = new(); public Customers customers = 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");
@@ -52,6 +53,25 @@ public class Settings
} }
} }
public class PdfExportSettings
{
public double cellPaddingTopMm { get; set; } = 5;
public double cellPaddingBottomMm { get; set; } = 5;
public double cellPaddingLeftMm { get; set; } = 5;
public double cellPaddingRightMm { get; set; } = 5;
public double pageMarginTopMm { get; set; } = 0;
public double pageMarginBottomMm { get; set; } = 0;
public double pageMarginLeftMm { get; set; } = 0;
public double pageMarginRightMm { get; set; } = 0;
public int rowsPerPage { get; set; } = 7;
public int columnsPerPage { get; set; } = 3;
public double fontSize { get; set; } = 9;
public double smallFontSize { get; set; } = 6;
}
public class Global public class Global
{ {
public static Global _instance; public static Global _instance;
@@ -61,8 +81,16 @@ public class Global
_instance = this; _instance = this;
} }
public string config_path { get; set; } = ""; public string config_path { get; set; } = Path.Combine(
public string wiki_storage_path { get; set; } = ""; Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient",
"config.json");
public string wiki_storage_path { get; set; } = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"logofclient",
"wiki");
public List<Country> countries { get; set; } = new(); public List<Country> countries { get; set; } = new();
public string font_path { get; set; } = Path.Combine(AppContext.BaseDirectory, "assets", "fonts"); public string font_path { get; set; } = Path.Combine(AppContext.BaseDirectory, "assets", "fonts");
@@ -183,4 +211,4 @@ public class Country
return null; return null;
} }
} }
+108 -37
View File
@@ -28,7 +28,7 @@
<Label FontSize="20" Content="Addressverwaltung" VerticalContentAlignment="Center" /> <Label FontSize="20" Content="Addressverwaltung" VerticalContentAlignment="Center" />
</StackPanel> </StackPanel>
</TabItem.Header> </TabItem.Header>
<Grid RowDefinitions="2*,*,*"> <Grid RowDefinitions="3*,80,2*">
<Grid ColumnDefinitions="*,*" Grid.Row="0"> <Grid ColumnDefinitions="*,*" Grid.Row="0">
<!-- Kunden --> <!-- Kunden -->
<Grid Margin="30,30,10,30"> <Grid Margin="30,30,10,30">
@@ -67,7 +67,28 @@
SelectionChanged="LstCustomerAdressSets_OnSelectionChanged" SelectionChanged="LstCustomerAdressSets_OnSelectionChanged"
Background="AliceBlue" Background="AliceBlue"
Margin="0,5,0,5" Margin="0,5,0,5"
SelectionMode="Multiple,Toggle" /> SelectionMode="Multiple,Toggle">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="MnIAdSetRename" Click="MnIAdSetRename_OnClick">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Pencil" Width="12" Height="12" Size="12" />
<Label Content="Umbenennen" VerticalContentAlignment="Center" />
</StackPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem x:Name="MnIAdSetDelete" Click="MnIAdSetRename_OnClick" IsEnabled="False">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Trash" Width="12" Height="12" Size="12" />
<Label Content="Löschen" VerticalContentAlignment="Center" />
</StackPanel>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Button Grid.Row="2" HorizontalAlignment="Stretch" x:Name="BtnCustomerAddressSetImport" <Button Grid.Row="2" HorizontalAlignment="Stretch" x:Name="BtnCustomerAddressSetImport"
Click="BtnCustomerAddressSetImport_OnClick"> Click="BtnCustomerAddressSetImport_OnClick">
@@ -78,23 +99,10 @@
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
<!-- <Grid Grid.Row="0"> --> <!-- <Grid ColumnDefinitions="*,*,*" Grid.Row="1"> -->
<!-- <StackPanel Orientation="Horizontal" VerticalAlignment="Center" --> <StackPanel Grid.Row="1" Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center"
<!-- HorizontalAlignment="Center"> -->
<!-- <TextBox x:Name="TbFilename" Watermark="Dateipfad" Width="400" -->
<!-- VerticalContentAlignment="Center" /> -->
<!-- <Button x:Name="BtnChooseFile" Margin="10,0,0,0" Click="BtnChooseFile_OnClick"> -->
<!-- <StackPanel Orientation="Horizontal"> -->
<!-- <LucideIcon Kind="FolderOpen" Width="16" Height="16" Size="16" /> -->
<!-- <Label Content="Öffnen" VerticalContentAlignment="Center" /> -->
<!-- </StackPanel> -->
<!-- </Button> -->
<!-- </StackPanel> -->
<!-- </Grid> -->
<Grid Grid.ColumnDefinitions="*,*" Grid.Row="1">
<StackPanel Grid.Column="0" Width="250" Orientation="Vertical" HorizontalAlignment="Right"
Margin="0,0,5,0"> Margin="0,0,5,0">
<Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" <Button Width="250" HorizontalContentAlignment="Center"
Margin="0,0,0,10" IsEnabled="False" Margin="0,0,0,10" IsEnabled="False"
x:Name="BtnCheck" Click="BtnCheck_OnClick"> x:Name="BtnCheck" Click="BtnCheck_OnClick">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@@ -103,7 +111,7 @@
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
</Button> </Button>
<Button HorizontalAlignment="Stretch" IsEnabled="False" <Button Width="250" IsEnabled="False"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Click="BtnCombine_OnClick" x:Name="BtnCombine" Click="BtnCombine_OnClick" x:Name="BtnCombine"
Margin="0,0,0,10"> Margin="0,0,0,10">
@@ -113,19 +121,7 @@
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
</Button> </Button>
<Button HorizontalAlignment="Stretch" IsEnabled="False" <Button Width="250" IsEnabled="False"
HorizontalContentAlignment="Center" x:Name="BtnRepair"
Margin="0,0,0,10">
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Hammer" Width="36" Height="36" />
<Label Content="Reparieren" VerticalContentAlignment="Center" FontSize="15"
FontWeight="Bold" />
</StackPanel>
</Button>
</StackPanel>
<StackPanel Grid.Column="1" Width="250" Orientation="Vertical" HorizontalAlignment="Left"
Margin="5,0,0,0">
<Button HorizontalAlignment="Stretch" IsEnabled="False"
HorizontalContentAlignment="Center" x:Name="BtnShorten" HorizontalContentAlignment="Center" x:Name="BtnShorten"
Margin="0,0,0,10"> Margin="0,0,0,10">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@@ -134,7 +130,7 @@
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
</Button> </Button>
<Button HorizontalAlignment="Stretch" IsEnabled="False" <Button Width="250" IsEnabled="False"
Click="BtnGenerateLabels_OnClick" Click="BtnGenerateLabels_OnClick"
HorizontalContentAlignment="Center" x:Name="BtnGenerateLabels" HorizontalContentAlignment="Center" x:Name="BtnGenerateLabels"
Margin="0,0,0,10"> Margin="0,0,0,10">
@@ -145,8 +141,17 @@
FontWeight="Bold" /> FontWeight="Bold" />
</StackPanel> </StackPanel>
</Button> </Button>
<Button Width="250" IsEnabled="False"
HorizontalContentAlignment="Center" x:Name="BtnRepair"
Margin="0,0,0,10">
<StackPanel Orientation="Horizontal">
<LucideIcon Kind="Hammer" Width="36" Height="36" />
<Label Content="Reparieren" VerticalContentAlignment="Center" FontSize="15"
FontWeight="Bold" />
</StackPanel>
</Button>
</StackPanel> </StackPanel>
</Grid> <!-- </Grid> -->
<Grid Grid.Row="2" Margin="20" IsVisible="True" x:Name="GrdCalcMan"> <Grid Grid.Row="2" Margin="20" IsVisible="True" x:Name="GrdCalcMan">
<Image Source="assets/calc_man.png" VerticalAlignment="Center" HorizontalAlignment="Center" /> <Image Source="assets/calc_man.png" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid> </Grid>
@@ -221,6 +226,71 @@
<CheckBox HorizontalAlignment="Center" x:Name="CbMergeExportUnmerged" IsChecked="False">Speichere Unverarbeitete in neuem Verteiler</CheckBox> <CheckBox HorizontalAlignment="Center" x:Name="CbMergeExportUnmerged" IsChecked="False">Speichere Unverarbeitete in neuem Verteiler</CheckBox>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Grid Grid.Row="2" Margin="20" ColumnDefinitions="*,5*,*" IsVisible="False" x:Name="GrdExportMarginOptions">
<StackPanel Grid.Column="1" Orientation="Vertical" Spacing="20">
<Grid ColumnDefinitions="*,*,*" ColumnSpacing="20">
<StackPanel Orientation="Vertical" Spacing="10">
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Zellenrand oben (mm)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargCellPaddingTop" Minimum="0" Maximum="20" Value="5"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Zellenrand unten (mm)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargCellPaddingBot" Minimum="0" Maximum="20" Value="5"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Zellenrand links (mm)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargCellPaddingLeft" Minimum="0" Maximum="20" Value="5"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Zellenrand rechts (mm)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargCellPaddingRight" Minimum="0" Maximum="20" Value="5"></NumericUpDown>
</Grid>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical" Spacing="10">
<Grid ColumnDefinitions="*,*">
<Label Content="Zellenabstand oben"></Label>
<NumericUpDown Grid.Column="1" x:Name="TbExpMargMarginTop" Minimum="0" Maximum="20" Value="0"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Content="Zellenabstand unten"></Label>
<NumericUpDown Grid.Column="1" x:Name="TbExpMargMarginBottom" Minimum="0" Maximum="20" Value="0"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Content="Zellenabstand rechts"></Label>
<NumericUpDown Grid.Column="1" x:Name="TbExpMargMarginRight" Minimum="0" Maximum="20" Value="0"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Content="Zellenabstand links"></Label>
<NumericUpDown Grid.Column="1" x:Name="TbExpMargMarginLeft" Minimum="0" Maximum="20" Value="0"></NumericUpDown>
</Grid>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Vertical" Spacing="10">
<Grid ColumnDefinitions="*,*">
<Label Content="Zeilen pro Seite"></Label>
<NumericUpDown Grid.Column="1" x:Name="TbExpMargRowsPerPage" Minimum="1" Maximum="10" Value="7"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Spalten pro Seite"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargColumnsPerPage" Minimum="1" Maximum="8" Value="3"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Schriftgröße (groß)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargFontSize" Minimum="5" Maximum="30" Value="9"></NumericUpDown>
</Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Schriftgröße (klein)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargSmallFontSize" Minimum="3" Maximum="30" Value="6"></NumericUpDown>
</Grid>
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Start" Click="BtnStartGenerateLabels_OnClick"></Button>
</StackPanel>
</StackPanel>
</Grid>
</Grid> </Grid>
</TabItem> </TabItem>
<TabItem IsEnabled="False"> <TabItem IsEnabled="False">
@@ -257,9 +327,10 @@
<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> <StackPanel>
<TextBlock Text="Wiki" FontSize="18" Margin="12" /> <Button Content="+ Hinzufügen" Margin="10" x:Name="BtnWikiAddFile"
Click="BtnWikiAddFile_OnClick" />
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TreeView Name="NavTree" Margin="8" /> <TreeView Name="NavTree" Margin="10" />
</ScrollViewer> </ScrollViewer>
</StackPanel> </StackPanel>
</Border> </Border>
@@ -541,4 +612,4 @@
</Grid> </Grid>
</Border> </Border>
</Window> </Window>
+188 -15
View File
@@ -5,6 +5,7 @@ using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Controls.Primitives;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Logof_Client.Wiki; using Logof_Client.Wiki;
@@ -15,6 +16,7 @@ public partial class MainWindow : Window
public static MainWindow _instance; public static MainWindow _instance;
private Country _selectedCountry; private Country _selectedCountry;
private string _selectedWikiFilePath;
private bool _suppressCountryRefresh; private bool _suppressCountryRefresh;
private WikiService _wikiService; private WikiService _wikiService;
@@ -32,6 +34,8 @@ public partial class MainWindow : Window
WindowState = WindowState.Maximized; WindowState = WindowState.Maximized;
Global.Load(); Global.Load();
Settings.Load(); Settings.Load();
LoadPdfExportOptions();
HookPdfExportOptionEvents();
RefreshCountryView(); RefreshCountryView();
@@ -182,18 +186,20 @@ public partial class MainWindow : Window
{ {
GrdCalcMan.IsVisible = false; GrdCalcMan.IsVisible = false;
GrdCombineTypes.IsVisible = true; GrdCombineTypes.IsVisible = true;
GrdExportMarginOptions.IsVisible = false;
} }
private void MakeCalcManVisible() private void MakeCalcManVisible()
{ {
GrdCalcMan.IsVisible = true; GrdCalcMan.IsVisible = true;
GrdCombineTypes.IsVisible = false; GrdCombineTypes.IsVisible = false;
GrdExportMarginOptions.IsVisible = false;
} }
private async void StartCombine(Uri path) private async void StartCombine(Uri path)
{ {
MakeCalcManVisible(); MakeCalcManVisible();
var addresses = DataImport.ImportKasAddressList(path); var addresses = await DataImport.ImportKasAddressList(path);
var progressWindow = new ProgressWindow(); var progressWindow = new ProgressWindow();
var address_list = new List<KasAddressList> { addresses.Item2 }; var address_list = new List<KasAddressList> { addresses.Item2 };
@@ -215,7 +221,7 @@ public partial class MainWindow : Window
if (file == null) return; if (file == null) return;
//filePath = file[0].Path; //filePath = file[0].Path;
foreach (var f in file) address_list.Add(DataImport.ImportKasAddressList(f.Path).Item2); foreach (var f in file) address_list.Add((await DataImport.ImportKasAddressList(f.Path)).Item2);
progressWindow.Show(_instance); progressWindow.Show(_instance);
@@ -230,6 +236,7 @@ public partial class MainWindow : Window
{ {
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;
var text = await _wikiService.LoadFileContentAsync(item.Path); var text = await _wikiService.LoadFileContentAsync(item.Path);
try try
{ {
@@ -246,9 +253,14 @@ public partial class MainWindow : Window
EditButton.IsEnabled = true; EditButton.IsEnabled = true;
} }
else
{
_selectedWikiFilePath = null;
EditButton.IsEnabled = false;
}
} }
private void PopulateNavTree() public void PopulateNavTree()
{ {
var roots = _wikiService.GetRootItems(); var roots = _wikiService.GetRootItems();
var nodes = new List<TreeViewItem>(); var nodes = new List<TreeViewItem>();
@@ -446,7 +458,16 @@ public partial class MainWindow : Window
private async void EditButton_Click(object? sender, RoutedEventArgs e) private async void EditButton_Click(object? sender, RoutedEventArgs e)
{ {
await MessageBox.Show(this, "Edit feature is currently disabled.", "Edit Disabled"); if (string.IsNullOrWhiteSpace(_selectedWikiFilePath))
{
await MessageBox.Show(this, "Bitte wählen Sie zunächst eine Wiki-Datei aus.", "Keine Datei ausgewählt");
return;
}
EditorWindow ew = new(_selectedWikiFilePath);
ew.Show();
//await MessageBox.Show(this, "Edit feature is currently disabled.", "Edit Disabled");
} }
public void RefreshCustomerItems(int index = 0) public void RefreshCustomerItems(int index = 0)
@@ -526,7 +547,7 @@ public partial class MainWindow : Window
{ {
if (customer.patch == null) if (customer.patch == null)
{ {
var got = DataImport.ImportKasAddressList(selected_path, null, customer.separator); var got = await DataImport.ImportKasAddressList(selected_path, null, customer.separator);
if (!got.Item1) if (!got.Item1)
{ {
Console.WriteLine("Error while importing. Please try another file."); Console.WriteLine("Error while importing. Please try another file.");
@@ -542,7 +563,7 @@ public partial class MainWindow : Window
} }
else else
{ {
var got = DataImport.ImportKasAddressList(selected_path, customer.patch, customer.separator); var got = await DataImport.ImportKasAddressList(selected_path, customer.patch, customer.separator);
if (!got.Item1) if (!got.Item1)
{ {
Console.WriteLine("Error while importing. Please try another file."); Console.WriteLine("Error while importing. Please try another file.");
@@ -577,7 +598,7 @@ public partial class MainWindow : Window
foreach (var k in Settings._instance.addressSets.addresses) foreach (var k in Settings._instance.addressSets.addresses)
foreach (var customer in Settings._instance.customers.customers) foreach (var customer in Settings._instance.customers.customers)
if (customer.ID == k.owner_id && customer.ID == customer_id) if (customer.ID == k.owner_id && customer.ID == customer_id)
LstCustomerAdressSets.Items.Add(k.ID + " - " + k.Name + "(" + k.KasPersons.Count + " Einträge)"); LstCustomerAdressSets.Items.Add(k.ID + " - " + k.Name + " (" + k.KasPersons.Count + " Einträge)");
} }
private void LstCustomerAdressSets_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) private void LstCustomerAdressSets_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
@@ -659,8 +680,14 @@ public partial class MainWindow : Window
foreach (var item in LstCustomerAdressSets.SelectedItems) foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID( list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0]))); Convert.ToInt32(item.ToString().Split(" - ")[0])));
try
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "difference"); {
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "difference");
}
catch
{
}
} }
private void BtnCombineUnion_OnClick(object? sender, RoutedEventArgs e) private void BtnCombineUnion_OnClick(object? sender, RoutedEventArgs e)
@@ -669,8 +696,15 @@ public partial class MainWindow : Window
foreach (var item in LstCustomerAdressSets.SelectedItems) foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID( list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0]))); Convert.ToInt32(item.ToString().Split(" - ")[0])));
try
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "union"); {
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "union");
}
catch
{
}
} }
private void BtnCombineIntersection_OnClick(object? sender, RoutedEventArgs e) private void BtnCombineIntersection_OnClick(object? sender, RoutedEventArgs e)
@@ -679,8 +713,14 @@ public partial class MainWindow : Window
foreach (var item in LstCustomerAdressSets.SelectedItems) foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add(Settings._instance.addressSets.GetAddressSetByID( list.Add(Settings._instance.addressSets.GetAddressSetByID(
Convert.ToInt32(item.ToString().Split(" - ")[0]))); Convert.ToInt32(item.ToString().Split(" - ")[0])));
try
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "intersection"); {
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "intersection");
}
catch
{
}
} }
private void BtnCombineSymmetricDifference_OnClick(object? sender, RoutedEventArgs e) private void BtnCombineSymmetricDifference_OnClick(object? sender, RoutedEventArgs e)
@@ -695,6 +735,16 @@ public partial class MainWindow : Window
private async void BtnGenerateLabels_OnClick(object? sender, RoutedEventArgs e) private async void BtnGenerateLabels_OnClick(object? sender, RoutedEventArgs e)
{ {
GrdCalcMan.IsVisible = false;
GrdCombineTypes.IsVisible = false;
GrdExportMarginOptions.IsVisible = true;
LoadPdfExportOptions();
}
private async void BtnStartGenerateLabels_OnClick(object? sender, RoutedEventArgs e)
{
SavePdfExportOptions();
var saveDialog = new SaveFileDialog var saveDialog = new SaveFileDialog
{ {
DefaultExtension = "pdf", DefaultExtension = "pdf",
@@ -704,7 +754,7 @@ public partial class MainWindow : Window
if (!string.IsNullOrEmpty(filePath)) if (!string.IsNullOrEmpty(filePath))
{ {
var builder = new PdfBuilder(); var builder = new PdfBuilder(Settings._instance.pdfExport);
builder.CreateAddressLabelPdfFromAddressSetWithPlaceholder( builder.CreateAddressLabelPdfFromAddressSetWithPlaceholder(
Convert.ToInt32(LstCustomerAdressSets.SelectedItems[0].ToString().Split(" - ")[0]), Convert.ToInt32(LstCustomerAdressSets.SelectedItems[0].ToString().Split(" - ")[0]),
@@ -715,6 +765,87 @@ public partial class MainWindow : Window
} }
} }
private void HookPdfExportOptionEvents()
{
var controls = GetPdfExportControls();
foreach (var control in controls) control.ValueChanged += PdfExportOption_OnValueChanged;
}
private void LoadPdfExportOptions()
{
var options = Settings._instance.pdfExport ?? new PdfExportSettings();
NudExpMargCellPaddingTop.Value = (decimal)options.cellPaddingTopMm;
NudExpMargCellPaddingBot.Value = (decimal)options.cellPaddingBottomMm;
NudExpMargCellPaddingLeft.Value = (decimal)options.cellPaddingLeftMm;
NudExpMargCellPaddingRight.Value = (decimal)options.cellPaddingRightMm;
TbExpMargMarginTop.Value = (decimal)options.pageMarginTopMm;
TbExpMargMarginBottom.Value = (decimal)options.pageMarginBottomMm;
TbExpMargMarginLeft.Value = (decimal)options.pageMarginLeftMm;
TbExpMargMarginRight.Value = (decimal)options.pageMarginRightMm;
TbExpMargRowsPerPage.Value = options.rowsPerPage;
NudExpMargColumnsPerPage.Value = options.columnsPerPage;
NudExpMargFontSize.Value = (decimal)options.fontSize;
NudExpMargSmallFontSize.Value = (decimal)options.smallFontSize;
}
private void SavePdfExportOptions()
{
Settings._instance.pdfExport = new PdfExportSettings
{
cellPaddingTopMm = ReadDouble(NudExpMargCellPaddingTop),
cellPaddingBottomMm = ReadDouble(NudExpMargCellPaddingBot),
cellPaddingLeftMm = ReadDouble(NudExpMargCellPaddingLeft),
cellPaddingRightMm = ReadDouble(NudExpMargCellPaddingRight),
pageMarginTopMm = ReadDouble(TbExpMargMarginTop),
pageMarginBottomMm = ReadDouble(TbExpMargMarginBottom),
pageMarginLeftMm = ReadDouble(TbExpMargMarginLeft),
pageMarginRightMm = ReadDouble(TbExpMargMarginRight),
rowsPerPage = ReadInt(TbExpMargRowsPerPage, 7),
columnsPerPage = ReadInt(NudExpMargColumnsPerPage, 3),
fontSize = ReadDouble(NudExpMargFontSize),
smallFontSize = ReadDouble(NudExpMargSmallFontSize)
};
Settings.Save();
}
private void PdfExportOption_OnValueChanged(object? sender, NumericUpDownValueChangedEventArgs e)
{
SavePdfExportOptions();
}
private double ReadDouble(NumericUpDown control)
{
return (double)(control.Value ?? 0);
}
private int ReadInt(NumericUpDown control, int fallback)
{
return (int)Math.Round(control.Value ?? fallback);
}
private NumericUpDown[] GetPdfExportControls()
{
return
[
NudExpMargCellPaddingTop,
NudExpMargCellPaddingBot,
NudExpMargCellPaddingLeft,
NudExpMargCellPaddingRight,
TbExpMargMarginTop,
TbExpMargMarginBottom,
TbExpMargMarginLeft,
TbExpMargMarginRight,
TbExpMargRowsPerPage,
NudExpMargColumnsPerPage,
NudExpMargFontSize,
NudExpMargSmallFontSize
];
}
private void TbSettingsCustomerSenderAddress_OnTextChanged(object? sender, TextChangedEventArgs e) private void TbSettingsCustomerSenderAddress_OnTextChanged(object? sender, TextChangedEventArgs e)
{ {
if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return; if (LstSettingsCustomers.SelectedIndex == null || LstSettingsCustomers.SelectedIndex == -1) return;
@@ -856,4 +987,46 @@ public partial class MainWindow : Window
new List<string> { countryie.ThreeLetterCode, countryie.TwoLetterCode })); new List<string> { countryie.ThreeLetterCode, countryie.TwoLetterCode }));
RefreshCountryView(); RefreshCountryView();
} }
}
private async void BtnWikiAddFile_OnClick(object? sender, RoutedEventArgs e)
{
var result = await NamingWindow.Show(this);
if (result != null)
try
{
File.WriteAllText(Path.Combine(Global._instance.wiki_storage_path, result), "");
PopulateNavTree();
}
catch (Exception ex)
{
MessageBox.Show(this, ex.StackTrace, "Fehler");
}
}
private async void MnIAdSetRename_OnClick(object? sender, RoutedEventArgs e)
{
if (LstCustomerAdressSets.SelectedItems.Count > 0)
try
{
var result = await NamingWindow.Show(this);
if (result != null)
{
var id = KasAddressList.GetIDByAddressSetListItem(LstCustomerAdressSets.SelectedItems[0]
.ToString());
var cus_id = Customer.GetIDByCustomerListItem(LstCustomers.SelectedItems[0].ToString());
foreach (var set in Settings._instance.addressSets.addresses)
if (set.ID == id)
{
set.Name = result;
Settings.Save();
RefreshAddressSetListItems(cus_id);
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show(this, ex.StackTrace, "Fehler");
}
}
}
+19
View File
@@ -0,0 +1,19 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" SizeToContent="WidthAndHeight"
x:Class="Logof_Client.NamingWindow"
Title="NamingWindow">
<StackPanel Orientation="Vertical">
<TextBlock Name="Text" Margin="10" TextWrapping="Wrap" />
<TextBox Name="Input" Margin="10" />
<StackPanel HorizontalAlignment="Right" Margin="5" Orientation="Horizontal" Name="Buttons">
<StackPanel.Styles>
<Style Selector="Button">
<Setter Property="Margin" Value="5" />
</Style>
</StackPanel.Styles>
</StackPanel>
</StackPanel>
</Window>
+57
View File
@@ -0,0 +1,57 @@
using System;
using System.Threading.Tasks;
using Avalonia.Controls;
namespace Logof_Client;
public partial class NamingWindow : Window
{
public NamingWindow()
{
InitializeComponent();
}
public static Task<string> Show(Window parent, string input = "", string info = "Bitte geben Sie einen Namen ein:")
{
try
{
var wind = new NamingWindow
{
Title = "Name eingeben"
};
wind.FindControl<TextBlock>("Text").Text = info;
var buttonPanel = wind.FindControl<StackPanel>("Buttons");
var inputBox = wind.FindControl<TextBox>("Input");
inputBox.Text = input;
string res = null;
void AddButton(string caption)
{
var btn = new Button { Content = caption };
btn.Click += (_, __) =>
{
res = inputBox.Text;
wind.Close();
};
buttonPanel.Children.Add(btn);
}
AddButton("Ok");
var tcs = new TaskCompletionSource<string>();
wind.Closed += delegate { tcs.TrySetResult(res); };
if (parent != null)
wind.ShowDialog(parent);
else wind.Show();
return tcs.Task;
}
catch (Exception ex)
{
Console.WriteLine("Error while showing naming window: " + ex.Message);
return Task.FromResult<string>(null!);
}
}
}
+14 -39
View File
@@ -19,36 +19,11 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> Perform(List<KasAddressList> address_lists, string type, public async Task<(KasAddressList, KasAddressList)> Perform(List<KasAddressList> address_lists, string type,
bool? exportUnused) bool? exportUnused)
{ {
var res = await Task.Run(async () => if (type == "difference") return await Difference(address_lists, exportUnused);
{ if (type == "union") return await Union(address_lists, exportUnused);
if (type == "difference") return Difference(address_lists, exportUnused); if (type == "intersection") return await Intersection(address_lists, exportUnused);
if (type == "union") return Union(address_lists, exportUnused); if (type == "symdiff") return await SymmetricDifference(address_lists, exportUnused);
if (type == "intersection") return Intersection(address_lists, exportUnused);
if (type == "symdiff") return SymmetricDifference(address_lists, exportUnused);
return null;
});
return res.Result;
// KasAddressList result = new("Ergebnis_" + DateTime.Now.ToString("ddMMyy_HHmmss"));
// await Task.Run(async () =>
// {
// for (var i = 0; i < address_lists.Count; i++)
// if (i == 0)
// lock (result)
// {
// result = address_lists[i];
// }
// else
// lock (result)
// {
// result = Merge(result, address_lists[i], i + 1, address_lists.Count).Result;
// }
// });
// return result;
return (null, null); return (null, null);
} }
@@ -97,7 +72,7 @@ public class CombineAddresses
Progress? progress = null) Progress? progress = null)
{ {
if (address_lists == null || address_lists.Count == 0) if (address_lists == null || address_lists.Count == 0)
return (new KasAddressList(KasAddressList.GenerateName("difference")), null); return (new KasAddressList(await KasAddressList.GenerateName("difference")), null);
progress ??= new Progress progress ??= new Progress
{ {
@@ -109,8 +84,8 @@ public class CombineAddresses
var restUnion = new List<KasPerson>(); var restUnion = new List<KasPerson>();
for (var i = 1; i < address_lists.Count; i++) for (var i = 1; i < address_lists.Count; i++)
restUnion.AddRange(address_lists[i].KasPersons); restUnion.AddRange(address_lists[i].KasPersons);
var result = new KasAddressList(KasAddressList.GenerateName("difference")); var result = new KasAddressList(await KasAddressList.GenerateName("difference"));
var second_result = new KasAddressList(KasAddressList.GenerateName("difference_rest")); var second_result = new KasAddressList(await KasAddressList.GenerateName("difference_rest", false));
foreach (var person in address_lists[0].KasPersons) foreach (var person in address_lists[0].KasPersons)
{ {
@@ -136,8 +111,8 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> Union(List<KasAddressList> address_lists, bool? return_unused, public async Task<(KasAddressList, KasAddressList)> Union(List<KasAddressList> address_lists, bool? return_unused,
Progress progress = null) Progress progress = null)
{ {
var result = new KasAddressList(KasAddressList.GenerateName("union")); var result = new KasAddressList(await KasAddressList.GenerateName("union"));
var second_result = new KasAddressList(KasAddressList.GenerateName("union_rest")); var second_result = new KasAddressList(await KasAddressList.GenerateName("union_rest", false));
if (address_lists == null || address_lists.Count == 0) if (address_lists == null || address_lists.Count == 0)
return (result, null); return (result, null);
@@ -178,8 +153,8 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> Intersection(List<KasAddressList> address_lists, public async Task<(KasAddressList, KasAddressList)> Intersection(List<KasAddressList> address_lists,
bool? return_unused, Progress progress = null) bool? return_unused, Progress progress = null)
{ {
var result = new KasAddressList(KasAddressList.GenerateName("intersection")); var result = new KasAddressList(await KasAddressList.GenerateName("intersection"));
var second_result = new KasAddressList(KasAddressList.GenerateName("intersection_rest")); var second_result = new KasAddressList(await KasAddressList.GenerateName("intersection_rest", false));
if (address_lists == null || address_lists.Count == 0) if (address_lists == null || address_lists.Count == 0)
return (result, null); return (result, null);
@@ -225,8 +200,8 @@ public class CombineAddresses
public async Task<(KasAddressList, KasAddressList)> SymmetricDifference(List<KasAddressList> address_lists, public async Task<(KasAddressList, KasAddressList)> SymmetricDifference(List<KasAddressList> address_lists,
bool? return_unused, Progress progress = null) bool? return_unused, Progress progress = null)
{ {
var result = new KasAddressList(KasAddressList.GenerateName("symmetric_difference")); var result = new KasAddressList(await KasAddressList.GenerateName("symmetric_difference"));
var second_result = new KasAddressList(KasAddressList.GenerateName("symmetric_rest")); var second_result = new KasAddressList(await KasAddressList.GenerateName("symmetric_rest", false));
if (address_lists == null || address_lists.Count == 0) if (address_lists == null || address_lists.Count == 0)
return (result, null); return (result, null);
@@ -354,4 +329,4 @@ public class Progress
var comparedPersons = ComparedPersons; var comparedPersons = ComparedPersons;
Interlocked.Increment(ref comparedPersons); Interlocked.Increment(ref comparedPersons);
} }
} }
+75
View File
@@ -0,0 +1,75 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Logof_Client;
public class CsvBuilder
{
private readonly string Header;
private readonly List<object> Instances;
private readonly KasAddressList KasAddressList;
private readonly char Separator;
public CsvBuilder(string header, List<object> instances, char separator = ',')
{
Header = header;
Instances = instances;
Separator = separator;
}
public CsvBuilder(string header, KasAddressList instances, char separator = ',')
{
Header = header;
KasAddressList = instances;
Separator = separator;
}
public string? BuildKas()
{
var result = new StringBuilder();
result.AppendLine(Header);
foreach (var l in KasAddressList.KasPersons)
result.AppendLine(string.Join(Separator, new[]
{
EscapeCsvField(l.refsid.ToString()),
EscapeCsvField(l.anrede),
EscapeCsvField(l.titel),
EscapeCsvField(l.vorname),
EscapeCsvField(l.adel),
EscapeCsvField(l.name),
EscapeCsvField(l.namezus),
EscapeCsvField(l.anredzus),
EscapeCsvField(l.strasse),
EscapeCsvField(l.strasse2),
EscapeCsvField(l.plz),
EscapeCsvField(l.ort),
EscapeCsvField(l.land),
EscapeCsvField(l.pplz),
EscapeCsvField(l.postfach),
EscapeCsvField(l.name1),
EscapeCsvField(l.name2),
EscapeCsvField(l.name3),
EscapeCsvField(l.name4),
EscapeCsvField(l.name5),
EscapeCsvField(l.funktion),
EscapeCsvField(l.funktion2),
EscapeCsvField(l.abteilung),
EscapeCsvField(l.funktionad)
}));
// weitere Cases
return result.ToString();
}
private string EscapeCsvField(string? value)
{
var field = value ?? string.Empty;
var mustQuote = field.Contains(Separator) || field.Contains('"') || field.Contains('\r') || field.Contains('\n');
if (!mustQuote)
return field;
return "\"" + field.Replace("\"", "\"\"") + "\"";
}
}
+52 -13
View File
@@ -3,20 +3,22 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Logof_Client; namespace Logof_Client;
public class DataImport public class DataImport
{ {
public static (bool, KasAddressList) ImportKasAddressList(Uri pathToCsv, AddressPatch patch = null, public static async Task<(bool, KasAddressList)> ImportKasAddressList(Uri pathToCsv, AddressPatch patch = null,
char separator = ',') char separator = ',')
{ {
if (patch == null) if (patch == null)
return ImportKasAddressListWithoutPatch(pathToCsv, separator); return await ImportKasAddressListWithoutPatch(pathToCsv, separator);
return ImportKasAddressListWithPatch(pathToCsv, patch, separator); return await ImportKasAddressListWithPatch(pathToCsv, patch, separator);
} }
private static (bool, KasAddressList) ImportKasAddressListWithoutPatch(Uri pathToCsv, char separator) private static async Task<(bool, KasAddressList)> ImportKasAddressListWithoutPatch(Uri pathToCsv, char separator)
{ {
if (!File.Exists(pathToCsv.LocalPath)) if (!File.Exists(pathToCsv.LocalPath))
{ {
@@ -32,8 +34,8 @@ public class DataImport
return (false, null); return (false, null);
} }
var imported = var imported = new KasAddressList(
new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); await KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath)));
while (!reader.EndOfStream) while (!reader.EndOfStream)
{ {
@@ -41,7 +43,7 @@ public class DataImport
if (string.IsNullOrWhiteSpace(line)) if (string.IsNullOrWhiteSpace(line))
continue; continue;
var parts = line.Split(separator).Select(p => p.Trim()).ToArray(); var parts = ParseCsvLine(line, separator);
if (parts.Length < 24) if (parts.Length < 24)
{ {
@@ -90,7 +92,7 @@ public class DataImport
return (true, imported); return (true, imported);
} }
private static (bool, KasAddressList) ImportKasAddressListWithPatch(Uri pathToCsv, AddressPatch patch, private static async Task<(bool, KasAddressList)> ImportKasAddressListWithPatch(Uri pathToCsv, AddressPatch patch,
char separator) char separator)
{ {
if (!File.Exists(pathToCsv.LocalPath)) if (!File.Exists(pathToCsv.LocalPath))
@@ -107,10 +109,10 @@ public class DataImport
return (false, null); return (false, null);
} }
var headers = headerLine.Split(separator).Select(h => h.Trim()).ToArray(); var headers = ParseCsvLine(headerLine, separator);
var imported = var imported = new KasAddressList(
new KasAddressList(KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath))); await KasAddressList.GenerateName(Path.GetFileNameWithoutExtension(pathToCsv.LocalPath)));
var patchType = typeof(AddressPatch); var patchType = typeof(AddressPatch);
var binding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; var binding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
@@ -126,7 +128,7 @@ public class DataImport
if (string.IsNullOrWhiteSpace(line)) if (string.IsNullOrWhiteSpace(line))
continue; continue;
var parts = line.Split(separator).Select(p => p.Trim()).ToArray(); var parts = ParseCsvLine(line, separator);
var fieldValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); var fieldValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@@ -241,4 +243,41 @@ public class DataImport
{ {
return int.TryParse(input, out var result) ? result : 0; return int.TryParse(input, out var result) ? result : 0;
} }
}
private static string[] ParseCsvLine(string line, char separator)
{
var fields = new List<string>();
var current = new StringBuilder();
var inQuotes = false;
for (var i = 0; i < line.Length; i++)
{
var c = line[i];
if (c == '"')
{
if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
{
current.Append('"');
i++;
continue;
}
inQuotes = !inQuotes;
continue;
}
if (c == separator && !inQuotes)
{
fields.Add(current.ToString().Trim());
current.Clear();
continue;
}
current.Append(c);
}
fields.Add(current.ToString().Trim());
return fields.ToArray();
}
}
+36 -50
View File
@@ -11,35 +11,15 @@ namespace Logof_Client;
public class PdfBuilder public class PdfBuilder
{ {
// Table layout private readonly PdfExportSettings _settings;
private const int CellsPerRow = 3;
private const int CellsPerPage = 21; // 3 columns × 7 rows
private readonly XFont _boldFont; private readonly XFont _boldFont;
private readonly double _cellHeight = 42.43; // mm
private readonly double _cellPaddingBottom = 5; // mm
// Padding inside cells
private readonly double _cellPaddingLeft = 5; // mm
private readonly double _cellPaddingTop = 5; // mm
// Cell dimensions (in mm)
private readonly double _cellWidth = 70; // mm
// Font settings
private readonly double _fontSize = 9;
private readonly double _marginBottom = 1; // mm
// Paper and layout settings
private readonly double _marginLeft = 0; // mm
private readonly double _marginRight = 0; // mm
private readonly double _marginTop = 0; // mm
private readonly XFont _regularFont; private readonly XFont _regularFont;
private readonly XFont _smallFont; private readonly XFont _smallFont;
public PdfBuilder() public PdfBuilder(PdfExportSettings? settings = null)
{ {
EnsureFontResolverRegistered(); EnsureFontResolverRegistered();
_settings = settings ?? new PdfExportSettings();
// Select first font from build output fonts folder (AppContext.BaseDirectory/fonts) // Select first font from build output fonts folder (AppContext.BaseDirectory/fonts)
var chosenFamily = "Arial"; var chosenFamily = "Arial";
@@ -57,9 +37,9 @@ public class PdfBuilder
chosenFamily = "Arial"; chosenFamily = "Arial";
} }
_boldFont = new XFont(chosenFamily, 9, XFontStyleEx.Bold); _boldFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Bold);
_regularFont = new XFont(chosenFamily, 9, XFontStyleEx.Regular); _regularFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Regular);
_smallFont = new XFont(chosenFamily, 6, XFontStyleEx.Regular); _smallFont = new XFont(chosenFamily, _settings.smallFontSize, XFontStyleEx.Regular);
} }
private static void EnsureFontResolverRegistered() private static void EnsureFontResolverRegistered()
@@ -159,20 +139,17 @@ public class PdfBuilder
private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex) private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex)
{ {
var cellCount = 0; for (var row = 0; row < _settings.rowsPerPage; row++)
for (var row = 0; row < 7; row++)
{ {
for (var col = 0; col < 3; col++) for (var col = 0; col < _settings.columnsPerPage; col++)
{ {
if (addressIndex >= addresses.Count) break; if (addressIndex >= addresses.Count) break;
var x = MmToPoints(_marginLeft + col * _cellWidth); var x = MmToPoints(_settings.pageMarginLeftMm + col * GetCellWidthMm());
var y = MmToPoints(_marginTop + row * _cellHeight); var y = MmToPoints(_settings.pageMarginTopMm + row * GetCellHeightMm());
DrawCell(gfx, x, y, addresses[addressIndex]); DrawCell(gfx, x, y, addresses[addressIndex]);
addressIndex++; addressIndex++;
cellCount++;
} }
if (addressIndex >= addresses.Count) break; if (addressIndex >= addresses.Count) break;
@@ -182,13 +159,11 @@ 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)
{ {
var cellCount = 0; for (var row = 0; row < _settings.rowsPerPage; row++)
for (var col = 0; col < _settings.columnsPerPage; col++)
for (var row = 0; row < 7; row++)
for (var col = 0; col < 3; col++)
{ {
var x = MmToPoints(_marginLeft + col * _cellWidth); var x = MmToPoints(_settings.pageMarginLeftMm + col * GetCellWidthMm());
var y = MmToPoints(_marginTop + row * _cellHeight); var y = MmToPoints(_settings.pageMarginTopMm + row * GetCellHeightMm());
// First cell: placeholder // First cell: placeholder
if (isFirstCell) if (isFirstCell)
@@ -205,15 +180,13 @@ public class PdfBuilder
{ {
DrawEmptyCell(gfx, x, y); DrawEmptyCell(gfx, x, y);
} }
cellCount++;
} }
} }
private void DrawCell(XGraphics gfx, double x, double y, string? address) private void DrawCell(XGraphics gfx, double x, double y, string? address)
{ {
var cellWidthPoints = MmToPoints(_cellWidth); var cellWidthPoints = MmToPoints(GetCellWidthMm());
var cellHeightPoints = MmToPoints(_cellHeight); var cellHeightPoints = MmToPoints(GetCellHeightMm());
// Draw cell border // Draw cell border
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints); var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
@@ -225,8 +198,8 @@ public class PdfBuilder
private void DrawEmptyCell(XGraphics gfx, double x, double y) private void DrawEmptyCell(XGraphics gfx, double x, double y)
{ {
var cellWidthPoints = MmToPoints(_cellWidth); var cellWidthPoints = MmToPoints(GetCellWidthMm());
var cellHeightPoints = MmToPoints(_cellHeight); var cellHeightPoints = MmToPoints(GetCellHeightMm());
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);
@@ -234,11 +207,12 @@ public class PdfBuilder
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)
{ {
var paddingLeftPoints = MmToPoints(_cellPaddingLeft); var paddingLeftPoints = MmToPoints(_settings.cellPaddingLeftMm);
var paddingTopPoints = MmToPoints(_cellPaddingTop); var paddingRightPoints = MmToPoints(_settings.cellPaddingRightMm);
var paddingBottomPoints = MmToPoints(_cellPaddingBottom); var paddingTopPoints = MmToPoints(_settings.cellPaddingTopMm);
var paddingBottomPoints = MmToPoints(_settings.cellPaddingBottomMm);
var maxWidth = cellWidth - paddingLeftPoints * 2; var maxWidth = Math.Max(0, cellWidth - paddingLeftPoints - paddingRightPoints);
// Split text by newlines and remove empty trailing lines // Split text by newlines and remove empty trailing lines
var rawLines = text.Split(new[] { "\n" }, StringSplitOptions.None); var rawLines = text.Split(new[] { "\n" }, StringSplitOptions.None);
@@ -382,6 +356,18 @@ public class PdfBuilder
return mm * 2.834645669; return mm * 2.834645669;
} }
private double GetCellWidthMm()
{
var availableWidthMm = 210d - _settings.pageMarginLeftMm - _settings.pageMarginRightMm;
return availableWidthMm / _settings.columnsPerPage;
}
private double GetCellHeightMm()
{
var availableHeightMm = 297d - _settings.pageMarginTopMm - _settings.pageMarginBottomMm;
return availableHeightMm / _settings.rowsPerPage;
}
// Configuration methods to allow customization // Configuration methods to allow customization
/// <summary> /// <summary>
@@ -401,4 +387,4 @@ public class PdfBuilder
if (left < 0 || top < 0 || right < 0 || bottom < 0) if (left < 0 || top < 0 || right < 0 || bottom < 0)
throw new ArgumentException("Margins cannot be negative"); throw new ArgumentException("Margins cannot be negative");
} }
} }
+11 -2
View File
@@ -1,8 +1,17 @@
<Window xmlns="https://github.com/avaloniaui" <Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Logof_Client.Wiki.EditorWindow" x:Class="Logof_Client.Wiki.EditorWindow"
Title="Wiki Editor (disabled)" Width="400" Height="150"> Title="Wiki Editor" MinWidth="600" MinHeight="350" WindowState="Maximized">
<Grid> <Grid>
<TextBlock Margin="12" TextWrapping="Wrap">Coming soon.</TextBlock> <Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button x:Name="BtnSave" Content="Speichern" Click="BtnSave_OnClick" />
<Button x:Name="BtnSaveAs" Content="Speichern unter..." Click="BtnSaveAs_OnClick" />
<Button x:Name="BtnDelete" Content="Löschen" Click="BtnDelete_OnClick" />
</StackPanel>
<TextBox Grid.Row="1" x:Name="TbContent" />
</Grid> </Grid>
</Window> </Window>
+51 -9
View File
@@ -1,17 +1,59 @@
using System; using System;
using System.IO;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity;
namespace Logof_Client.Wiki; namespace Logof_Client.Wiki;
public partial class EditorWindow : Window public partial class EditorWindow : Window
{ {
private void InitializeComponent() public string filename = "";
{
Avalonia.Markup.Xaml.AvaloniaXamlLoader.Load(this);
}
public EditorWindow() public EditorWindow(string filename = "")
{ {
InitializeComponent(); InitializeComponent();
} this.filename = filename;
} if (!string.IsNullOrWhiteSpace(filename) && File.Exists(filename))
{
var content = TbContent;
if (content != null) content.Text = File.ReadAllText(this.filename);
Title = "Wiki Editor - " + filename;
}
else if (!string.IsNullOrWhiteSpace(filename))
{
MessageBox.Show(null, "Die Datei existiert nicht", "Fehler");
Close();
}
}
private void BtnSave_OnClick(object? sender, RoutedEventArgs e)
{
try
{
File.WriteAllText(filename, TbContent.Text);
MainWindow._instance.PopulateNavTree();
}
catch (Exception ex)
{
MessageBox.Show(null,
"Es ist ein Fehler aufgetreten. Bitte senden Sie ihn über git.mypapercloud.de/fierke/logofclient ein:\n" +
ex.StackTrace, "Fehler");
}
}
private void BtnSaveAs_OnClick(object? sender, RoutedEventArgs e)
{
MessageBox.Show(null,
"Feature noch nicht implemetiert.\nErstelle neue Dateien unter " + Global._instance.wiki_storage_path,
"Fehler");
}
private async void BtnDelete_OnClick(object? sender, RoutedEventArgs e)
{
var result = await MessageBox.Show(null, "Sicher?", "Sicher?", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No) return;
File.Delete(filename);
MainWindow._instance.PopulateNavTree();
Close();
}
}