Переглянути джерело

add feature to print Labels by .csv file #7

Dalibor Votruba 1 рік тому
батько
коміт
a7fa3e0007

+ 33 - 18
App.config

@@ -7,30 +7,12 @@
     </configSections>
     </configSections>
     <userSettings>
     <userSettings>
         <qdr.app.studiou.orders2printpack.Properties.AppSettings>
         <qdr.app.studiou.orders2printpack.Properties.AppSettings>
-            <setting name="CSVDelimiter" serializeAs="String">
-                <value>;</value>
-            </setting>
             <setting name="LastOutputDir" serializeAs="String">
             <setting name="LastOutputDir" serializeAs="String">
                 <value />
                 <value />
             </setting>
             </setting>
-            <setting name="MapColOrderNo" serializeAs="String">
-                <value>order_no</value>
-            </setting>
-            <setting name="MapColProductCat" serializeAs="String">
-                <value>prod_cat</value>
-            </setting>
-            <setting name="MapColUri" serializeAs="String">
-                <value>prod_img_url</value>
-            </setting>
-            <setting name="MapColQuantity" serializeAs="String">
-                <value>qty</value>
-            </setting>
             <setting name="SourceSearchPattern" serializeAs="String">
             <setting name="SourceSearchPattern" serializeAs="String">
                 <value>*.jpg</value>
                 <value>*.jpg</value>
             </setting>
             </setting>
-            <setting name="MapColProductFormat" serializeAs="String">
-                <value>prod_var_type</value>
-            </setting>
             <setting name="LastSourceDir" serializeAs="String">
             <setting name="LastSourceDir" serializeAs="String">
                 <value />
                 <value />
             </setting>
             </setting>
@@ -62,6 +44,39 @@
             <setting name="OutputFileMask" serializeAs="String">
             <setting name="OutputFileMask" serializeAs="String">
                 <value>{prod_var_type}\{order_no}_{prod_name}_{ordinal}{ext}</value>
                 <value>{prod_var_type}\{order_no}_{prod_name}_{ordinal}{ext}</value>
             </setting>
             </setting>
+            <setting name="CSVDelimiter" serializeAs="String">
+                <value>;</value>
+            </setting>
+            <setting name="MapColOrderNo" serializeAs="String">
+                <value>order_no</value>
+            </setting>
+            <setting name="MapColProductCat" serializeAs="String">
+                <value>prod_cat</value>
+            </setting>
+            <setting name="MapColUri" serializeAs="String">
+                <value>prod_img_url</value>
+            </setting>
+            <setting name="MapColQuantity" serializeAs="String">
+                <value>qty</value>
+            </setting>
+            <setting name="MapColProductFormat" serializeAs="String">
+                <value>prod_var_type</value>
+            </setting>
+            <setting name="LabelTemplate" serializeAs="String">
+                <value>^^18^**Objednávka: {order_no}**^^{cr}^^14^**{prod_cat}**^^{cr}{prod_var_type}{cr}Počet: {qty}</value>
+            </setting>
+            <setting name="LabelWidth" serializeAs="String">
+                <value>200</value>
+            </setting>
+            <setting name="LabelHeight" serializeAs="String">
+                <value>120</value>
+            </setting>
+            <setting name="LabelPerRow" serializeAs="String">
+                <value>3</value>
+            </setting>
+            <setting name="LabelPerCol" serializeAs="String">
+                <value>8</value>
+            </setting>
         </qdr.app.studiou.orders2printpack.Properties.AppSettings>
         </qdr.app.studiou.orders2printpack.Properties.AppSettings>
     </userSettings>
     </userSettings>
 </configuration>
 </configuration>

+ 8 - 6
Extensions/CsvUtils.cs

@@ -20,7 +20,7 @@ public static class CsvUtils
         DataTable dataTable = new DataTable();
         DataTable dataTable = new DataTable();
         using (StreamReader streamReader = fs.File.OpenText(csvFile))
         using (StreamReader streamReader = fs.File.OpenText(csvFile))
         {
         {
-            string[] array = null;
+            string[]? array = null;
             if (hasHeaderRow)
             if (hasHeaderRow)
             {
             {
                 array = ParseCsvLine(streamReader.ReadLine(), delimiter);
                 array = ParseCsvLine(streamReader.ReadLine(), delimiter);
@@ -38,7 +38,7 @@ public static class CsvUtils
 
 
             while (!streamReader.EndOfStream)
             while (!streamReader.EndOfStream)
             {
             {
-                string[] array3 = ParseCsvLine(streamReader.ReadLine(), delimiter);
+                string[]? array3 = ParseCsvLine(streamReader.ReadLine(), delimiter);
                 if (array3 == null)
                 if (array3 == null)
                 {
                 {
                     continue;
                     continue;
@@ -123,8 +123,10 @@ public static class CsvUtils
                                                        select QuoteValue(processColumnCallback == null ? column.ColumnName : processColumnCallback(column.ColumnName), delimiter2)));
                                                        select QuoteValue(processColumnCallback == null ? column.ColumnName : processColumnCallback(column.ColumnName), delimiter2)));
         foreach (DataRow row in dataTable.Rows)
         foreach (DataRow row in dataTable.Rows)
         {
         {
-            streamWriter.WriteLine(string.Join(delimiter2, row.ItemArray.Select((object field) => QuoteValue(field?.ToString(), delimiter2))));
-        }
+#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes).
+                streamWriter.WriteLine(string.Join(delimiter2, row.ItemArray.Select((object field) => QuoteValue(field?.ToString(), delimiter2))));
+#pragma warning restore CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes).
+            }
     }
     }
 
 
     public static List<Dictionary<string, string>> CsvToDictionaryList(IFileSystem fs, string csvFile, string delimiter = ",")
     public static List<Dictionary<string, string>> CsvToDictionaryList(IFileSystem fs, string csvFile, string delimiter = ",")
@@ -137,7 +139,7 @@ public static class CsvUtils
         List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
         List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
         using (StreamReader streamReader = new StreamReader(csvFile))
         using (StreamReader streamReader = new StreamReader(csvFile))
         {
         {
-            string[] array = ParseCsvLine(streamReader.ReadLine(), delimiter);
+            string[]? array = ParseCsvLine(streamReader.ReadLine(), delimiter);
             if (array == null)
             if (array == null)
             {
             {
                 return list;
                 return list;
@@ -145,7 +147,7 @@ public static class CsvUtils
 
 
             while (!streamReader.EndOfStream)
             while (!streamReader.EndOfStream)
             {
             {
-                string[] array2 = ParseCsvLine(streamReader.ReadLine(), delimiter);
+                string[]? array2 = ParseCsvLine(streamReader.ReadLine(), delimiter);
                 if (array2 != null)
                 if (array2 != null)
                 {
                 {
                     Dictionary<string, string> dictionary = new Dictionary<string, string>();
                     Dictionary<string, string> dictionary = new Dictionary<string, string>();

+ 227 - 0
FormLabelPrint.Designer.cs

@@ -0,0 +1,227 @@
+namespace qdr.app.studiou.orders2printpack
+{
+    partial class FormLabelPrint
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormLabelPrint));
+            butOpenCsv = new Button();
+            butOpenXls = new Button();
+            butGenerate = new Button();
+            label1 = new Label();
+            tbCsvPath = new TextBox();
+            tbXslxPath = new TextBox();
+            label2 = new Label();
+            butConfig = new Button();
+            groupBox1 = new GroupBox();
+            lParRow = new Label();
+            lParCol = new Label();
+            lParCount = new Label();
+            butClose = new Button();
+            dlgOpenCsv = new OpenFileDialog();
+            dlgSaveXls = new SaveFileDialog();
+            groupBox1.SuspendLayout();
+            SuspendLayout();
+            // 
+            // butOpenCsv
+            // 
+            butOpenCsv.Location = new Point(12, 12);
+            butOpenCsv.Name = "butOpenCsv";
+            butOpenCsv.Size = new Size(142, 47);
+            butOpenCsv.TabIndex = 0;
+            butOpenCsv.Text = "1. Otevři CSV soubor";
+            butOpenCsv.UseVisualStyleBackColor = true;
+            butOpenCsv.Click += butOpenCsv_Click;
+            // 
+            // butOpenXls
+            // 
+            butOpenXls.Location = new Point(160, 12);
+            butOpenXls.Name = "butOpenXls";
+            butOpenXls.Size = new Size(142, 47);
+            butOpenXls.TabIndex = 1;
+            butOpenXls.Text = "2. Výstupní XSLX soubor";
+            butOpenXls.UseVisualStyleBackColor = true;
+            butOpenXls.Click += butOpenXls_Click;
+            // 
+            // butGenerate
+            // 
+            butGenerate.BackColor = Color.FromArgb(192, 255, 192);
+            butGenerate.Location = new Point(308, 12);
+            butGenerate.Name = "butGenerate";
+            butGenerate.Size = new Size(142, 47);
+            butGenerate.TabIndex = 2;
+            butGenerate.Text = "3. Generuj";
+            butGenerate.UseVisualStyleBackColor = false;
+            butGenerate.Click += butGenerate_Click;
+            // 
+            // label1
+            // 
+            label1.AutoSize = true;
+            label1.Location = new Point(14, 62);
+            label1.Name = "label1";
+            label1.Size = new Size(87, 15);
+            label1.TabIndex = 3;
+            label1.Text = "Vstupní soubor";
+            // 
+            // tbCsvPath
+            // 
+            tbCsvPath.Location = new Point(14, 80);
+            tbCsvPath.Name = "tbCsvPath";
+            tbCsvPath.Size = new Size(436, 23);
+            tbCsvPath.TabIndex = 4;
+            // 
+            // tbXslxPath
+            // 
+            tbXslxPath.Location = new Point(14, 125);
+            tbXslxPath.Name = "tbXslxPath";
+            tbXslxPath.Size = new Size(436, 23);
+            tbXslxPath.TabIndex = 6;
+            // 
+            // label2
+            // 
+            label2.AutoSize = true;
+            label2.Location = new Point(14, 107);
+            label2.Name = "label2";
+            label2.Size = new Size(93, 15);
+            label2.TabIndex = 5;
+            label2.Text = "Výstupní soubor";
+            // 
+            // butConfig
+            // 
+            butConfig.Location = new Point(351, 162);
+            butConfig.Name = "butConfig";
+            butConfig.Size = new Size(99, 29);
+            butConfig.TabIndex = 7;
+            butConfig.Text = "Konfigurace";
+            butConfig.UseVisualStyleBackColor = true;
+            butConfig.Click += butConfig_Click;
+            // 
+            // groupBox1
+            // 
+            groupBox1.Controls.Add(lParRow);
+            groupBox1.Controls.Add(lParCol);
+            groupBox1.Controls.Add(lParCount);
+            groupBox1.Location = new Point(12, 154);
+            groupBox1.Name = "groupBox1";
+            groupBox1.Size = new Size(200, 134);
+            groupBox1.TabIndex = 8;
+            groupBox1.TabStop = false;
+            groupBox1.Text = "Parametry";
+            // 
+            // lParRow
+            // 
+            lParRow.AutoSize = true;
+            lParRow.Location = new Point(15, 52);
+            lParRow.Name = "lParRow";
+            lParRow.Size = new Size(131, 15);
+            lParRow.TabIndex = 2;
+            lParRow.Text = "Štítků řádků na stránku:";
+            // 
+            // lParCol
+            // 
+            lParCol.AutoSize = true;
+            lParCol.Location = new Point(15, 37);
+            lParCol.Name = "lParCol";
+            lParCol.Size = new Size(96, 15);
+            lParCol.TabIndex = 1;
+            lParCol.Text = "Štítků ve sloupci:";
+            // 
+            // lParCount
+            // 
+            lParCount.AutoSize = true;
+            lParCount.Location = new Point(15, 22);
+            lParCount.Name = "lParCount";
+            lParCount.Size = new Size(92, 15);
+            lParCount.TabIndex = 0;
+            lParCount.Text = "Štítků/záznamů:";
+            // 
+            // butClose
+            // 
+            butClose.Location = new Point(351, 259);
+            butClose.Name = "butClose";
+            butClose.Size = new Size(99, 29);
+            butClose.TabIndex = 9;
+            butClose.Text = "Zavřít";
+            butClose.UseVisualStyleBackColor = true;
+            butClose.Click += butClose_Click;
+            // 
+            // dlgOpenCsv
+            // 
+            dlgOpenCsv.Filter = "CSV files|*.csv";
+            dlgOpenCsv.Title = "Otevři CSV soubor s daty pro štítky";
+            // 
+            // dlgSaveXls
+            // 
+            dlgSaveXls.Filter = "Xlsx Excel soubor|*.xlsx";
+            dlgSaveXls.Title = "Vyber výstupní soubor Xlsx štítků";
+            // 
+            // FormLabelPrint
+            // 
+            AutoScaleDimensions = new SizeF(7F, 15F);
+            AutoScaleMode = AutoScaleMode.Font;
+            ClientSize = new Size(465, 309);
+            Controls.Add(butClose);
+            Controls.Add(groupBox1);
+            Controls.Add(butConfig);
+            Controls.Add(tbXslxPath);
+            Controls.Add(label2);
+            Controls.Add(tbCsvPath);
+            Controls.Add(label1);
+            Controls.Add(butGenerate);
+            Controls.Add(butOpenXls);
+            Controls.Add(butOpenCsv);
+            FormBorderStyle = FormBorderStyle.FixedSingle;
+            Icon = (Icon)resources.GetObject("$this.Icon");
+            MaximizeBox = false;
+            MinimizeBox = false;
+            Name = "FormLabelPrint";
+            Text = "Tisk štítků";
+            groupBox1.ResumeLayout(false);
+            groupBox1.PerformLayout();
+            ResumeLayout(false);
+            PerformLayout();
+        }
+
+        #endregion
+
+        private Button butOpenCsv;
+        private Button butOpenXls;
+        private Button butGenerate;
+        private Label label1;
+        private TextBox tbCsvPath;
+        private TextBox tbXslxPath;
+        private Label label2;
+        private Button butConfig;
+        private GroupBox groupBox1;
+        private Label lParRow;
+        private Label lParCol;
+        private Label lParCount;
+        private Button butClose;
+        private OpenFileDialog dlgOpenCsv;
+        private SaveFileDialog dlgSaveXls;
+    }
+}

+ 109 - 0
FormLabelPrint.cs

@@ -0,0 +1,109 @@
+using qdr.app.studiou.orders2printpack.Extensions;
+using qdr.app.studiou.orders2printpack.Labels;
+using qdr.app.studiou.orders2printpack.Properties;
+using System.Data;
+using System.IO.Abstractions;
+
+namespace qdr.app.studiou.orders2printpack
+{
+    public partial class FormLabelPrint : Form
+    {
+
+        private string? _csvPath;
+        private string? _xlsPath;
+
+        private DataTable? _data;
+
+        public FormLabelPrint()
+        {
+            InitializeComponent();
+        }
+
+
+        #region *** Form Handlers *** 
+        private void butOpenCsv_Click(object sender, EventArgs e)
+        {
+            BlockErrorHandled(() =>
+            {
+                if (dlgOpenCsv.ShowDialog(this) == DialogResult.OK)
+                {
+                    _csvPath = dlgOpenCsv.FileName;
+                    tbCsvPath.Text = _csvPath;
+
+                    _data = CsvUtils.CsvToDataTable(new FileSystem(), _csvPath, AppSettings.Default.CSVDelimiter );
+
+                    RefreshParameters();
+                }
+            });
+        }
+
+        private void butOpenXls_Click(object sender, EventArgs e)
+        {
+            BlockErrorHandled(() =>
+            {
+                if (dlgSaveXls.ShowDialog(this) == DialogResult.OK)
+                {
+                    _xlsPath = dlgSaveXls.FileName;
+                    tbXslxPath.Text = _csvPath;
+                }
+            });
+        }
+
+        private void butGenerate_Click(object sender, EventArgs e)
+        {
+            BlockErrorHandled(() =>
+            {
+                if (string.IsNullOrEmpty(_csvPath)) throw new Exception($"Vstupní CSV soubor musí být vybrán.");
+                if (string.IsNullOrEmpty(_xlsPath)) throw new Exception($"Výstupní XSLX soubor musí být vybrán.");
+                if (!File.Exists(_csvPath)) throw new Exception($"Vstupní CSV soubor '{_csvPath}' neexistuje, vyberte existující soubor.");
+                if (_data == null) throw new Exception($"Vstupní CSV soubor '{_csvPath}' musí být otevřen.");
+
+                var generator = new ExcelLabelGenerator(AppSettings.Default.LabelTemplate.Replace("{cr}","\n"));
+
+                if (generator.GenerateLabels(_data, _xlsPath, int.Parse(AppSettings.Default.LabelPerRow), int.Parse(AppSettings.Default.LabelPerCol), double.Parse(AppSettings.Default.LabelWidth), double.Parse(AppSettings.Default.LabelHeight)))
+                    MessageBox.Show(this, $"Výstupní soubor '{_xlsPath}' byl vygenerován.", "Export", MessageBoxButtons.OK, MessageBoxIcon.Information);
+                
+                RefreshParameters();
+            });
+        }
+
+        private void butConfig_Click(object sender, EventArgs e)
+        {
+            var dlg = new dlgLabelSettings();
+            if (dlg.ShowDialog(this) == DialogResult.OK)
+            {
+                // Save settings
+                RefreshParameters();
+            }
+        }
+
+        private void butClose_Click(object sender, EventArgs e)
+        {
+            Close();
+        }
+        #endregion
+
+
+        #region *** Private Methods ***
+        private void RefreshParameters()
+        {
+            lParCount.Text = $"Štítků/záznamů: {_data?.Rows.Count}";
+            lParCol.Text = $"Štítků ve sloupci: {AppSettings.Default.LabelPerCol}";
+            lParRow.Text = $"Štítků řádků na stránku: {AppSettings.Default.LabelPerRow}";
+        }
+
+        private void BlockErrorHandled(Action block)
+        {
+            try
+            {
+                block();
+            }
+            catch (Exception ex)
+            {
+                // Log("Error: " + ex.Message);
+                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            }
+        }
+        #endregion
+    }
+}

+ 222 - 0
FormLabelPrint.resx

@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="dlgOpenCsv.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="dlgSaveXls.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>183, 17</value>
+  </metadata>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQ
+        AADDDgAAww4AAAAAAAAAAAAAjIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/iYmJ/6Ghof/Y2Nj/u7u7/46Ojv/Gxsb/yMjI/42N
+        jf+ysrL/1tbW/6Wlpf+JiYn/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+Kior/lJSU/+zs7P/29vb/pqam/+np
+        6f/s7Oz/mpqa//Dw8P/z8/P/mZmZ/4qKiv+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+JiYn/ysrK//7+
+        /v/Hx8f/5+fn/+vr6/++vr7//////8/Pz/+Ghob/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4mJ
+        if+jo6P/+fn5/+np6f/t7e3/8fHx/+3t7f/39/f/oKCg/4mJif+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4qKiv/a2tr///////z8/P/+/v7//////9nZ2f+MjIz/i4uL/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uLi/+MjIz/jIyM/4yM
+        jP+Li4v/ioqK/4qKiv+JiYn/iIiI/9DQ0P//////////////////////0tLS/4qKiv+JiYn/iYmJ/4mJ
+        if+Li4v/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/i4uL/4yM
+        jP+MjIz/ioqK/5iYmP+kpKT/pKSk/6Kiov+urq7/9vb2///////////////////////z8/P/ra2t/6Ki
+        ov+lpaX/paWl/5qamv+Kior/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+Li4v/jIyM/4mJif+xsbH/8/Pz//n5+f/4+Pj/+Pj4//n5+f//////////////////////////////
+        ///5+fn/+Pj4//j4+P/5+fn/9PT0/7e3t/+JiYn/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/ioqK/9jY2P/////////////////////////////////r6+v/1NTU/9TU
+        1P/q6ur//v7+////////////////////////////2tra/4uLi/+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/39/f////////////////////////////1dXV/5ub
+        m/+Ghob/h4eH/5mZmf/U1NT////////////////////////////e3t7/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uLi//e3t7//////////////////////+Pj
+        4/+Pj4//mJiY/7+/v/+/v7//mJiY/42Njf/n5+f//////////////////////97e3v+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uLi/+MjIz/i4uL/+Dg4P//////////////
+        ///+/v7/ubm5/5GRkf/g4OD////////////j4+P/lJSU/7Kysv/+/v7/////////////////39/f/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/i4uL/4yMjP+Kior/ycnJ/+7u
+        7v/r6+v/7e3t/+Li4v+UlJT/vLy8///////////////////////CwsL/kJCQ/9vb2//u7u7/7Ozs/+3t
+        7f/Ly8v/i4uL/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+Li4v/jIyM/4yM
+        jP+MjIz/j4+P/42Njf+Pj4//i4uL/4aGhv/R0dH//////////////////////9XV1f+JiYn/i4uL/4+P
+        j/+Ojo7/jo6O/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uL
+        i/+MjIz/i4uL/76+vv/d3d3/2tra/9zc3P/Q0ND/jY2N/8bGxv//////////////////////zMzM/42N
+        jf/Kysr/3d3d/9vb2//d3d3/wMDA/4uLi/+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+Li4v/39/f//////////////////v7+/+rq6v/nZ2d//Ly8v////////////X1
+        9f+jo6P/o6Oj//n5+f/////////////////f39//jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uLi//e3t7//////////////////////9HR0f+Ghob/tbW1/+fn
+        5//m5ub/uLi4/4SEhP/Pz8////////Hx8f/Jycn/7u7u/+Dg4P+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/9/f3///////////////////////9/f3/7u7
+        u/+Ghob/jo6O/42Njf+EhIT/ubm5//n5+f//////0dHR/3t7e/++vr7/39/f/42Njf+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+Li4v/3d3d////////////////////
+        ////////+fn5/9XV1f+zs7P/s7Oz/9PT0//39/f////////////f39//i4uL/9LS0v/f39//jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4mJif/Dw8P//Pz8//39
+        /f/9/f3//f39//7+/v////////////r6+v/6+vr////////////+/v7//f39//r6+v/r6+v/9/f3/8jI
+        yP+Kior/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/i4uL/5KS
+        kv+zs7P/u7u7/7u7u/+7u7v/y8vL//z8/P//////////////////////+vr6/8nJyf+5ubn/vb29/8DA
+        wP+2trb/lJSU/4uLi/+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/i4uL/4qKiv+JiYn/iYmJ/4iIiP+Tk5P/6enp//r6+v/4+Pj/+Pj4//r6+v/g4OD/kJCQ/4iI
+        iP+Kior/ioqK/4qKiv+Li4v/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uLi/+ZmZn/o6Oj/6CgoP+hoaH/o6Oj/5iY
+        mP+Li4v/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4qKiv+Kior/ioqK/4qK
+        iv+Kior/i4uL/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAABAAAAAgAAAAAQAgAAAA
+        AAAABAAAww4AAMMOAAAAAAAAAAAAAIyMjP+MjIz/jIyM/4yMjP+MjIz/i4uL/4qKiv+JiYn/iYmJ/4qK
+        iv+Li4v/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/i4uL/4aGhv9/f3//fX19/319
+        ff9/f3//hoaG/4qKiv+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4mJif+JiYn//////7m5
+        uf+1tbX//////42Njf+JiYn/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4uLi/+Ghob/dXV1//Dw
+        8P/u7u7/8PDw//Dw8P90dHT/hoaG/4uLi/+MjIz/jIyM/4yMjP+MjIz/jIyM/4qKiv+FhYX/enp6/2tr
+        a/+YmJj///////////+ampr/ampq/3p6ev+FhYX/ioqK/4yMjP+MjIz/jIyM/4uLi/+FhYX/hoaG/9jY
+        2P/Q0ND/9PT0////////////8vLy/9DQ0P/Z2dn/iYmJ/4aGhv+Li4v/jIyM/4yMjP+Kior/gYGB/7S0
+        tP////////////////+cnJz/m5ub/////////////////7S0tP+BgYH/ioqK/4yMjP+MjIz/ioqK/4CA
+        gP+1tbX///////////+Pj4//yMjI/8rKyv+Ojo7///////////+1tbX/gICA/4qKiv+MjIz/jIyM/4qK
+        iv+BgYH/iIiI/7Kysv+np6f/ioqK////////////jo6O/6Wlpf+zs7P/ioqK/4KCgv+Kior/jIyM/4yM
+        jP+Kior/gYGB/6enp///////+vr6/4KCgv///////////4aGhv/8/Pz//////6ysrP+CgoL/ioqK/4yM
+        jP+MjIz/ioqK/4CAgP+zs7P///////////+vr6//ioqK/4qKiv+xsbH//////7Kysv+9vb3/gYGB/4qK
+        iv+MjIz/jIyM/4uLi/+Dg4P/q6ur/////////////////+fn5//n5+f////////////g4OD/tra2/4SE
+        hP+Li4v/jIyM/4yMjP+Li4v/iIiI/39/f/+VlZX/jY2N/9vb2////////////9XV1f+RkZH/np6e/4OD
+        g/+IiIj/i4uL/4yMjP+MjIz/jIyM/4uLi/+IiIj/hISE/39/f/98fHz/hISE/4SEhP99fX3/f39//4WF
+        hf+JiYn/i4uL/4yMjP+MjIz/jIyM/4yMjP+MjIz/i4uL/4uLi/+Kior/iIiI/4aGhv+Ghob/iIiI/4qK
+        iv+Li4v/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP+Li4v/i4uL/4yM
+        jP+MjIz/jIyM/4yMjP+MjIz/jIyM/4yMjP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+</value>
+  </data>
+</root>

+ 28 - 2
FormLauncher.Designer.cs

@@ -33,6 +33,8 @@
             butFormBatch = new Button();
             butFormBatch = new Button();
             butProductEdit = new Button();
             butProductEdit = new Button();
             butResetCfg = new Button();
             butResetCfg = new Button();
+            butLabalPrint = new Button();
+            lVersion = new Label();
             ((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
             ((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
             SuspendLayout();
             SuspendLayout();
             // 
             // 
@@ -69,7 +71,7 @@
             // 
             // 
             // butResetCfg
             // butResetCfg
             // 
             // 
-            butResetCfg.Location = new Point(390, 75);
+            butResetCfg.Location = new Point(390, 116);
             butResetCfg.Name = "butResetCfg";
             butResetCfg.Name = "butResetCfg";
             butResetCfg.Size = new Size(72, 25);
             butResetCfg.Size = new Size(72, 25);
             butResetCfg.TabIndex = 4;
             butResetCfg.TabIndex = 4;
@@ -77,11 +79,32 @@
             butResetCfg.UseVisualStyleBackColor = true;
             butResetCfg.UseVisualStyleBackColor = true;
             butResetCfg.Click += butResetCfg_Click;
             butResetCfg.Click += butResetCfg_Click;
             // 
             // 
+            // butLabalPrint
+            // 
+            butLabalPrint.Location = new Point(209, 75);
+            butLabalPrint.Name = "butLabalPrint";
+            butLabalPrint.Size = new Size(253, 27);
+            butLabalPrint.TabIndex = 5;
+            butLabalPrint.Text = "Tisk štítků";
+            butLabalPrint.UseVisualStyleBackColor = true;
+            butLabalPrint.Click += butLabalPrint_Click;
+            // 
+            // lVersion
+            // 
+            lVersion.AutoSize = true;
+            lVersion.Location = new Point(10, 130);
+            lVersion.Name = "lVersion";
+            lVersion.Size = new Size(70, 15);
+            lVersion.TabIndex = 6;
+            lVersion.Text = "App.Version";
+            // 
             // FormLauncher
             // FormLauncher
             // 
             // 
             AutoScaleDimensions = new SizeF(7F, 15F);
             AutoScaleDimensions = new SizeF(7F, 15F);
             AutoScaleMode = AutoScaleMode.Font;
             AutoScaleMode = AutoScaleMode.Font;
-            ClientSize = new Size(478, 109);
+            ClientSize = new Size(477, 154);
+            Controls.Add(lVersion);
+            Controls.Add(butLabalPrint);
             Controls.Add(butResetCfg);
             Controls.Add(butResetCfg);
             Controls.Add(butProductEdit);
             Controls.Add(butProductEdit);
             Controls.Add(butFormBatch);
             Controls.Add(butFormBatch);
@@ -96,6 +119,7 @@
             Load += FormLauncher_Load;
             Load += FormLauncher_Load;
             ((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
             ((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
             ResumeLayout(false);
             ResumeLayout(false);
+            PerformLayout();
         }
         }
 
 
         #endregion
         #endregion
@@ -104,5 +128,7 @@
         private Button butFormBatch;
         private Button butFormBatch;
         private Button butProductEdit;
         private Button butProductEdit;
         private Button butResetCfg;
         private Button butResetCfg;
+        private Button butLabalPrint;
+        private Label lVersion;
     }
     }
 }
 }

+ 10 - 1
FormLauncher.cs

@@ -3,6 +3,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.ComponentModel;
 using System.Data;
 using System.Data;
+using System.Diagnostics;
 using System.Drawing;
 using System.Drawing;
 using System.Linq;
 using System.Linq;
 using System.Text;
 using System.Text;
@@ -21,6 +22,8 @@ namespace qdr.app.studiou.orders2printpack
         private void FormLauncher_Load(object sender, EventArgs e)
         private void FormLauncher_Load(object sender, EventArgs e)
         {
         {
             Text = $"{Application.ProductName} v{Application.ProductVersion}";
             Text = $"{Application.ProductName} v{Application.ProductVersion}";
+            lVersion.Text = $"Verze: {Application.ProductVersion}";
+           
         }
         }
 
 
         private void butFormBatch_Click(object sender, EventArgs e)
         private void butFormBatch_Click(object sender, EventArgs e)
@@ -34,7 +37,7 @@ namespace qdr.app.studiou.orders2printpack
             var form = new FormProductEdit();
             var form = new FormProductEdit();
             form.Show(this);
             form.Show(this);
         }
         }
-        
+
         private void butResetCfg_Click(object sender, EventArgs e)
         private void butResetCfg_Click(object sender, EventArgs e)
         {
         {
             AppSettings.Default.Reset();
             AppSettings.Default.Reset();
@@ -42,5 +45,11 @@ namespace qdr.app.studiou.orders2printpack
             AppSettings.Default.Save();
             AppSettings.Default.Save();
             MessageBox.Show("Konfigurace nastavena do výchozího nastavení.", "Reset konfigurace", MessageBoxButtons.OK, MessageBoxIcon.Information);
             MessageBox.Show("Konfigurace nastavena do výchozího nastavení.", "Reset konfigurace", MessageBoxButtons.OK, MessageBoxIcon.Information);
         }
         }
+
+        private void butLabalPrint_Click(object sender, EventArgs e)
+        {
+            var form = new FormLabelPrint();
+            form.Show(this);
+        }
     }
     }
 }
 }

+ 843 - 0
Labels/ExcelLabelGenerator.cs

@@ -0,0 +1,843 @@
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml;
+using System.Data;
+using System.Text.RegularExpressions;
+using Font = DocumentFormat.OpenXml.Spreadsheet.Font;
+using Color = DocumentFormat.OpenXml.Spreadsheet.Color;
+
+namespace qdr.app.studiou.orders2printpack.Labels
+{
+    /// <summary>
+    /// Generates Excel documents for printing labels using OpenXML format
+    /// without relying on Microsoft Office libraries.
+    /// </summary>
+    public class ExcelLabelGenerator
+    {
+        // Default row height in points
+        private const double DEFAULT_ROW_HEIGHT = 15.0;
+
+        // Border styles
+        private const int BORDER_STYLE_ID = 1;
+
+        // Template pattern to match column names
+        private static readonly Regex TemplatePattern = new Regex(@"\{([^{}]+)\}", RegexOptions.Compiled);
+
+        // Formatting patterns
+        private static readonly Regex BoldPattern = new Regex(@"\*\*(.+?)\*\*", RegexOptions.Compiled);
+        private static readonly Regex ItalicPattern = new Regex(@"__(.+?)__", RegexOptions.Compiled);
+        private static readonly Regex UnderlinePattern = new Regex(@"_(.+?)_", RegexOptions.Compiled);
+        private static readonly Regex FontSizePattern = new Regex(@"\^\^(\d+)\^(.*?)\^\^", RegexOptions.Compiled);
+
+        // Style indexes for different formatting
+        private const int STYLE_NORMAL = 0;
+        private const int STYLE_BORDER = 1;
+        private const int STYLE_BOLD = 2;
+        private const int STYLE_ITALIC = 3;
+        private const int STYLE_UNDERLINE = 4;
+        private const int STYLE_BOLD_BORDER = 5;
+        private const int STYLE_ITALIC_BORDER = 6;
+        private const int STYLE_UNDERLINE_BORDER = 7;
+
+        // Font size style indexes start at 8 and go up
+        private const int STYLE_FONT_SIZE_START = 8;
+
+        /// <summary>
+        /// Label format template that will be used to generate the content of each label.
+        /// Use {columnName} placeholders to reference DataTable columns.
+        /// Example: "ID: {ID}\nName: {ProductName}\nPrice: ${Price}"
+        /// </summary>
+        private readonly string _labelTemplate;
+
+        /// <summary>
+        /// Initializes a new instance of the ExcelLabelGenerator class with a specific label template.
+        /// </summary>
+        /// <param name="labelTemplate">Template string with {columnName} placeholders</param>
+        public ExcelLabelGenerator(string labelTemplate)
+        {
+            _labelTemplate = labelTemplate ?? throw new ArgumentNullException(nameof(labelTemplate));
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the ExcelLabelGenerator class with a default template.
+        /// The default template will simply concatenate all column values.
+        /// </summary>
+        public ExcelLabelGenerator()
+        {
+            _labelTemplate = string.Empty;
+        }
+
+        /// <summary>
+        /// Generates an Excel document with labels formatted according to specified layout
+        /// </summary>
+        /// <param name="data">DataTable containing the label data</param>
+        /// <param name="outputPath">Path where the Excel file will be saved</param>
+        /// <param name="columnsPerPage">Number of label columns per A4 page</param>
+        /// <param name="rowsPerPage">Number of label rows per A4 page</param>
+        /// <param name="labelWidthPt">Width of each label in points</param>
+        /// <param name="labelHeightPt">Height of each label in points</param>
+        /// <returns>True if generation was successful, otherwise false</returns>
+        public bool GenerateLabels(
+            DataTable data,
+            string outputPath,
+            int columnsPerPage,
+            int rowsPerPage,
+            double labelWidthPt = 200.0,
+            double labelHeightPt = 120.0)
+        {
+            if (data == null || data.Rows.Count == 0)
+                throw new ArgumentException("Data table cannot be null or empty");
+
+            if (columnsPerPage <= 0 || rowsPerPage <= 0)
+                throw new ArgumentException("Columns and rows per page must be greater than zero");
+
+            try
+            {
+                // Create the Excel document
+                using (SpreadsheetDocument document = SpreadsheetDocument.Create(outputPath, SpreadsheetDocumentType.Workbook))
+                {
+                    // Add a WorkbookPart to the document
+                    WorkbookPart workbookPart = document.AddWorkbookPart();
+                    workbookPart.Workbook = new Workbook();
+
+                    // Add styles to the workbook
+                    WorkbookStylesPart stylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
+                    stylesPart.Stylesheet = CreateStylesheet();
+                    stylesPart.Stylesheet.Save();
+
+                    // Add a WorksheetPart to the WorkbookPart
+                    WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
+                    worksheetPart.Worksheet = new Worksheet(new SheetData());
+
+                    // Add Sheets to the Workbook
+                    Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
+
+                    // Add a Sheet to the Sheets collection
+                    Sheet sheet = new Sheet()
+                    {
+                        Id = workbookPart.GetIdOfPart(worksheetPart),
+                        SheetId = 1,
+                        Name = "Labels"
+                    };
+                    sheets.Append(sheet);
+
+                    // Get the SheetData from the WorksheetPart
+                    var sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
+
+                    // Configure page layout for A4
+                    PageSetup pageSetup = new PageSetup
+                    {
+                        PaperSize = (UInt32Value)9U, // A4 paper size
+                        Orientation = OrientationValues.Portrait,
+                        FitToWidth = 1,
+                        FitToHeight = 0 // Auto height
+                    };
+
+                    PageMargins pageMargins = new PageMargins
+                    {
+                        Top = 0.75D,
+                        Bottom = 0.75D,
+                        Left = 0.7D,
+                        Right = 0.7D,
+                        Header = 0.3D,
+                        Footer = 0.3D
+                    };
+
+                    // Add page setup and margins
+                    worksheetPart.Worksheet.AppendChild(pageSetup);
+                    worksheetPart.Worksheet.AppendChild(pageMargins);
+
+                    // Set column widths based on the fixed label width
+                    Columns columns = new Columns();
+
+                    // Convert points to Excel column width
+                    // Excel column width units are based on the width of the "0" (zero) character in the default font
+                    // The conversion is approximate but works for most cases
+                    double excelColumnWidth = labelWidthPt / 7.0; // Approximate conversion
+
+                    for (int i = 1; i <= columnsPerPage; i++)
+                    {
+                        columns.Append(new Column
+                        {
+                            Min = (uint)i,
+                            Max = (uint)i,
+                            Width = excelColumnWidth,
+                            CustomWidth = true
+                        });
+                    }
+
+                    worksheetPart.Worksheet.InsertBefore(columns, sheetData);
+
+                    // Process each row of data
+                    Dictionary<uint, Row> rows = new Dictionary<uint, Row>();
+
+                    for (int dataIndex = 0; dataIndex < data.Rows.Count; dataIndex++)
+                    {
+                        // Calculate the label position on the page
+                        int pageCol = dataIndex % columnsPerPage + 1;
+                        int pageRow = dataIndex / columnsPerPage % rowsPerPage + 1;
+
+                        // Calculate actual row in Excel - one cell per label
+                        int excelRowIndex = dataIndex / columnsPerPage / rowsPerPage * rowsPerPage + pageRow;
+                        uint rowIndex = (uint)excelRowIndex;
+
+                        // Ensure row exists
+                        if (!rows.ContainsKey(rowIndex))
+                        {
+                            Row row = new Row
+                            {
+                                RowIndex = rowIndex,
+                                Height = labelHeightPt,
+                                CustomHeight = true
+                            };
+                            rows.Add(rowIndex, row);
+                        }
+
+                        string columnLetter = ColumnIndexToLetters(pageCol);
+
+                        // Create content for the label using the template with newlines
+                        string labelContent = GenerateLabelContent(data.Rows[dataIndex]);
+
+                        // Add cell with border style and content
+                        Cell cell = CreateCell(columnLetter, rowIndex, labelContent, BORDER_STYLE_ID);
+
+                        rows[rowIndex].Append(cell);
+                    }
+
+                    // Add all rows to the sheet
+                    foreach (var row in rows.Values.OrderBy(r => r.RowIndex))
+                    {
+                        sheetData?.Append(row);
+                    }
+
+                    // Save the worksheet
+                    worksheetPart.Worksheet.Save();
+
+                    // Save the workbook
+                    workbookPart.Workbook.Save();
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error generating Excel labels: {ex.Message}");
+                return false;
+            }
+        }
+
+
+
+        /// <summary>
+        /// Gets or creates a style for a specific font size
+        /// </summary>
+        /// <param name="fontSize">Font size in points</param>
+        /// <param name="withBorder">Whether to include a border</param>
+        /// <returns>Style index</returns>
+        private uint GetFontSizeStyle(int fontSize, bool withBorder)
+        {
+            // We'll use a simple formula to calculate the style index
+            // STYLE_FONT_SIZE_START + (fontSize * 2) for no border
+            // STYLE_FONT_SIZE_START + (fontSize * 2) + 1 for with border
+
+            int styleOffset = fontSize * 2 + (withBorder ? 1 : 0);
+            uint styleIndex = (uint)(STYLE_FONT_SIZE_START + styleOffset);
+
+            // Return the style index - we'll ensure the style exists when creating the stylesheet
+            return styleIndex;
+        }
+
+        /// <summary>
+        /// Parses text for style markers and removes them from the text
+        /// Handles nested formatting (e.g. _**text**_ for bold and underlined)
+        /// </summary>
+        /// <param name="text">Text to parse, will be modified to remove markers</param>
+        /// <returns>TextStyle object with detected formatting</returns>
+        private TextStyle ParseTextStyle(ref string text)
+        {
+            TextStyle style = new TextStyle();
+            bool madeChanges;
+
+            // We need to repeat the pattern matching until no more changes are made
+            // This handles nested formatting like _**text**_
+            do
+            {
+                madeChanges = false;
+
+                // Check for bold
+                if (BoldPattern.IsMatch(text))
+                {
+                    style.IsBold = true;
+                    string newText = BoldPattern.Replace(text, "$1");
+                    if (newText != text)
+                    {
+                        text = newText;
+                        madeChanges = true;
+                    }
+                }
+
+                // Check for italic
+                if (ItalicPattern.IsMatch(text))
+                {
+                    style.IsItalic = true;
+                    string newText = ItalicPattern.Replace(text, "$1");
+                    if (newText != text)
+                    {
+                        text = newText;
+                        madeChanges = true;
+                    }
+                }
+
+                // Check for underline
+                if (UnderlinePattern.IsMatch(text))
+                {
+                    style.IsUnderlined = true;
+                    string newText = UnderlinePattern.Replace(text, "$1");
+                    if (newText != text)
+                    {
+                        text = newText;
+                        madeChanges = true;
+                    }
+                }
+            } while (madeChanges);
+
+            return style;
+        }
+
+        /// <summary>
+        /// Represents text formatting style
+        /// </summary>
+        private class TextStyle
+        {
+            public bool IsBold { get; set; }
+            public bool IsItalic { get; set; }
+            public bool IsUnderlined { get; set; }
+
+            public bool HasFormatting => IsBold || IsItalic || IsUnderlined;
+        }
+
+        /// <summary>
+        /// The key update is to the CreateCell method and ensuring all cell formats
+        /// have WrapText = true properly set. Also ensuring the alignment is properly
+        /// applied to each cell format.
+        /// </summary>
+        private Cell CreateCell(string columnName, uint rowIndex, string text, uint? styleIndex = null)
+        {
+            // Create the cell
+            Cell cell = new Cell
+            {
+                CellReference = $"{columnName}{rowIndex}",
+                DataType = CellValues.InlineString,
+                StyleIndex = styleIndex ?? STYLE_NORMAL
+            };
+
+            // Create the inline string that will hold our text with preserved formatting
+            InlineString inlineString = new InlineString();
+
+            // We need to handle each line of text separately while preserving the newlines
+            string[] lines = text.Split(new[] { '\n' }, StringSplitOptions.None);
+
+            for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++)
+            {
+                string line = lines[lineIndex];
+
+                // Check if this is not the first line, we need to add a line break
+                if (lineIndex > 0)
+                {
+                    // For line breaks in Excel, we need to add a line feed character
+                    // within the same text run, not as a separate Break element
+                    Run lineBreakRun = new Run();
+                    lineBreakRun.AppendChild(new Text
+                    {
+                        Text = "\n",
+                        Space = SpaceProcessingModeValues.Preserve
+                    });
+                    inlineString.AppendChild(lineBreakRun);
+                }
+
+                // Process the current line
+                // This can contain formatting markers like bold, italic, etc.
+                string remainingText = line;
+
+                // First check for font size formatting
+                while (FontSizePattern.IsMatch(remainingText))
+                {
+                    Match match = FontSizePattern.Match(remainingText);
+
+                    // Add text before the font size marker if any
+                    if (match.Index > 0)
+                    {
+                        string beforeText = remainingText.Substring(0, match.Index);
+                        TextStyle beforeStyle = ParseTextStyle(ref beforeText);
+
+                        AddFormattedRun(inlineString, beforeText, beforeStyle);
+                    }
+
+                    // Handle the font-sized text
+                    int fontSize;
+                    if (int.TryParse(match.Groups[1].Value, out fontSize))
+                    {
+                        string fontSizeText = match.Groups[2].Value;
+                        TextStyle fontSizeStyle = ParseTextStyle(ref fontSizeText);
+
+                        // Create a run with font size and any other formatting
+                        Run fontSizeRun = new Run();
+                        RunProperties fontSizeProps = new RunProperties();
+                        fontSizeProps.AppendChild(new FontSize { Val = fontSize });
+
+                        if (fontSizeStyle.IsBold)
+                            fontSizeProps.AppendChild(new Bold());
+                        if (fontSizeStyle.IsItalic)
+                            fontSizeProps.AppendChild(new Italic());
+                        if (fontSizeStyle.IsUnderlined)
+                            fontSizeProps.AppendChild(new Underline { Val = UnderlineValues.Single });
+
+                        fontSizeRun.AppendChild(fontSizeProps);
+                        fontSizeRun.AppendChild(new Text
+                        {
+                            Text = fontSizeText,
+                            Space = SpaceProcessingModeValues.Preserve
+                        });
+
+                        inlineString.AppendChild(fontSizeRun);
+                    }
+
+                    // Move past the processed part
+                    remainingText = remainingText.Substring(match.Index + match.Length);
+                }
+
+                // Process any remaining text in this line if any
+                if (!string.IsNullOrEmpty(remainingText))
+                {
+                    TextStyle remainingStyle = ParseTextStyle(ref remainingText);
+                    AddFormattedRun(inlineString, remainingText, remainingStyle);
+                }
+            }
+
+            cell.AppendChild(inlineString);
+            return cell;
+        }
+
+        /// <summary>
+        /// Helper method to add a run with the specified formatting
+        /// </summary>
+        private void AddFormattedRun(InlineString inlineString, string text, TextStyle style)
+        {
+            if (string.IsNullOrEmpty(text))
+                return;
+
+            Run run = new Run();
+
+            if (style.HasFormatting)
+            {
+                RunProperties props = new RunProperties();
+
+                if (style.IsBold)
+                    props.AppendChild(new Bold());
+                if (style.IsItalic)
+                    props.AppendChild(new Italic());
+                if (style.IsUnderlined)
+                    props.AppendChild(new Underline { Val = UnderlineValues.Single });
+
+                run.AppendChild(props);
+            }
+
+            run.AppendChild(new Text
+            {
+                Text = text,
+                Space = SpaceProcessingModeValues.Preserve
+            });
+
+            inlineString.AppendChild(run);
+        }
+
+        /// <summary>
+        /// This is a key modification to ensure ALL cell formats have WrapText=true
+        /// </summary>
+        private Stylesheet CreateStylesheet()
+        {
+            Stylesheet stylesheet = new Stylesheet();
+
+            // Create Fonts
+            Fonts fonts = new Fonts();
+
+            // Font 0: Normal (11pt)
+            Font normalFont = new Font();
+            normalFont.AppendChild(new FontSize { Val = 11D });
+            fonts.Append(normalFont);
+
+            // Font 1: Bold (11pt)
+            Font boldFont = new Font();
+            boldFont.AppendChild(new FontSize { Val = 11D });
+            boldFont.Append(new Bold());
+            fonts.Append(boldFont);
+
+            // Font 2: Italic (11pt)
+            Font italicFont = new Font();
+            italicFont.AppendChild(new FontSize { Val = 11D });
+            italicFont.Append(new Italic());
+            fonts.Append(italicFont);
+
+            // Font 3: Underline (11pt)
+            Font underlineFont = new Font();
+            underlineFont.AppendChild(new FontSize { Val = 11D });
+            underlineFont.Append(new Underline() { Val = UnderlineValues.Single });
+            fonts.Append(underlineFont);
+
+            // Add font sizes from 8pt to 72pt
+            for (int size = 8; size <= 72; size++)
+            {
+                // Regular font with custom size
+                Font sizedFont = new Font();
+                sizedFont.AppendChild(new FontSize { Val = (double)size });
+                fonts.Append(sizedFont);
+            }
+
+            fonts.Count = (uint)fonts.ChildElements.Count;
+
+            // Create Fills
+            Fills fills = new Fills();
+            Fill fill1 = new Fill();
+            fill1.PatternFill = new PatternFill { PatternType = PatternValues.None };
+            Fill fill2 = new Fill();
+            fill2.PatternFill = new PatternFill { PatternType = PatternValues.Gray125 };
+            fills.Append(fill1);
+            fills.Append(fill2);
+            fills.Count = (uint)fills.ChildElements.Count;
+
+            // Create Borders
+            Borders borders = new Borders();
+
+            // Border 0: No border
+            Border noBorder = new Border();
+            borders.Append(noBorder);
+
+            // Border 1: All sides
+            Border allBorder = new Border();
+
+            // Left Border
+            LeftBorder leftBorder = new LeftBorder { Style = BorderStyleValues.Thin };
+            leftBorder.Append(new Color { Auto = true });
+            allBorder.Append(leftBorder);
+
+            // Right Border
+            RightBorder rightBorder = new RightBorder { Style = BorderStyleValues.Thin };
+            rightBorder.Append(new Color { Auto = true });
+            allBorder.Append(rightBorder);
+
+            // Top Border
+            TopBorder topBorder = new TopBorder { Style = BorderStyleValues.Thin };
+            topBorder.Append(new Color { Auto = true });
+            allBorder.Append(topBorder);
+
+            // Bottom Border
+            BottomBorder bottomBorder = new BottomBorder { Style = BorderStyleValues.Thin };
+            bottomBorder.Append(new Color { Auto = true });
+            allBorder.Append(bottomBorder);
+
+            // Diagonal Border (blank)
+            allBorder.Append(new DiagonalBorder());
+
+            borders.Append(allBorder);
+            borders.Count = (uint)borders.ChildElements.Count;
+
+            // Create CellFormats
+            CellFormats cellFormats = new CellFormats();
+
+            // *** CRITICALLY IMPORTANT: All cell formats must have WrapText=true ***
+
+            // Format 0: Default / Normal
+            CellFormat format0 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 0,
+                FillId = 0,
+                BorderId = 0,
+                FormatId = 0,
+                ApplyAlignment = true
+            };
+            format0.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format0);
+
+            // Format 1: Border only
+            CellFormat format1 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 0,
+                FillId = 0,
+                BorderId = 1,
+                FormatId = 0,
+                ApplyBorder = true,
+                ApplyAlignment = true
+            };
+            format1.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format1);
+
+            // Format 2: Bold
+            CellFormat format2 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 1,
+                FillId = 0,
+                BorderId = 0,
+                FormatId = 0,
+                ApplyFont = true,
+                ApplyAlignment = true
+            };
+            format2.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format2);
+
+            // Format 3: Italic
+            CellFormat format3 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 2,
+                FillId = 0,
+                BorderId = 0,
+                FormatId = 0,
+                ApplyFont = true,
+                ApplyAlignment = true
+            };
+            format3.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format3);
+
+            // Format 4: Underline
+            CellFormat format4 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 3,
+                FillId = 0,
+                BorderId = 0,
+                FormatId = 0,
+                ApplyFont = true,
+                ApplyAlignment = true
+            };
+            format4.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format4);
+
+            // Format 5: Bold + Border
+            CellFormat format5 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 1,
+                FillId = 0,
+                BorderId = 1,
+                FormatId = 0,
+                ApplyFont = true,
+                ApplyBorder = true,
+                ApplyAlignment = true
+            };
+            format5.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format5);
+
+            // Format 6: Italic + Border
+            CellFormat format6 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 2,
+                FillId = 0,
+                BorderId = 1,
+                FormatId = 0,
+                ApplyFont = true,
+                ApplyBorder = true,
+                ApplyAlignment = true
+            };
+            format6.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format6);
+
+            // Format 7: Underline + Border
+            CellFormat format7 = new CellFormat
+            {
+                NumberFormatId = 0,
+                FontId = 3,
+                FillId = 0,
+                BorderId = 1,
+                FormatId = 0,
+                ApplyFont = true,
+                ApplyBorder = true,
+                ApplyAlignment = true
+            };
+            format7.AppendChild(new Alignment
+            {
+                Vertical = VerticalAlignmentValues.Center,
+                Horizontal = HorizontalAlignmentValues.Left,
+                WrapText = true,
+                Indent = 1,    // Left indent for text margin
+                JustifyLastLine = false
+            });
+            cellFormats.Append(format7);
+
+            cellFormats.Count = (uint)cellFormats.ChildElements.Count;
+
+            // Add additional cell formats for font sizes 8pt to 72pt
+            // Both with and without borders
+            for (int size = 8; size <= 72; size++)
+            {
+                int fontIndex = 4 + (size - 8); // Font indexes start after our 4 basic fonts
+
+                // Create style without border
+                CellFormat formatSize = new CellFormat
+                {
+                    NumberFormatId = 0,
+                    FontId = (uint)fontIndex,
+                    FillId = 0,
+                    BorderId = 0,
+                    FormatId = 0,
+                    ApplyFont = true,
+                    ApplyAlignment = true
+                };
+                formatSize.AppendChild(new Alignment
+                {
+                    Vertical = VerticalAlignmentValues.Center,
+                    Horizontal = HorizontalAlignmentValues.Left,
+                    WrapText = true,
+                    Indent = 1,
+                    JustifyLastLine = false
+                });
+                cellFormats.Append(formatSize);
+
+                // Create style with border
+                CellFormat formatSizeBorder = new CellFormat
+                {
+                    NumberFormatId = 0,
+                    FontId = (uint)fontIndex,
+                    FillId = 0,
+                    BorderId = 1,
+                    FormatId = 0,
+                    ApplyFont = true,
+                    ApplyBorder = true,
+                    ApplyAlignment = true
+                };
+                formatSizeBorder.AppendChild(new Alignment
+                {
+                    Vertical = VerticalAlignmentValues.Center,
+                    Horizontal = HorizontalAlignmentValues.Left,
+                    WrapText = true,
+                    Indent = 1,
+                    JustifyLastLine = false
+                });
+                cellFormats.Append(formatSizeBorder);
+            }
+
+            cellFormats.Count = (uint)cellFormats.ChildElements.Count;
+
+            stylesheet.Append(fonts);
+            stylesheet.Append(fills);
+            stylesheet.Append(borders);
+            stylesheet.Append(cellFormats);
+
+            return stylesheet;
+        }
+
+        /// <summary>
+        /// Generates the content for a label based on the template and data row
+        /// </summary>
+        /// <param name="dataRow">The DataRow containing the label data</param>
+        /// <returns>String representing the label content with newlines</returns>
+        private string GenerateLabelContent(DataRow dataRow)
+        {
+            string result;
+
+            if (string.IsNullOrEmpty(_labelTemplate))
+            {
+                // Default behavior: use column name and value for each column
+                List<string> lines = new List<string>();
+                foreach (DataColumn column in dataRow.Table.Columns)
+                {
+                    object value = dataRow[column.ColumnName];
+                    string lineContent = $"{column.ColumnName}: {(value != DBNull.Value ? value?.ToString() : string.Empty)}";
+                    lines.Add(lineContent);
+                }
+
+                result = string.Join("\n", lines);
+            }
+            else
+            {
+                // Use the specified template
+                result = _labelTemplate;
+
+                // Replace all column placeholders with actual values
+                result = TemplatePattern.Replace(result, match =>
+                {
+                    string columnName = match.Groups[1].Value;
+
+                    if (dataRow.Table.Columns.Contains(columnName))
+                    {
+                        object value = dataRow[columnName];
+                        return value != DBNull.Value ? value?.ToString() ?? string.Empty : string.Empty;
+                    }
+
+                    return match.Value; // Keep the placeholder if column not found
+                });
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// Converts a column index to Excel column letters (e.g., 1 = A, 27 = AA)
+        /// </summary>
+        private string ColumnIndexToLetters(int columnIndex)
+        {
+            string columnLetters = string.Empty;
+
+            while (columnIndex > 0)
+            {
+                int remainder = (columnIndex - 1) % 26;
+                columnLetters = (char)('A' + remainder) + columnLetters;
+                columnIndex = (columnIndex - 1) / 26;
+            }
+
+            return columnLetters;
+        }
+    }
+}

+ 1 - 1
ProductStorage/ProductStorage.cs

@@ -115,7 +115,7 @@ namespace qdr.app.studiou.orders2printpack.ProductStorage
                 if (!_rawCollection.Any(x => string.Equals(x.Sku, parentSku, StringComparison.InvariantCultureIgnoreCase)))
                 if (!_rawCollection.Any(x => string.Equals(x.Sku, parentSku, StringComparison.InvariantCultureIgnoreCase)))
                     throw new Exception($"Parent Product SKU '{parentSku}' not found!");
                     throw new Exception($"Parent Product SKU '{parentSku}' not found!");
 
 
-            var item = new ProductDto() {Type = ProductDto.CS_ITEM_TYPE_VARIANT, ParentName = parentSku};
+            var item = new ProductDto() {Type = ProductDto.CS_ITEM_TYPE_VARIANT, ParentName = parentSku == null ? string.Empty : parentSku};
 
 
             _rawCollection.Add(item);
             _rawCollection.Add(item);
             return item;
             return item;

+ 134 - 73
Properties/AppSettings.Designer.cs

@@ -12,7 +12,7 @@ namespace qdr.app.studiou.orders2printpack.Properties {
     
     
     
     
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.11.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.13.0.0")]
     internal sealed partial class AppSettings : global::System.Configuration.ApplicationSettingsBase {
     internal sealed partial class AppSettings : global::System.Configuration.ApplicationSettingsBase {
         
         
         private static AppSettings defaultInstance = ((AppSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new AppSettings())));
         private static AppSettings defaultInstance = ((AppSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new AppSettings())));
@@ -23,18 +23,6 @@ namespace qdr.app.studiou.orders2printpack.Properties {
             }
             }
         }
         }
         
         
-        [global::System.Configuration.UserScopedSettingAttribute()]
-        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute(",")]
-        public string CSVDelimiter {
-            get {
-                return ((string)(this["CSVDelimiter"]));
-            }
-            set {
-                this["CSVDelimiter"] = value;
-            }
-        }
-        
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.DefaultSettingValueAttribute("")]
         [global::System.Configuration.DefaultSettingValueAttribute("")]
@@ -47,54 +35,6 @@ namespace qdr.app.studiou.orders2printpack.Properties {
             }
             }
         }
         }
         
         
-        [global::System.Configuration.UserScopedSettingAttribute()]
-        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Order No")]
-        public string MapColOrderNo {
-            get {
-                return ((string)(this["MapColOrderNo"]));
-            }
-            set {
-                this["MapColOrderNo"] = value;
-            }
-        }
-        
-        [global::System.Configuration.UserScopedSettingAttribute()]
-        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Prod Cat")]
-        public string MapColProductCat {
-            get {
-                return ((string)(this["MapColProductCat"]));
-            }
-            set {
-                this["MapColProductCat"] = value;
-            }
-        }
-        
-        [global::System.Configuration.UserScopedSettingAttribute()]
-        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Prod Img Url")]
-        public string MapColUri {
-            get {
-                return ((string)(this["MapColUri"]));
-            }
-            set {
-                this["MapColUri"] = value;
-            }
-        }
-        
-        [global::System.Configuration.UserScopedSettingAttribute()]
-        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Qty")]
-        public string MapColQuantity {
-            get {
-                return ((string)(this["MapColQuantity"]));
-            }
-            set {
-                this["MapColQuantity"] = value;
-            }
-        }
-        
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.DefaultSettingValueAttribute("*.jpg")]
         [global::System.Configuration.DefaultSettingValueAttribute("*.jpg")]
@@ -107,18 +47,6 @@ namespace qdr.app.studiou.orders2printpack.Properties {
             }
             }
         }
         }
         
         
-        [global::System.Configuration.UserScopedSettingAttribute()]
-        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-        [global::System.Configuration.DefaultSettingValueAttribute("Prod Var Type")]
-        public string MapColProductFormat {
-            get {
-                return ((string)(this["MapColProductFormat"]));
-            }
-            set {
-                this["MapColProductFormat"] = value;
-            }
-        }
-        
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Configuration.UserScopedSettingAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.DefaultSettingValueAttribute("")]
         [global::System.Configuration.DefaultSettingValueAttribute("")]
@@ -239,5 +167,138 @@ namespace qdr.app.studiou.orders2printpack.Properties {
                 this["OutputFileMask"] = value;
                 this["OutputFileMask"] = value;
             }
             }
         }
         }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute(";")]
+        public string CSVDelimiter {
+            get {
+                return ((string)(this["CSVDelimiter"]));
+            }
+            set {
+                this["CSVDelimiter"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("order_no")]
+        public string MapColOrderNo {
+            get {
+                return ((string)(this["MapColOrderNo"]));
+            }
+            set {
+                this["MapColOrderNo"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("prod_cat")]
+        public string MapColProductCat {
+            get {
+                return ((string)(this["MapColProductCat"]));
+            }
+            set {
+                this["MapColProductCat"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("prod_img_url")]
+        public string MapColUri {
+            get {
+                return ((string)(this["MapColUri"]));
+            }
+            set {
+                this["MapColUri"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("qty")]
+        public string MapColQuantity {
+            get {
+                return ((string)(this["MapColQuantity"]));
+            }
+            set {
+                this["MapColQuantity"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("prod_var_type")]
+        public string MapColProductFormat {
+            get {
+                return ((string)(this["MapColProductFormat"]));
+            }
+            set {
+                this["MapColProductFormat"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("^^18^**Objednávka: {order_no}**^^{cr}^^14^**{prod_cat}**^^{cr}{prod_var_type}{cr}" +
+            "Počet: {qty\r\n}")]
+        public string LabelTemplate {
+            get {
+                return ((string)(this["LabelTemplate"]));
+            }
+            set {
+                this["LabelTemplate"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("200")]
+        public string LabelWidth {
+            get {
+                return ((string)(this["LabelWidth"]));
+            }
+            set {
+                this["LabelWidth"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("120")]
+        public string LabelHeight {
+            get {
+                return ((string)(this["LabelHeight"]));
+            }
+            set {
+                this["LabelHeight"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("3")]
+        public string LabelPerRow {
+            get {
+                return ((string)(this["LabelPerRow"]));
+            }
+            set {
+                this["LabelPerRow"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("8")]
+        public string LabelPerCol {
+            get {
+                return ((string)(this["LabelPerCol"]));
+            }
+            set {
+                this["LabelPerCol"] = value;
+            }
+        }
     }
     }
 }
 }

+ 34 - 18
Properties/AppSettings.settings

@@ -2,30 +2,12 @@
 <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="qdr.app.studiou.orders2printpack.Properties" GeneratedClassName="AppSettings">
 <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="qdr.app.studiou.orders2printpack.Properties" GeneratedClassName="AppSettings">
   <Profiles />
   <Profiles />
   <Settings>
   <Settings>
-    <Setting Name="CSVDelimiter" Type="System.String" Scope="User">
-      <Value Profile="(Default)">,</Value>
-    </Setting>
     <Setting Name="LastOutputDir" Type="System.String" Scope="User">
     <Setting Name="LastOutputDir" Type="System.String" Scope="User">
       <Value Profile="(Default)" />
       <Value Profile="(Default)" />
     </Setting>
     </Setting>
-    <Setting Name="MapColOrderNo" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Order No</Value>
-    </Setting>
-    <Setting Name="MapColProductCat" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Prod Cat</Value>
-    </Setting>
-    <Setting Name="MapColUri" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Prod Img Url</Value>
-    </Setting>
-    <Setting Name="MapColQuantity" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Qty</Value>
-    </Setting>
     <Setting Name="SourceSearchPattern" Type="System.String" Scope="User">
     <Setting Name="SourceSearchPattern" Type="System.String" Scope="User">
       <Value Profile="(Default)">*.jpg</Value>
       <Value Profile="(Default)">*.jpg</Value>
     </Setting>
     </Setting>
-    <Setting Name="MapColProductFormat" Type="System.String" Scope="User">
-      <Value Profile="(Default)">Prod Var Type</Value>
-    </Setting>
     <Setting Name="LastSourceDir" Type="System.String" Scope="User">
     <Setting Name="LastSourceDir" Type="System.String" Scope="User">
       <Value Profile="(Default)" />
       <Value Profile="(Default)" />
     </Setting>
     </Setting>
@@ -57,5 +39,39 @@
     <Setting Name="OutputFileMask" Type="System.String" Scope="User">
     <Setting Name="OutputFileMask" Type="System.String" Scope="User">
       <Value Profile="(Default)">{prod_var_type}\{order_no}_{prod_name}_{ordinal}{ext}</Value>
       <Value Profile="(Default)">{prod_var_type}\{order_no}_{prod_name}_{ordinal}{ext}</Value>
     </Setting>
     </Setting>
+    <Setting Name="CSVDelimiter" Type="System.String" Scope="User">
+      <Value Profile="(Default)">;</Value>
+    </Setting>
+    <Setting Name="MapColOrderNo" Type="System.String" Scope="User">
+      <Value Profile="(Default)">order_no</Value>
+    </Setting>
+    <Setting Name="MapColProductCat" Type="System.String" Scope="User">
+      <Value Profile="(Default)">prod_cat</Value>
+    </Setting>
+    <Setting Name="MapColUri" Type="System.String" Scope="User">
+      <Value Profile="(Default)">prod_img_url</Value>
+    </Setting>
+    <Setting Name="MapColQuantity" Type="System.String" Scope="User">
+      <Value Profile="(Default)">qty</Value>
+    </Setting>
+    <Setting Name="MapColProductFormat" Type="System.String" Scope="User">
+      <Value Profile="(Default)">prod_var_type</Value>
+    </Setting>
+    <Setting Name="LabelTemplate" Type="System.String" Scope="User">
+      <Value Profile="(Default)">^^18^**Objednávka: {order_no}**^^{cr}^^14^**{prod_cat}**^^{cr}{prod_var_type}{cr}Počet: {qty
+}</Value>
+    </Setting>
+    <Setting Name="LabelWidth" Type="System.String" Scope="User">
+      <Value Profile="(Default)">200</Value>
+    </Setting>
+    <Setting Name="LabelHeight" Type="System.String" Scope="User">
+      <Value Profile="(Default)">120</Value>
+    </Setting>
+    <Setting Name="LabelPerRow" Type="System.String" Scope="User">
+      <Value Profile="(Default)">3</Value>
+    </Setting>
+    <Setting Name="LabelPerCol" Type="System.String" Scope="User">
+      <Value Profile="(Default)">8</Value>
+    </Setting>
   </Settings>
   </Settings>
 </SettingsFile>
 </SettingsFile>

+ 4 - 0
README.md

@@ -4,6 +4,10 @@ Proprietální řešení zpracování WooCommerce objednávek pro online tiskovo
 
 
 ## Changelog
 ## Changelog
 
 
+### 1.2.0 (2025-03-13)
+- Upgrade na .NET 9.0
+- Přidána podpora pro tisk štítků podle importovaného .CSV do xlsx (Excel)
+
 ### 1.1.1 (2025-03-13)
 ### 1.1.1 (2025-03-13)
 - Opraveno, Nový a Uložit otevře dialog pro uložení
 - Opraveno, Nový a Uložit otevře dialog pro uložení
 - Oprava importu produktů, měsíc importu v Url je formátován na dvě číslice
 - Oprava importu produktů, měsíc importu v Url je formátován na dvě číslice

+ 4 - 4
Setup/Setup.vdproj

@@ -198,15 +198,15 @@
         {
         {
         "Name" = "8:Microsoft Visual Studio"
         "Name" = "8:Microsoft Visual Studio"
         "ProductName" = "8:Order2PrintPack"
         "ProductName" = "8:Order2PrintPack"
-        "ProductCode" = "8:{03E8C3D9-DAFC-4219-8379-8E099C457110}"
-        "PackageCode" = "8:{752CBDEB-B891-4C85-BA95-B4122249BD29}"
+        "ProductCode" = "8:{6C91447D-8838-4610-BA8A-459AFE932E81}"
+        "PackageCode" = "8:{22834C86-369C-4B27-B4F0-B50D173BDBA3}"
         "UpgradeCode" = "8:{38F8DC1E-8290-49ED-A3D2-32BC6DD74325}"
         "UpgradeCode" = "8:{38F8DC1E-8290-49ED-A3D2-32BC6DD74325}"
         "AspNetVersion" = "8:2.0.50727.0"
         "AspNetVersion" = "8:2.0.50727.0"
         "RestartWWWService" = "11:FALSE"
         "RestartWWWService" = "11:FALSE"
         "RemovePreviousVersions" = "11:TRUE"
         "RemovePreviousVersions" = "11:TRUE"
         "DetectNewerInstalledVersion" = "11:TRUE"
         "DetectNewerInstalledVersion" = "11:TRUE"
         "InstallAllUsers" = "11:FALSE"
         "InstallAllUsers" = "11:FALSE"
-        "ProductVersion" = "8:1.1.1"
+        "ProductVersion" = "8:1.2.0"
         "Manufacturer" = "8:Quadarax"
         "Manufacturer" = "8:Quadarax"
         "ARPHELPTELEPHONE" = "8:"
         "ARPHELPTELEPHONE" = "8:"
         "ARPHELPLINK" = "8:"
         "ARPHELPLINK" = "8:"
@@ -734,7 +734,7 @@
         {
         {
             "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_401EDA760B6F46889C1BF580F3C37DBF"
             "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_401EDA760B6F46889C1BF580F3C37DBF"
             {
             {
-            "SourcePath" = "8:..\\obj\\Debug\\net8.0-windows\\apphost.exe"
+            "SourcePath" = "8:..\\obj\\x64\\Debug\\net9.0-windows7.0\\apphost.exe"
             "TargetName" = "8:"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_96DC0B7F01834A1BA713E7E8A0904D3E"
             "Folder" = "8:_96DC0B7F01834A1BA713E7E8A0904D3E"

+ 226 - 0
dlgLabelSettings.Designer.cs

@@ -0,0 +1,226 @@
+namespace qdr.app.studiou.orders2printpack
+{
+    partial class dlgLabelSettings
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            butOk = new Button();
+            butCancel = new Button();
+            label1 = new Label();
+            tbTemplate = new TextBox();
+            label2 = new Label();
+            label3 = new Label();
+            label4 = new Label();
+            tbLPerCol = new TextBox();
+            tbLPerRow = new TextBox();
+            label5 = new Label();
+            tbLWidth = new TextBox();
+            label6 = new Label();
+            tbLHeight = new TextBox();
+            label7 = new Label();
+            label8 = new Label();
+            SuspendLayout();
+            // 
+            // butOk
+            // 
+            butOk.DialogResult = DialogResult.OK;
+            butOk.Location = new Point(12, 176);
+            butOk.Name = "butOk";
+            butOk.Size = new Size(75, 23);
+            butOk.TabIndex = 0;
+            butOk.Text = "Ok";
+            butOk.UseVisualStyleBackColor = true;
+            butOk.Click += butOk_Click;
+            // 
+            // butCancel
+            // 
+            butCancel.DialogResult = DialogResult.Cancel;
+            butCancel.Location = new Point(405, 176);
+            butCancel.Name = "butCancel";
+            butCancel.Size = new Size(75, 23);
+            butCancel.TabIndex = 1;
+            butCancel.Text = "Zrušit";
+            butCancel.UseVisualStyleBackColor = true;
+            butCancel.Click += butCancel_Click;
+            // 
+            // label1
+            // 
+            label1.AutoSize = true;
+            label1.Location = new Point(12, 9);
+            label1.Name = "label1";
+            label1.Size = new Size(81, 15);
+            label1.TabIndex = 2;
+            label1.Text = "Šablona štítku";
+            // 
+            // tbTemplate
+            // 
+            tbTemplate.Location = new Point(12, 27);
+            tbTemplate.Multiline = true;
+            tbTemplate.Name = "tbTemplate";
+            tbTemplate.Size = new Size(360, 70);
+            tbTemplate.TabIndex = 3;
+            // 
+            // label2
+            // 
+            label2.AutoSize = true;
+            label2.Location = new Point(385, 11);
+            label2.Name = "label2";
+            label2.Size = new Size(100, 120);
+            label2.TabIndex = 4;
+            label2.Text = "Použité proměné:\r\norder_no\r\nprod_cat\r\nprod_name\r\nprod_var\r\nprod_var_type\r\nprod_img_url\r\nqty";
+            // 
+            // label3
+            // 
+            label3.AutoSize = true;
+            label3.Location = new Point(12, 100);
+            label3.Name = "label3";
+            label3.Size = new Size(95, 15);
+            label3.TabIndex = 5;
+            label3.Text = "Štítků na stránku";
+            // 
+            // label4
+            // 
+            label4.AutoSize = true;
+            label4.Location = new Point(12, 116);
+            label4.Name = "label4";
+            label4.Size = new Size(66, 15);
+            label4.TabIndex = 6;
+            label4.Text = "Na sloupec";
+            // 
+            // tbLPerCol
+            // 
+            tbLPerCol.Location = new Point(12, 134);
+            tbLPerCol.Name = "tbLPerCol";
+            tbLPerCol.Size = new Size(66, 23);
+            tbLPerCol.TabIndex = 7;
+            // 
+            // tbLPerRow
+            // 
+            tbLPerRow.Location = new Point(84, 134);
+            tbLPerRow.Name = "tbLPerRow";
+            tbLPerRow.Size = new Size(66, 23);
+            tbLPerRow.TabIndex = 9;
+            // 
+            // label5
+            // 
+            label5.AutoSize = true;
+            label5.Location = new Point(84, 116);
+            label5.Name = "label5";
+            label5.Size = new Size(55, 15);
+            label5.TabIndex = 8;
+            label5.Text = "Na řádku";
+            // 
+            // tbLWidth
+            // 
+            tbLWidth.Location = new Point(305, 134);
+            tbLWidth.Name = "tbLWidth";
+            tbLWidth.Size = new Size(66, 23);
+            tbLWidth.TabIndex = 14;
+            // 
+            // label6
+            // 
+            label6.AutoSize = true;
+            label6.Location = new Point(305, 116);
+            label6.Name = "label6";
+            label6.Size = new Size(32, 15);
+            label6.TabIndex = 13;
+            label6.Text = "Šířka";
+            // 
+            // tbLHeight
+            // 
+            tbLHeight.Location = new Point(233, 134);
+            tbLHeight.Name = "tbLHeight";
+            tbLHeight.Size = new Size(66, 23);
+            tbLHeight.TabIndex = 12;
+            // 
+            // label7
+            // 
+            label7.AutoSize = true;
+            label7.Location = new Point(233, 116);
+            label7.Name = "label7";
+            label7.Size = new Size(37, 15);
+            label7.TabIndex = 11;
+            label7.Text = "Výška";
+            // 
+            // label8
+            // 
+            label8.AutoSize = true;
+            label8.Location = new Point(233, 100);
+            label8.Name = "label8";
+            label8.Size = new Size(85, 15);
+            label8.TabIndex = 10;
+            label8.Text = "Dimenze štítků";
+            // 
+            // dlgLabelSettings
+            // 
+            AutoScaleDimensions = new SizeF(7F, 15F);
+            AutoScaleMode = AutoScaleMode.Font;
+            ClientSize = new Size(491, 210);
+            Controls.Add(tbLWidth);
+            Controls.Add(label6);
+            Controls.Add(tbLHeight);
+            Controls.Add(label7);
+            Controls.Add(label8);
+            Controls.Add(tbLPerRow);
+            Controls.Add(label5);
+            Controls.Add(tbLPerCol);
+            Controls.Add(label4);
+            Controls.Add(label3);
+            Controls.Add(label2);
+            Controls.Add(tbTemplate);
+            Controls.Add(label1);
+            Controls.Add(butCancel);
+            Controls.Add(butOk);
+            FormBorderStyle = FormBorderStyle.FixedDialog;
+            MaximizeBox = false;
+            MinimizeBox = false;
+            Name = "dlgLabelSettings";
+            Text = "Nastavení štítků";
+            Load += dlgLabelSettings_Load;
+            ResumeLayout(false);
+            PerformLayout();
+        }
+
+        #endregion
+
+        private Button butOk;
+        private Button butCancel;
+        private Label label1;
+        private TextBox tbTemplate;
+        private Label label2;
+        private Label label3;
+        private Label label4;
+        private TextBox tbLPerCol;
+        private TextBox tbLPerRow;
+        private Label label5;
+        private TextBox tbLWidth;
+        private Label label6;
+        private TextBox tbLHeight;
+        private Label label7;
+        private Label label8;
+    }
+}

+ 44 - 0
dlgLabelSettings.cs

@@ -0,0 +1,44 @@
+using qdr.app.studiou.orders2printpack.Properties;
+
+namespace qdr.app.studiou.orders2printpack
+{
+    public partial class dlgLabelSettings : Form
+    {
+        public dlgLabelSettings()
+        {
+            InitializeComponent();
+        }
+
+        #region *** Form Handler ***
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
+        private void dlgLabelSettings_Load(object sender, EventArgs e)
+        {
+            tbTemplate.Text = AppSettings.Default.LabelTemplate;
+            tbLPerCol.Text = AppSettings.Default.LabelPerCol;
+            tbLPerRow.Text = AppSettings.Default.LabelPerRow;
+            tbLWidth.Text = AppSettings.Default.LabelWidth;
+            tbLHeight.Text = AppSettings.Default.LabelHeight;
+
+        }
+
+
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
+        private void butOk_Click(object sender, EventArgs e)
+        {
+            AppSettings.Default.LabelTemplate = tbTemplate.Text;
+            AppSettings.Default.LabelPerCol = tbLPerCol.Text;
+            AppSettings.Default.LabelPerRow = tbLPerRow.Text;
+             AppSettings.Default.LabelWidth = tbLWidth.Text;
+            AppSettings.Default.LabelHeight =tbLHeight.Text ;
+            AppSettings.Default.Save();
+            Close();
+        }
+
+        #endregion
+
+        private void butCancel_Click(object sender, EventArgs e)
+        {
+            Close();
+        }
+    }
+}

+ 120 - 0
dlgLabelSettings.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 6 - 5
qdr.app.studiou.orders2printpack.csproj

@@ -2,7 +2,7 @@
 
 
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>WinExe</OutputType>
     <OutputType>WinExe</OutputType>
-    <TargetFramework>net8.0-windows</TargetFramework>
+    <TargetFramework>net9.0-windows7.0</TargetFramework>
     <Nullable>enable</Nullable>
     <Nullable>enable</Nullable>
     <UseWindowsForms>true</UseWindowsForms>
     <UseWindowsForms>true</UseWindowsForms>
     <ImplicitUsings>enable</ImplicitUsings>
     <ImplicitUsings>enable</ImplicitUsings>
@@ -16,9 +16,9 @@
     <SignAssembly>True</SignAssembly>
     <SignAssembly>True</SignAssembly>
     <AssemblyOriginatorKeyFile>bo_strong_key_pair.snk</AssemblyOriginatorKeyFile>
     <AssemblyOriginatorKeyFile>bo_strong_key_pair.snk</AssemblyOriginatorKeyFile>
     <Platforms>AnyCPU;x86;x64</Platforms>
     <Platforms>AnyCPU;x86;x64</Platforms>
-    <AssemblyVersion>1.1.1.0</AssemblyVersion>
-    <FileVersion>1.1.1.0</FileVersion>
-    <Version>1.1.1</Version>
+    <AssemblyVersion>1.2.0.0</AssemblyVersion>
+    <FileVersion>1.2.0.0</FileVersion>
+    <Version>1.2.0</Version>
 	<ForceDesignerDpiUnaware>true</ForceDesignerDpiUnaware>
 	<ForceDesignerDpiUnaware>true</ForceDesignerDpiUnaware>
   </PropertyGroup>
   </PropertyGroup>
 
 
@@ -34,7 +34,8 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="qdr.fnd.core" Version="0.0.5-alpha" />
+    <PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
+    <PackageReference Include="qdr.fnd.core" Version="0.0.8-alpha" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>