From 75fb3df2b6e19adf561784e8ed31ad3ee5ac4fb4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 13:55:26 +0000 Subject: [PATCH 1/6] Initial plan From c8f38992021b901b36d234332c3778549f15b354 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 13:59:17 +0000 Subject: [PATCH 2/6] Add Tutorials 01-04: Basic Table, HTML Formatting, Colors, Alignment Co-authored-by: quodlibetbv <220320055+quodlibetbv@users.noreply.github.com> --- .../tutorial/Tutorial01_BasicTable.java | 137 +++++++++ .../tutorial/Tutorial02_HtmlFormatting.java | 160 +++++++++++ .../Tutorial03_ColorsAndTransparency.java | 243 ++++++++++++++++ .../tutorial/Tutorial04_Alignment.java | 264 ++++++++++++++++++ 4 files changed, 804 insertions(+) create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial02_HtmlFormatting.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial03_ColorsAndTransparency.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java new file mode 100644 index 0000000..fb86dd5 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java @@ -0,0 +1,137 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 01: Basic Table Creation + * + * This tutorial demonstrates: + * - Creating a simple PDF table + * - Adding header rows with styling + * - Creating data rows + * - Basic cell styling (colors, fonts, alignment) + * - Saving the PDF document + */ +public class Tutorial01_BasicTable { + + @Test + public void createBasicTable() throws IOException { + // Step 1: Initialize PDF Document and Page + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Step 2: Define table dimensions and margins + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Step 3: Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Step 4: Create a title row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 01: Basic Table Creation"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(41, 128, 185)); // Blue background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Step 5: Create a description row + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "This table demonstrates basic table creation, headers, and cell styling."); + descCell.setFillColor(new Color(236, 240, 241)); // Light gray background + descCell.setAlign(HorizontalAlignment.CENTER); + + // Step 6: Create header row + Row headerRow = table.createRow(20f); + Cell headerCell1 = headerRow.createCell(25, "Product"); + Cell headerCell2 = headerRow.createCell(25, "Category"); + Cell headerCell3 = headerRow.createCell(25, "Price"); + Cell headerCell4 = headerRow.createCell(25, "Stock"); + + // Style header cells + Color headerColor = new Color(52, 152, 219); // Blue + Color headerTextColor = Color.WHITE; + for (Cell cell : headerRow.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(headerTextColor); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + cell.setAlign(HorizontalAlignment.CENTER); + } + + // Step 7: Add data rows with alternating colors + String[][] data = { + {"Laptop", "Electronics", "$999.99", "15"}, + {"Mouse", "Accessories", "$19.99", "120"}, + {"Keyboard", "Accessories", "$49.99", "85"}, + {"Monitor", "Electronics", "$299.99", "42"}, + {"USB Cable", "Accessories", "$9.99", "200"}, + {"Headphones", "Audio", "$79.99", "67"}, + {"Webcam", "Electronics", "$59.99", "33"}, + {"Desk Lamp", "Furniture", "$34.99", "58"} + }; + + Color lightGray = new Color(236, 240, 241); + Color white = Color.WHITE; + + for (int i = 0; i < data.length; i++) { + Row dataRow = table.createRow(15f); + + // Alternate row colors for better readability + Color rowColor = (i % 2 == 0) ? white : lightGray; + + Cell cell1 = dataRow.createCell(25, data[i][0]); + Cell cell2 = dataRow.createCell(25, data[i][1]); + Cell cell3 = dataRow.createCell(25, data[i][2]); + Cell cell4 = dataRow.createCell(25, data[i][3]); + + // Apply styling + for (Cell cell : dataRow.getCells()) { + cell.setFillColor(rowColor); + } + + // Right-align numeric columns + cell3.setAlign(HorizontalAlignment.RIGHT); + cell4.setAlign(HorizontalAlignment.RIGHT); + } + + // Step 8: Add a summary row + Row summaryRow = table.createRow(20f); + Cell summaryCell = summaryRow.createCell(100, + "Total Items: " + data.length); + summaryCell.setFillColor(new Color(46, 204, 113)); // Green background + summaryCell.setTextColor(Color.WHITE); + summaryCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + summaryCell.setAlign(HorizontalAlignment.CENTER); + + // Step 9: Draw the table + table.draw(); + + // Step 10: Save the document + File file = new File("target/tutorials/Tutorial01_BasicTable.pdf"); + System.out.println("Tutorial 01 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial02_HtmlFormatting.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial02_HtmlFormatting.java new file mode 100644 index 0000000..35566df --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial02_HtmlFormatting.java @@ -0,0 +1,160 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 02: HTML Formatting + * + * This tutorial demonstrates all supported HTML tags in Boxable: + * - Text formatting: , , , + * - Headings:

through

+ * - Superscript and subscript: , + * - Line breaks:
+ * - Paragraphs:

+ * - Lists:

    ,
      ,
    1. + * - Nested tags + */ +public class Tutorial02_HtmlFormatting { + + @Test + public void demonstrateHtmlFormatting() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 02: HTML Formatting"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(231, 76, 60)); // Red background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Boxable supports various HTML tags for rich text formatting."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Header Row + Row headerRow = table.createRow(15f); + Cell htmlHeader = headerRow.createCell(40, "HTML Code"); + Cell descHeader = headerRow.createCell(60, "Description"); + htmlHeader.setFillColor(new Color(52, 73, 94)); + descHeader.setFillColor(new Color(52, 73, 94)); + htmlHeader.setTextColor(Color.WHITE); + descHeader.setTextColor(Color.WHITE); + + // Text Formatting Examples + addExampleRow(table, "Bold text", "Makes text bold"); + addExampleRow(table, "Italic text", "Makes text italic"); + addExampleRow(table, "Underlined text", "Underlines text"); + addExampleRow(table, "Strikethrough text", "Strikes through text"); + + // Nested formatting + addExampleRow(table, "Bold and Italic", "Combines multiple styles"); + addExampleRow(table, "Bold Underlined", "Underlined bold text"); + + // Headings + addSectionHeader(table, "Heading Tags"); + addExampleRow(table, "

      Heading 1

      ", "Largest heading"); + addExampleRow(table, "

      Heading 2

      ", "Second-level heading"); + addExampleRow(table, "

      Heading 3

      ", "Third-level heading"); + addExampleRow(table, "
      Heading 6
      ", "Smallest heading"); + + // Superscript and Subscript (NEW FEATURES) + addSectionHeader(table, "Superscript and Subscript (New!)"); + addExampleRow(table, "H2O", "Water formula with subscript"); + addExampleRow(table, "x2 + y2", "Mathematical exponents"); + addExampleRow(table, "CO2", "Carbon dioxide formula"); + addExampleRow(table, "E=mc2", "Einstein's equation"); + addExampleRow(table, "Ani", "Combined super and subscript"); + + // Line Breaks and Paragraphs + addSectionHeader(table, "Line Breaks and Paragraphs"); + addExampleRow(table, "First line
      Second line
      Third line", + "Line breaks separate lines"); + addExampleRow(table, "

      First paragraph

      Second paragraph

      ", + "Paragraphs create vertical spacing"); + + // Lists + addSectionHeader(table, "Lists"); + addExampleRow(table, "
      • Item 1
      • Item 2
      • Item 3
      ", + "Unordered (bullet) list"); + addExampleRow(table, "
      1. First
      2. Second
      3. Third
      ", + "Ordered (numbered) list"); + + // Complex Nested Example + addSectionHeader(table, "Complex Nested Tags"); + addExampleRow(table, + "Bold with italic and underline", + "Multiple nested tags work together"); + addExampleRow(table, + "Underlined with superscript and subscript", + "Combines underline with super/subscripts"); + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial02_HtmlFormatting.pdf"); + System.out.println("Tutorial 02 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add an example row with alternating colors + */ + private void addExampleRow(BaseTable table, String htmlCode, String description) throws IOException { + Row row = table.createRow(15f); + Cell codeCell = row.createCell(40, htmlCode); + Cell descCell = row.createCell(60, description); + + // Alternate colors for readability + Color rowColor = (table.getRows().size() % 2 == 0) ? + Color.WHITE : new Color(236, 240, 241); + codeCell.setFillColor(rowColor); + descCell.setFillColor(rowColor); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(15f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(149, 165, 166)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial03_ColorsAndTransparency.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial03_ColorsAndTransparency.java new file mode 100644 index 0000000..5867fa9 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial03_ColorsAndTransparency.java @@ -0,0 +1,243 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 03: Colors and Transparency + * + * This tutorial demonstrates: + * - Setting cell fill colors (background) + * - Setting text colors + * - Using the alpha channel for transparency + * - Creating visual effects with color combinations + * - RGB and RGBA color specifications + */ +public class Tutorial03_ColorsAndTransparency { + + @Test + public void demonstrateColorsAndTransparency() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 03: Colors and Transparency"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(155, 89, 182)); // Purple background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Explore RGB colors, text colors, and alpha channel transparency effects."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Basic RGB Colors + addSectionHeader(table, "Basic RGB Colors"); + + Row rgbHeader = table.createRow(15f); + rgbHeader.createCell(25, "Color Name"); + rgbHeader.createCell(25, "RGB Values"); + rgbHeader.createCell(25, "Fill Color"); + rgbHeader.createCell(25, "Text Color"); + styleHeaderRow(rgbHeader); + + // Red + addColorRow(table, "Red", "255, 0, 0", + new Color(255, 0, 0), new Color(255, 0, 0)); + + // Green + addColorRow(table, "Green", "0, 255, 0", + new Color(0, 255, 0), new Color(0, 128, 0)); + + // Blue + addColorRow(table, "Blue", "0, 0, 255", + new Color(0, 0, 255), new Color(0, 0, 255)); + + // Yellow + addColorRow(table, "Yellow", "255, 255, 0", + new Color(255, 255, 0), new Color(184, 134, 11)); + + // Cyan + addColorRow(table, "Cyan", "0, 255, 255", + new Color(0, 255, 255), new Color(0, 139, 139)); + + // Magenta + addColorRow(table, "Magenta", "255, 0, 255", + new Color(255, 0, 255), new Color(139, 0, 139)); + + // Section 2: Transparency (Alpha Channel) + addSectionHeader(table, "Transparency with Alpha Channel"); + + Row alphaHeader = table.createRow(15f); + alphaHeader.createCell(25, "Description"); + alphaHeader.createCell(25, "Alpha Value"); + alphaHeader.createCell(50, "Visual Effect"); + styleHeaderRow(alphaHeader); + + // Demonstrate different alpha values + addAlphaRow(table, "Opaque Red", "255 (100%)", + new Color(255, 0, 0, 255)); + + addAlphaRow(table, "Semi-Transparent Red", "180 (70%)", + new Color(255, 0, 0, 180)); + + addAlphaRow(table, "Half-Transparent Red", "128 (50%)", + new Color(255, 0, 0, 128)); + + addAlphaRow(table, "Very Transparent Red", "50 (20%)", + new Color(255, 0, 0, 50)); + + // Section 3: Color Combinations + addSectionHeader(table, "Text and Background Color Combinations"); + + Row comboHeader = table.createRow(15f); + comboHeader.createCell(50, "Background Color"); + comboHeader.createCell(50, "Text Color Example"); + styleHeaderRow(comboHeader); + + addCombinationRow(table, new Color(41, 128, 185), Color.WHITE, "White on Blue"); + addCombinationRow(table, new Color(46, 204, 113), Color.BLACK, "Black on Green"); + addCombinationRow(table, new Color(241, 196, 15), Color.BLACK, "Black on Yellow"); + addCombinationRow(table, new Color(52, 73, 94), Color.WHITE, "White on Dark Gray"); + addCombinationRow(table, new Color(236, 240, 241), Color.BLACK, "Black on Light Gray"); + addCombinationRow(table, new Color(231, 76, 60), Color.WHITE, "White on Red"); + + // Section 4: Gradient-like effects + addSectionHeader(table, "Simulated Gradient Effect (Using Alpha)"); + + Row gradientDesc = table.createRow(15f); + Cell gradCell = gradientDesc.createCell(100, + "By varying alpha values, we can create gradient-like visual effects:"); + gradCell.setFillColor(Color.WHITE); + + // Create gradient effect with different alpha values + for (int i = 0; i <= 5; i++) { + int alpha = 255 - (i * 40); // Decreasing opacity + Row gradRow = table.createRow(12f); + Cell cell = gradRow.createCell(100, + String.format("Level %d - Alpha: %d", i + 1, alpha)); + cell.setFillColor(new Color(52, 152, 219, alpha)); + if (alpha < 150) { + cell.setTextColor(Color.BLACK); + } else { + cell.setTextColor(Color.WHITE); + } + } + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial03_ColorsAndTransparency.pdf"); + System.out.println("Tutorial 03 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } + + /** + * Helper method to add a color demonstration row + */ + private void addColorRow(BaseTable table, String name, String rgb, + Color fillColor, Color textColor) throws IOException { + Row row = table.createRow(15f); + row.createCell(25, name); + row.createCell(25, rgb); + + Cell fillCell = row.createCell(25, "Sample"); + fillCell.setFillColor(fillColor); + fillCell.setTextColor(Color.WHITE); + fillCell.setAlign(HorizontalAlignment.CENTER); + + Cell textCell = row.createCell(25, "Sample Text"); + textCell.setTextColor(textColor); + textCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to add an alpha/transparency demonstration row + */ + private void addAlphaRow(BaseTable table, String description, String alphaValue, + Color color) throws IOException { + Row row = table.createRow(15f); + row.createCell(25, description); + row.createCell(25, alphaValue); + + Cell visualCell = row.createCell(50, "This cell shows the transparency effect"); + visualCell.setFillColor(color); + visualCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to add a color combination row + */ + private void addCombinationRow(BaseTable table, Color bgColor, Color textColor, + String text) throws IOException { + Row row = table.createRow(15f); + + Cell bgCell = row.createCell(50, "Background Sample"); + bgCell.setFillColor(bgColor); + bgCell.setTextColor(Color.WHITE); + bgCell.setAlign(HorizontalAlignment.CENTER); + + Cell textCell = row.createCell(50, text); + textCell.setFillColor(bgColor); + textCell.setTextColor(textColor); + textCell.setAlign(HorizontalAlignment.CENTER); + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java new file mode 100644 index 0000000..0649f96 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java @@ -0,0 +1,264 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import be.quodlibet.boxable.VerticalAlignment; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 04: Cell Alignment + * + * This tutorial demonstrates: + * - Horizontal alignment (LEFT, CENTER, RIGHT) + * - Vertical alignment (TOP, MIDDLE, BOTTOM) + * - Combined horizontal and vertical alignments + * - Practical alignment examples + */ +public class Tutorial04_Alignment { + + @Test + public void demonstrateAlignment() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 04: Cell Alignment"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(230, 126, 34)); // Orange background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Demonstrate horizontal and vertical text alignment options in cells."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Horizontal Alignment + addSectionHeader(table, "Horizontal Alignment"); + + Row hAlignHeader = table.createRow(15f); + hAlignHeader.createCell(25, "Alignment"); + hAlignHeader.createCell(75, "Example"); + styleHeaderRow(hAlignHeader); + + // LEFT alignment + Row leftRow = table.createRow(15f); + leftRow.createCell(25, "LEFT"); + Cell leftCell = leftRow.createCell(75, "This text is aligned to the left"); + leftCell.setAlign(HorizontalAlignment.LEFT); + leftCell.setFillColor(new Color(174, 214, 241)); + + // CENTER alignment + Row centerRow = table.createRow(15f); + centerRow.createCell(25, "CENTER"); + Cell centerCell = centerRow.createCell(75, "This text is centered"); + centerCell.setAlign(HorizontalAlignment.CENTER); + centerCell.setFillColor(new Color(174, 214, 241)); + + // RIGHT alignment + Row rightRow = table.createRow(15f); + rightRow.createCell(25, "RIGHT"); + Cell rightCell = rightRow.createCell(75, "This text is aligned to the right"); + rightCell.setAlign(HorizontalAlignment.RIGHT); + rightCell.setFillColor(new Color(174, 214, 241)); + + // Section 2: Vertical Alignment + addSectionHeader(table, "Vertical Alignment (Tall Cells)"); + + Row vAlignHeader = table.createRow(15f); + vAlignHeader.createCell(25, "Alignment"); + vAlignHeader.createCell(75, "Example (40pt tall cells)"); + styleHeaderRow(vAlignHeader); + + // TOP alignment + Row topRow = table.createRow(40f); + topRow.createCell(25, "TOP"); + Cell topCell = topRow.createCell(75, "Text at top"); + topCell.setValign(VerticalAlignment.TOP); + topCell.setFillColor(new Color(212, 230, 241)); + + // MIDDLE alignment + Row middleRow = table.createRow(40f); + middleRow.createCell(25, "MIDDLE"); + Cell middleCell = middleRow.createCell(75, "Text in middle"); + middleCell.setValign(VerticalAlignment.MIDDLE); + middleCell.setFillColor(new Color(212, 230, 241)); + + // BOTTOM alignment + Row bottomRow = table.createRow(40f); + bottomRow.createCell(25, "BOTTOM"); + Cell bottomCell = bottomRow.createCell(75, "Text at bottom"); + bottomCell.setValign(VerticalAlignment.BOTTOM); + bottomCell.setFillColor(new Color(212, 230, 241)); + + // Section 3: Combined Alignment + addSectionHeader(table, "Combined Horizontal and Vertical Alignment"); + + Row comboHeader = table.createRow(15f); + comboHeader.createCell(33.33f, "Top Left"); + comboHeader.createCell(33.33f, "Top Center"); + comboHeader.createCell(33.34f, "Top Right"); + styleHeaderRow(comboHeader); + + // Top row combinations + Row topComboRow = table.createRow(35f); + Cell topLeft = topComboRow.createCell(33.33f, "TOP
      LEFT"); + topLeft.setAlign(HorizontalAlignment.LEFT); + topLeft.setValign(VerticalAlignment.TOP); + topLeft.setFillColor(new Color(230, 245, 255)); + + Cell topCenter = topComboRow.createCell(33.33f, "TOP
      CENTER"); + topCenter.setAlign(HorizontalAlignment.CENTER); + topCenter.setValign(VerticalAlignment.TOP); + topCenter.setFillColor(new Color(230, 245, 255)); + + Cell topRight = topComboRow.createCell(33.34f, "TOP
      RIGHT"); + topRight.setAlign(HorizontalAlignment.RIGHT); + topRight.setValign(VerticalAlignment.TOP); + topRight.setFillColor(new Color(230, 245, 255)); + + // Middle row combinations + Row middleComboRow = table.createRow(35f); + Cell middleLeft = middleComboRow.createCell(33.33f, "MIDDLE
      LEFT"); + middleLeft.setAlign(HorizontalAlignment.LEFT); + middleLeft.setValign(VerticalAlignment.MIDDLE); + middleLeft.setFillColor(new Color(255, 243, 224)); + + Cell middleCenter = middleComboRow.createCell(33.33f, "MIDDLE
      CENTER"); + middleCenter.setAlign(HorizontalAlignment.CENTER); + middleCenter.setValign(VerticalAlignment.MIDDLE); + middleCenter.setFillColor(new Color(255, 243, 224)); + + Cell middleRight = middleComboRow.createCell(33.34f, "MIDDLE
      RIGHT"); + middleRight.setAlign(HorizontalAlignment.RIGHT); + middleRight.setValign(VerticalAlignment.MIDDLE); + middleRight.setFillColor(new Color(255, 243, 224)); + + // Bottom row combinations + Row bottomComboRow = table.createRow(35f); + Cell bottomLeft = bottomComboRow.createCell(33.33f, "BOTTOM
      LEFT"); + bottomLeft.setAlign(HorizontalAlignment.LEFT); + bottomLeft.setValign(VerticalAlignment.BOTTOM); + bottomLeft.setFillColor(new Color(255, 235, 238)); + + Cell bottomCenter = bottomComboRow.createCell(33.33f, "BOTTOM
      CENTER"); + bottomCenter.setAlign(HorizontalAlignment.CENTER); + bottomCenter.setValign(VerticalAlignment.BOTTOM); + bottomCenter.setFillColor(new Color(255, 235, 238)); + + Cell bottomRight = bottomComboRow.createCell(33.34f, "BOTTOM
      RIGHT"); + bottomRight.setAlign(HorizontalAlignment.RIGHT); + bottomRight.setValign(VerticalAlignment.BOTTOM); + bottomRight.setFillColor(new Color(255, 235, 238)); + + // Section 4: Practical Example + addSectionHeader(table, "Practical Example: Invoice Table"); + + Row invoiceHeader = table.createRow(15f); + Cell itemHeader = invoiceHeader.createCell(40, "Item"); + Cell qtyHeader = invoiceHeader.createCell(20, "Qty"); + Cell priceHeader = invoiceHeader.createCell(20, "Price"); + Cell totalHeader = invoiceHeader.createCell(20, "Total"); + styleHeaderRow(invoiceHeader); + + // Center align numeric headers + qtyHeader.setAlign(HorizontalAlignment.CENTER); + priceHeader.setAlign(HorizontalAlignment.RIGHT); + totalHeader.setAlign(HorizontalAlignment.RIGHT); + + // Invoice data rows + String[][] invoiceData = { + {"Premium Widget", "5", "$10.00", "$50.00"}, + {"Standard Widget", "10", "$5.00", "$50.00"}, + {"Economy Widget", "20", "$2.50", "$50.00"} + }; + + for (String[] row : invoiceData) { + Row dataRow = table.createRow(15f); + Cell itemCell = dataRow.createCell(40, row[0]); + Cell qtyCell = dataRow.createCell(20, row[1]); + Cell priceCell = dataRow.createCell(20, row[2]); + Cell totalCell = dataRow.createCell(20, row[3]); + + // Apply appropriate alignment + itemCell.setAlign(HorizontalAlignment.LEFT); + qtyCell.setAlign(HorizontalAlignment.CENTER); + priceCell.setAlign(HorizontalAlignment.RIGHT); + totalCell.setAlign(HorizontalAlignment.RIGHT); + } + + // Total row + Row totalRow = table.createRow(15f); + Cell totalLabel = totalRow.createCell(80, "TOTAL:"); + Cell totalAmount = totalRow.createCell(20, "$150.00"); + totalLabel.setAlign(HorizontalAlignment.RIGHT); + totalLabel.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + totalAmount.setAlign(HorizontalAlignment.RIGHT); + totalAmount.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + totalAmount.setFillColor(new Color(46, 204, 113)); + totalAmount.setTextColor(Color.WHITE); + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial04_Alignment.pdf"); + System.out.println("Tutorial 04 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} From 5f8bf0f9d0e7b51a626c0f0c94dcc2754bbc1947 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 14:03:19 +0000 Subject: [PATCH 3/6] Add Tutorials 05-08: Images, Borders, Headers, Data Import Co-authored-by: quodlibetbv <220320055+quodlibetbv@users.noreply.github.com> --- .../boxable/tutorial/Tutorial05_Images.java | 256 ++++++++++++++++ .../Tutorial06_BordersAndStyling.java | 281 ++++++++++++++++++ .../tutorial/Tutorial07_HeaderRows.java | 243 +++++++++++++++ .../tutorial/Tutorial08_DataImport.java | 260 ++++++++++++++++ 4 files changed, 1040 insertions(+) create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial05_Images.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial06_BordersAndStyling.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial05_Images.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial05_Images.java new file mode 100644 index 0000000..ca8233e --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial05_Images.java @@ -0,0 +1,256 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.ImageCell; +import be.quodlibet.boxable.Row; +import be.quodlibet.boxable.image.Image; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 05: Images in Cells + * + * This tutorial demonstrates: + * - Adding images to table cells + * - Image scaling to fit cells + * - Image padding control + * - Multiple images in a table + * - Different image sizes and aspect ratios + */ +public class Tutorial05_Images { + + @Test + public void demonstrateImages() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 05: Images in Cells"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(26, 188, 156)); // Teal background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Learn how to add images to cells, control scaling, and adjust padding."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Basic Image in Cell + addSectionHeader(table, "Basic Image in Cell"); + + Row basicDesc = table.createRow(15f); + basicDesc.createCell(100, "A simple image in a cell with default settings:"); + + // Create a sample image (red background with green circle) + BufferedImage redGreenImage = createSampleImage(200, 100, Color.RED, Color.GREEN); + Image image1 = new Image(redGreenImage); + + Row imageRow1 = table.createRow(100f); + ImageCell imageCell1 = imageRow1.createImageCell(100, image1); + imageCell1.setAlign(HorizontalAlignment.CENTER); + + // Section 2: Image Scaling + addSectionHeader(table, "Image Scaling"); + + Row scalingHeader = table.createRow(15f); + scalingHeader.createCell(33.33f, "Small Cell"); + scalingHeader.createCell(33.33f, "Medium Cell"); + scalingHeader.createCell(33.34f, "Large Cell"); + styleHeaderRow(scalingHeader); + + Row scalingRow = table.createRow(80f); + + // Small cell with image + BufferedImage blueImage = createSampleImage(200, 100, Color.BLUE, Color.YELLOW); + Image image2 = new Image(blueImage); + ImageCell smallCell = scalingRow.createImageCell(33.33f, image2); + smallCell.setAlign(HorizontalAlignment.CENTER); + + // Medium cell with image + BufferedImage orangeImage = createSampleImage(200, 100, Color.ORANGE, Color.CYAN); + Image image3 = new Image(orangeImage); + ImageCell mediumCell = scalingRow.createImageCell(33.33f, image3); + mediumCell.setAlign(HorizontalAlignment.CENTER); + + // Large cell with image + BufferedImage purpleImage = createSampleImage(200, 100, new Color(155, 89, 182), Color.WHITE); + Image image4 = new Image(purpleImage); + ImageCell largeCell = scalingRow.createImageCell(33.34f, image4); + largeCell.setAlign(HorizontalAlignment.CENTER); + + // Section 3: Image Padding Control + addSectionHeader(table, "Image Padding Control"); + + Row paddingDesc = table.createRow(15f); + paddingDesc.createCell(100, "Control the padding around images:"); + + Row paddingHeader = table.createRow(15f); + paddingHeader.createCell(33.33f, "Default Padding"); + paddingHeader.createCell(33.33f, "No Padding"); + paddingHeader.createCell(33.34f, "Custom Padding"); + styleHeaderRow(paddingHeader); + + Row paddingRow = table.createRow(80f); + + // Default padding + BufferedImage greenImage = createSampleImage(200, 100, new Color(46, 204, 113), Color.BLACK); + Image image5 = new Image(greenImage); + ImageCell defaultPadCell = paddingRow.createImageCell(33.33f, image5); + defaultPadCell.setFillColor(new Color(236, 240, 241)); + + // No padding + BufferedImage yellowImage = createSampleImage(200, 100, new Color(241, 196, 15), Color.BLACK); + Image image6 = new Image(yellowImage); + ImageCell noPadCell = paddingRow.createImageCell(33.33f, image6); + noPadCell.setTopPadding(0); + noPadCell.setBottomPadding(0); + noPadCell.setLeftPadding(0); + noPadCell.setRightPadding(0); + noPadCell.setFillColor(new Color(236, 240, 241)); + + // Custom padding (20pt) + BufferedImage cyanImage = createSampleImage(200, 100, new Color(52, 152, 219), Color.WHITE); + Image image7 = new Image(cyanImage); + ImageCell customPadCell = paddingRow.createImageCell(33.34f, image7); + customPadCell.setTopPadding(20); + customPadCell.setBottomPadding(20); + customPadCell.setLeftPadding(20); + customPadCell.setRightPadding(20); + customPadCell.setFillColor(new Color(236, 240, 241)); + + // Section 4: Different Image Aspect Ratios + addSectionHeader(table, "Different Image Aspect Ratios"); + + Row aspectHeader = table.createRow(15f); + aspectHeader.createCell(33.33f, "Landscape (2:1)"); + aspectHeader.createCell(33.33f, "Square (1:1)"); + aspectHeader.createCell(33.34f, "Portrait (1:2)"); + styleHeaderRow(aspectHeader); + + Row aspectRow = table.createRow(100f); + + // Landscape image + BufferedImage landscapeImage = createSampleImage(200, 100, new Color(231, 76, 60), Color.WHITE); + Image image8 = new Image(landscapeImage); + ImageCell landscapeCell = aspectRow.createImageCell(33.33f, image8); + landscapeCell.setAlign(HorizontalAlignment.CENTER); + + // Square image + BufferedImage squareImage = createSampleImage(150, 150, new Color(52, 73, 94), Color.WHITE); + Image image9 = new Image(squareImage); + ImageCell squareCell = aspectRow.createImageCell(33.33f, image9); + squareCell.setAlign(HorizontalAlignment.CENTER); + + // Portrait image + BufferedImage portraitImage = createSampleImage(100, 200, new Color(155, 89, 182), Color.WHITE); + Image image10 = new Image(portraitImage); + ImageCell portraitCell = aspectRow.createImageCell(33.34f, image10); + portraitCell.setAlign(HorizontalAlignment.CENTER); + + // Section 5: Images with Text + addSectionHeader(table, "Images Combined with Text"); + + Row combinedRow = table.createRow(80f); + + // Image cell + BufferedImage finalImage = createSampleImage(200, 100, new Color(41, 128, 185), Color.WHITE); + Image image11 = new Image(finalImage); + ImageCell imgCell = combinedRow.createImageCell(40f, image11); + imgCell.setAlign(HorizontalAlignment.CENTER); + + // Text description cell + Cell textCell = combinedRow.createCell(60f, + "Product Name: Sample Widget
      " + + "Description: This is a high-quality product with excellent features.
      " + + "Price: $99.99
      " + + "Stock: In Stock"); + textCell.setAlign(HorizontalAlignment.LEFT); + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial05_Images.pdf"); + System.out.println("Tutorial 05 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to create a sample image with colored background and shape + */ + private BufferedImage createSampleImage(int width, int height, Color bgColor, Color shapeColor) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + + // Fill background + g.setColor(bgColor); + g.fillRect(0, 0, width, height); + + // Draw a circle or oval + g.setColor(shapeColor); + int size = Math.min(width, height); + int x = (width - size) / 2; + int y = (height - size) / 2; + g.fillOval(x, y, size, size); + + g.dispose(); + return image; + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial06_BordersAndStyling.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial06_BordersAndStyling.java new file mode 100644 index 0000000..4d38bc1 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial06_BordersAndStyling.java @@ -0,0 +1,281 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import be.quodlibet.boxable.line.LineStyle; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 06: Borders and Styling + * + * This tutorial demonstrates: + * - Border styles (solid lines with different widths) + * - Border colors + * - Selective borders (top, bottom, left, right) + * - No borders (removing borders) + * - Outer border only + * - Custom border configurations + */ +public class Tutorial06_BordersAndStyling { + + @Test + public void demonstrateBordersAndStyling() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 06: Borders and Styling"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(192, 57, 43)); // Dark red background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Learn how to customize cell borders, including colors, widths, and selective borders."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Default Borders + addSectionHeader(table, "Default Borders"); + + Row defaultDesc = table.createRow(15f); + defaultDesc.createCell(100, "By default, all cells have 1pt black borders:"); + + Row defaultRow = table.createRow(20f); + defaultRow.createCell(33.33f, "Cell 1"); + defaultRow.createCell(33.33f, "Cell 2"); + defaultRow.createCell(33.34f, "Cell 3"); + + // Section 2: Border Width Variations + addSectionHeader(table, "Border Width Variations"); + + Row widthHeader = table.createRow(15f); + widthHeader.createCell(33.33f, "Thin (0.5pt)"); + widthHeader.createCell(33.33f, "Normal (1pt)"); + widthHeader.createCell(33.34f, "Thick (3pt)"); + styleHeaderRow(widthHeader); + + Row widthRow = table.createRow(20f); + + // Thin border + Cell thinCell = widthRow.createCell(33.33f, "Thin Border"); + thinCell.setBorderStyle(new LineStyle(Color.BLACK, 0.5f)); + thinCell.setAlign(HorizontalAlignment.CENTER); + + // Normal border + Cell normalCell = widthRow.createCell(33.33f, "Normal Border"); + normalCell.setBorderStyle(new LineStyle(Color.BLACK, 1f)); + normalCell.setAlign(HorizontalAlignment.CENTER); + + // Thick border + Cell thickCell = widthRow.createCell(33.34f, "Thick Border"); + thickCell.setBorderStyle(new LineStyle(Color.BLACK, 3f)); + thickCell.setAlign(HorizontalAlignment.CENTER); + + // Section 3: Border Colors + addSectionHeader(table, "Border Colors"); + + Row colorHeader = table.createRow(15f); + colorHeader.createCell(25, "Red"); + colorHeader.createCell(25, "Blue"); + colorHeader.createCell(25, "Green"); + colorHeader.createCell(25, "Purple"); + styleHeaderRow(colorHeader); + + Row colorRow = table.createRow(20f); + + Cell redBorder = colorRow.createCell(25, "Red Border"); + redBorder.setBorderStyle(new LineStyle(Color.RED, 2f)); + redBorder.setAlign(HorizontalAlignment.CENTER); + + Cell blueBorder = colorRow.createCell(25, "Blue Border"); + blueBorder.setBorderStyle(new LineStyle(Color.BLUE, 2f)); + blueBorder.setAlign(HorizontalAlignment.CENTER); + + Cell greenBorder = colorRow.createCell(25, "Green Border"); + greenBorder.setBorderStyle(new LineStyle(new Color(46, 204, 113), 2f)); + greenBorder.setAlign(HorizontalAlignment.CENTER); + + Cell purpleBorder = colorRow.createCell(25, "Purple Border"); + purpleBorder.setBorderStyle(new LineStyle(new Color(155, 89, 182), 2f)); + purpleBorder.setAlign(HorizontalAlignment.CENTER); + + // Section 4: Selective Borders + addSectionHeader(table, "Selective Borders"); + + Row selectDesc = table.createRow(15f); + selectDesc.createCell(100, "Control which sides have borders:"); + + Row selectHeader = table.createRow(15f); + selectHeader.createCell(25, "Top Only"); + selectHeader.createCell(25, "Bottom Only"); + selectHeader.createCell(25, "Left Only"); + selectHeader.createCell(25, "Right Only"); + styleHeaderRow(selectHeader); + + Row selectRow = table.createRow(30f); + + Cell topOnly = selectRow.createCell(25, "Top Border Only"); + topOnly.setTopBorderStyle(new LineStyle(Color.BLACK, 2f)); + topOnly.setBottomBorderStyle(null); + topOnly.setLeftBorderStyle(null); + topOnly.setRightBorderStyle(null); + topOnly.setAlign(HorizontalAlignment.CENTER); + + Cell bottomOnly = selectRow.createCell(25, "Bottom Border Only"); + bottomOnly.setTopBorderStyle(null); + bottomOnly.setBottomBorderStyle(new LineStyle(Color.BLACK, 2f)); + bottomOnly.setLeftBorderStyle(null); + bottomOnly.setRightBorderStyle(null); + bottomOnly.setAlign(HorizontalAlignment.CENTER); + + Cell leftOnly = selectRow.createCell(25, "Left Border Only"); + leftOnly.setTopBorderStyle(null); + leftOnly.setBottomBorderStyle(null); + leftOnly.setLeftBorderStyle(new LineStyle(Color.BLACK, 2f)); + leftOnly.setRightBorderStyle(null); + leftOnly.setAlign(HorizontalAlignment.CENTER); + + Cell rightOnly = selectRow.createCell(25, "Right Border Only"); + rightOnly.setTopBorderStyle(null); + rightOnly.setBottomBorderStyle(null); + rightOnly.setLeftBorderStyle(null); + rightOnly.setRightBorderStyle(new LineStyle(Color.BLACK, 2f)); + rightOnly.setAlign(HorizontalAlignment.CENTER); + + // Section 5: No Borders + addSectionHeader(table, "No Borders"); + + Row noBorderDesc = table.createRow(15f); + noBorderDesc.createCell(100, "Cells can be created without any borders:"); + + Row noBorderRow = table.createRow(20f); + + Cell noBorder1 = noBorderRow.createCell(33.33f, "No Border"); + noBorder1.setBorderStyle(null); + noBorder1.setFillColor(new Color(174, 214, 241)); + noBorder1.setAlign(HorizontalAlignment.CENTER); + + Cell noBorder2 = noBorderRow.createCell(33.33f, "No Border"); + noBorder2.setBorderStyle(null); + noBorder2.setFillColor(new Color(255, 243, 224)); + noBorder2.setAlign(HorizontalAlignment.CENTER); + + Cell noBorder3 = noBorderRow.createCell(33.34f, "No Border"); + noBorder3.setBorderStyle(null); + noBorder3.setFillColor(new Color(255, 235, 238)); + noBorder3.setAlign(HorizontalAlignment.CENTER); + + // Section 6: Combined Styling + addSectionHeader(table, "Combined Styling Example"); + + Row comboDesc = table.createRow(15f); + comboDesc.createCell(100, "Combining borders with colors for visual effects:"); + + Row comboRow = table.createRow(25f); + + Cell combo1 = comboRow.createCell(50, "Important: Highlighted Cell"); + combo1.setFillColor(new Color(255, 243, 224)); + combo1.setBorderStyle(new LineStyle(new Color(243, 156, 18), 3f)); + + Cell combo2 = comboRow.createCell(50, "Warning: Alert Cell"); + combo2.setFillColor(new Color(255, 235, 238)); + combo2.setBorderStyle(new LineStyle(new Color(231, 76, 60), 3f)); + + // Draw the table + table.draw(); + + // Create a second table demonstrating outer border only + if (table.getCurrentPage() != page) { + page = table.getCurrentPage(); + } + // Create new page for the second table + page = new PDPage(PDRectangle.A4); + document.addPage(page); + float newYStart = yStartNewPage; + + BaseTable table2 = new BaseTable(newYStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + false, true); // drawLines = false + table2.setOuterBorderStyle(new LineStyle(Color.BLACK, 2f)); + + Row outerTitle = table2.createRow(20f); + Cell outerTitleCell = outerTitle.createCell(100, "Outer Border Only Example"); + outerTitleCell.setFillColor(new Color(52, 73, 94)); + outerTitleCell.setTextColor(Color.WHITE); + outerTitleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + outerTitleCell.setAlign(HorizontalAlignment.CENTER); + + Row outerRow1 = table2.createRow(15f); + outerRow1.createCell(33.33f, "Cell 1"); + outerRow1.createCell(33.33f, "Cell 2"); + outerRow1.createCell(33.34f, "Cell 3"); + + Row outerRow2 = table2.createRow(15f); + outerRow2.createCell(33.33f, "Cell 4"); + outerRow2.createCell(33.33f, "Cell 5"); + outerRow2.createCell(33.34f, "Cell 6"); + + table2.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial06_BordersAndStyling.pdf"); + System.out.println("Tutorial 06 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java new file mode 100644 index 0000000..2311cd5 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java @@ -0,0 +1,243 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 07: Header Rows + * + * This tutorial demonstrates: + * - Creating single header rows + * - Creating multiple header rows + * - Header styling + * - Headers spanning multiple pages + * - Header row repetition on new pages + */ +public class Tutorial07_HeaderRows { + + @Test + public void demonstrateHeaderRows() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 07: Header Rows"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(142, 68, 173)); // Purple background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Learn how to create header rows that repeat on each page of multi-page tables."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Single Header Row + addSectionHeader(table, "Single Header Row"); + + Row singleHeader = table.createRow(20f); + Cell col1 = singleHeader.createCell(25, "Name"); + Cell col2 = singleHeader.createCell(25, "Age"); + Cell col3 = singleHeader.createCell(25, "City"); + Cell col4 = singleHeader.createCell(25, "Country"); + styleHeaderRow(singleHeader); + table.addHeaderRow(singleHeader); + + // Add some data rows + for (int i = 1; i <= 5; i++) { + Row dataRow = table.createRow(15f); + dataRow.createCell(25, "Person " + i); + dataRow.createCell(25, String.valueOf(20 + i)); + dataRow.createCell(25, "City " + i); + dataRow.createCell(25, "Country " + i); + + if (i % 2 == 0) { + for (Cell cell : dataRow.getCells()) { + cell.setFillColor(new Color(236, 240, 241)); + } + } + } + + // Section 2: Multiple Header Rows + addSectionHeader(table, "Multiple Header Rows"); + + // Create a new table to demonstrate multiple headers + float newYStart = table.draw() - 30; + if (table.getCurrentPage() != page) { + page = table.getCurrentPage(); + } + + BaseTable table2 = new BaseTable(newYStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // First header row - Main title + Row mainHeader = table2.createRow(20f); + Cell mainHeaderCell = mainHeader.createCell(100, "2024 Sales Report"); + mainHeaderCell.setFillColor(new Color(41, 128, 185)); + mainHeaderCell.setTextColor(Color.WHITE); + mainHeaderCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + mainHeaderCell.setAlign(HorizontalAlignment.CENTER); + table2.addHeaderRow(mainHeader); + + // Second header row - Subtitle + Row subHeader = table2.createRow(15f); + Cell subHeaderCell = subHeader.createCell(100, "Quarterly Performance Analysis"); + subHeaderCell.setFillColor(new Color(52, 152, 219)); + subHeaderCell.setTextColor(Color.WHITE); + subHeaderCell.setAlign(HorizontalAlignment.CENTER); + table2.addHeaderRow(subHeader); + + // Third header row - Column headers + Row colHeader = table2.createRow(15f); + colHeader.createCell(40, "Product"); + colHeader.createCell(20, "Q1"); + colHeader.createCell(20, "Q2"); + colHeader.createCell(20, "Q3"); + styleHeaderRow(colHeader); + table2.addHeaderRow(colHeader); + + // Data rows + String[][] salesData = { + {"Widget A", "$10,000", "$12,000", "$11,500"}, + {"Widget B", "$8,500", "$9,200", "$9,800"}, + {"Widget C", "$15,000", "$16,500", "$17,200"}, + {"Widget D", "$7,200", "$7,800", "$8,100"}, + {"Widget E", "$11,000", "$10,500", "$11,800"} + }; + + for (int i = 0; i < salesData.length; i++) { + Row dataRow = table2.createRow(15f); + dataRow.createCell(40, salesData[i][0]); + dataRow.createCell(20, salesData[i][1]); + dataRow.createCell(20, salesData[i][2]); + dataRow.createCell(20, salesData[i][3]); + + // Right-align numeric columns + for (int j = 1; j < 4; j++) { + dataRow.getCells().get(j).setAlign(HorizontalAlignment.RIGHT); + } + + if (i % 2 == 0) { + for (Cell cell : dataRow.getCells()) { + cell.setFillColor(new Color(236, 240, 241)); + } + } + } + + // Draw the second table + newYStart = table2.draw() - 30; + if (table2.getCurrentPage() != page) { + page = table2.getCurrentPage(); + } + + // Section 3: Multi-Page Table with Header Repetition + BaseTable table3 = new BaseTable(newYStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + Row multiTitle = table3.createRow(20f); + Cell multiTitleCell = multiTitle.createCell(100, "Multi-Page Table with Repeating Headers"); + multiTitleCell.setFillColor(new Color(44, 62, 80)); + multiTitleCell.setTextColor(Color.WHITE); + multiTitleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + multiTitleCell.setAlign(HorizontalAlignment.CENTER); + + Row multiDesc = table3.createRow(15f); + Cell multiDescCell = multiDesc.createCell(100, + "This table has many rows. The header will repeat on the next page."); + multiDescCell.setFillColor(new Color(236, 240, 241)); + + Row multiHeader = table3.createRow(15f); + multiHeader.createCell(10, "#"); + multiHeader.createCell(30, "Item Name"); + multiHeader.createCell(30, "Description"); + multiHeader.createCell(15, "Quantity"); + multiHeader.createCell(15, "Price"); + styleHeaderRow(multiHeader); + table3.addHeaderRow(multiHeader); + + // Generate many rows to force page break + for (int i = 1; i <= 60; i++) { + Row dataRow = table3.createRow(15f); + dataRow.createCell(10, String.valueOf(i)); + dataRow.createCell(30, "Item " + i); + dataRow.createCell(30, "Description for item " + i); + dataRow.createCell(15, String.valueOf(i * 10)); + dataRow.createCell(15, "$" + String.format("%.2f", i * 9.99)); + + // Right-align numeric columns + dataRow.getCells().get(3).setAlign(HorizontalAlignment.RIGHT); + dataRow.getCells().get(4).setAlign(HorizontalAlignment.RIGHT); + + if (i % 2 == 0) { + for (Cell cell : dataRow.getCells()) { + cell.setFillColor(new Color(236, 240, 241)); + } + } + } + + table3.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial07_HeaderRows.pdf"); + System.out.println("Tutorial 07 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java new file mode 100644 index 0000000..e8b6c49 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java @@ -0,0 +1,260 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import be.quodlibet.boxable.datatable.DataTable; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tutorial 08: Data Import + * + * This tutorial demonstrates: + * - Importing data from CSV strings + * - Importing data from Java Lists + * - Column width customization + * - Data formatting + * - Header handling + */ +public class Tutorial08_DataImport { + + @Test + public void demonstrateDataImport() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + page.setMediaBox(new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth())); // Landscape + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Title + BaseTable titleTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + Row titleRow = titleTable.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 08: Data Import"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(52, 152, 219)); + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + Row descRow = titleTable.createRow(20f); + Cell descCell = descRow.createCell(100, + "Learn how to import data from CSV and Lists into tables with customization options."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + yStart = titleTable.draw() - 30; + if (titleTable.getCurrentPage() != page) { + page = titleTable.getCurrentPage(); + } + + // Section 1: Import from List (Basic) + addSectionHeader(document, page, "Section 1: Import from List (Basic)", + yStart, yStartNewPage, bottomMargin, tableWidth, margin); + yStart -= 48; + + // Create sample data list + List listData = new ArrayList<>(); + listData.add(new ArrayList<>(Arrays.asList("Product", "Category", "Price", "Stock", "Status"))); + listData.add(new ArrayList<>(Arrays.asList("Laptop", "Electronics", "$999.99", "15", "In Stock"))); + listData.add(new ArrayList<>(Arrays.asList("Mouse", "Accessories", "$19.99", "120", "In Stock"))); + listData.add(new ArrayList<>(Arrays.asList("Keyboard", "Accessories", "$49.99", "85", "In Stock"))); + listData.add(new ArrayList<>(Arrays.asList("Monitor", "Electronics", "$299.99", "42", "In Stock"))); + listData.add(new ArrayList<>(Arrays.asList("USB Cable", "Accessories", "$9.99", "200", "In Stock"))); + + BaseTable listTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + DataTable dt1 = new DataTable(listTable, page); + dt1.addListToTable(listData, DataTable.HASHEADER); + + yStart = listTable.draw() - 30; + if (listTable.getCurrentPage() != page) { + page = listTable.getCurrentPage(); + } + + // Section 2: Import from CSV + addSectionHeader(document, page, "Section 2: Import from CSV", + yStart, yStartNewPage, bottomMargin, tableWidth, margin); + yStart -= 48; + + // Create sample CSV data + String csvData = "Name;Age;City;Country;Occupation\n" + + "John Smith;28;New York;USA;Engineer\n" + + "Jane Doe;32;London;UK;Designer\n" + + "Bob Johnson;45;Toronto;Canada;Manager\n" + + "Alice Williams;25;Sydney;Australia;Developer\n" + + "Charlie Brown;38;Berlin;Germany;Analyst"; + + BaseTable csvTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + DataTable dt2 = new DataTable(csvTable, page); + dt2.addCsvToTable(csvData, DataTable.HASHEADER, ';'); + + yStart = csvTable.draw() - 30; + if (csvTable.getCurrentPage() != page) { + page = csvTable.getCurrentPage(); + } + + // Section 3: Custom Column Widths + addSectionHeader(document, page, "Section 3: Custom Column Widths", + yStart, yStartNewPage, bottomMargin, tableWidth, margin); + yStart -= 48; + + // CSV with custom column widths + String csvData2 = "Description;Code;Value;Notes\n" + + "This is a very long description that needs more space;ABC;100;Short\n" + + "Another long description with details;DEF;200;Note\n" + + "More descriptive text here;GHI;300;Info"; + + BaseTable customWidthTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + // Custom column width ratios: Description (3x), Code (1x), Value (1x), Notes (1x) + DataTable dt3 = new DataTable(customWidthTable, page, Arrays.asList(3f, 1f, 1f, 1f)); + dt3.addCsvToTable(csvData2, DataTable.HASHEADER, ';'); + + yStart = customWidthTable.draw() - 30; + if (customWidthTable.getCurrentPage() != page) { + page = customWidthTable.getCurrentPage(); + } + + // Section 4: Styled Data Import + addSectionHeader(document, page, "Section 4: Styled Data Import", + yStart, yStartNewPage, bottomMargin, tableWidth, margin); + yStart -= 48; + + // Create styled table with custom headers + BaseTable styledTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Add custom header rows before importing data + Row customHeader1 = styledTable.createRow(20f); + Cell header1Cell = customHeader1.createCell(100, "Monthly Sales Report - Q4 2024"); + header1Cell.setFillColor(new Color(41, 128, 185)); + header1Cell.setTextColor(Color.WHITE); + header1Cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + header1Cell.setAlign(HorizontalAlignment.CENTER); + styledTable.addHeaderRow(customHeader1); + + Row customHeader2 = styledTable.createRow(15f); + Cell header2Cell = customHeader2.createCell(100, "Sales figures in USD"); + header2Cell.setFillColor(new Color(52, 152, 219)); + header2Cell.setTextColor(Color.WHITE); + header2Cell.setAlign(HorizontalAlignment.CENTER); + styledTable.addHeaderRow(customHeader2); + + // Now import data + String salesCsv = "Month;Revenue;Expenses;Profit;Growth\n" + + "October;$125,000;$45,000;$80,000;+12%\n" + + "November;$145,000;$48,000;$97,000;+16%\n" + + "December;$180,000;$52,000;$128,000;+24%"; + + DataTable dt4 = new DataTable(styledTable, page); + // Customize header cell styling + dt4.getHeaderCellTemplate().setFillColor(new Color(52, 73, 94)); + dt4.getHeaderCellTemplate().setTextColor(Color.WHITE); + + // Customize data cell styling for alternating rows + for (Cell cell : dt4.getDataCellTemplateEvenList()) { + cell.setFillColor(Color.WHITE); + } + for (Cell cell : dt4.getDataCellTemplateOddList()) { + cell.setFillColor(new Color(236, 240, 241)); + } + + dt4.addCsvToTable(salesCsv, DataTable.HASHEADER, ';'); + + yStart = styledTable.draw() - 30; + if (styledTable.getCurrentPage() != page) { + page = styledTable.getCurrentPage(); + } + + // Section 5: Large Dataset Import + addSectionHeader(document, page, "Section 5: Large Dataset Import", + yStart, yStartNewPage, bottomMargin, tableWidth, margin); + yStart -= 48; + + // Generate large dataset + List largeData = new ArrayList<>(); + largeData.add(new ArrayList<>(Arrays.asList("ID", "Name", "Department", "Email", "Phone"))); + + for (int i = 1; i <= 30; i++) { + largeData.add(new ArrayList<>(Arrays.asList( + String.valueOf(i), + "Employee " + i, + "Dept " + ((i % 5) + 1), + "employee" + i + "@company.com", + "555-" + String.format("%04d", i) + ))); + } + + BaseTable largeTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + DataTable dt5 = new DataTable(largeTable, page); + + // Style the large table + dt5.getHeaderCellTemplate().setFillColor(new Color(155, 89, 182)); + dt5.getHeaderCellTemplate().setTextColor(Color.WHITE); + for (Cell cell : dt5.getDataCellTemplateEvenList()) { + cell.setFillColor(Color.WHITE); + } + for (Cell cell : dt5.getDataCellTemplateOddList()) { + cell.setFillColor(new Color(250, 242, 255)); + } + + dt5.addListToTable(largeData, DataTable.HASHEADER); + + largeTable.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial08_DataImport.pdf"); + System.out.println("Tutorial 08 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(PDDocument document, PDPage page, String title, + float yStart, float yStartNewPage, float bottomMargin, + float tableWidth, float margin) throws IOException { + BaseTable headerTable = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + Row sectionRow = headerTable.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + headerTable.draw(); + } +} From 43e4555b3250a398cb0264d0433d126fec1421c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 14:07:09 +0000 Subject: [PATCH 4/6] Add Tutorials 09-12 and TutorialRunner - All tutorials working Co-authored-by: quodlibetbv <220320055+quodlibetbv@users.noreply.github.com> --- .../tutorial/Tutorial09_MultiPageTables.java | 159 +++++++++ .../tutorial/Tutorial10_NestedTables.java | 246 ++++++++++++++ .../tutorial/Tutorial11_FixedHeightRows.java | 272 ++++++++++++++++ .../tutorial/Tutorial12_AdvancedFeatures.java | 305 ++++++++++++++++++ .../boxable/tutorial/TutorialRunner.java | 216 +++++++++++++ 5 files changed, 1198 insertions(+) create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial11_FixedHeightRows.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java create mode 100644 src/test/java/be/quodlibet/boxable/tutorial/TutorialRunner.java diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java new file mode 100644 index 0000000..c39b21f --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java @@ -0,0 +1,159 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 09: Multi-Page Tables + * + * This tutorial demonstrates: + * - Automatic page breaks + * - Large content handling across multiple pages + * - Header repetition on new pages + * - Managing page transitions + */ +public class Tutorial09_MultiPageTables { + + @Test + public void demonstrateMultiPageTables() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 09: Multi-Page Tables"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(22, 160, 133)); // Turquoise background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Demonstrate how tables automatically span multiple pages with repeating headers."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Create repeating header + Row headerRow = table.createRow(20f); + headerRow.createCell(10, "#"); + headerRow.createCell(25, "Product Name"); + headerRow.createCell(25, "Description"); + headerRow.createCell(15, "Price"); + headerRow.createCell(10, "Qty"); + headerRow.createCell(15, "Total"); + styleHeaderRow(headerRow); + table.addHeaderRow(headerRow); + + // Generate 100 rows to force multiple page breaks + Color lightBlue = new Color(236, 240, 241); + Color white = Color.WHITE; + + for (int i = 1; i <= 100; i++) { + Row dataRow = table.createRow(15f); + + // Row color alternation + Color rowColor = (i % 2 == 0) ? white : lightBlue; + + Cell numCell = dataRow.createCell(10, String.valueOf(i)); + Cell nameCell = dataRow.createCell(25, "Product " + i); + Cell descCell2 = dataRow.createCell(25, + "Description for product number " + i); + Cell priceCell = dataRow.createCell(15, + String.format("$%.2f", i * 9.99)); + Cell qtyCell = dataRow.createCell(10, String.valueOf(i % 50 + 1)); + Cell totalCell = dataRow.createCell(15, + String.format("$%.2f", (i * 9.99) * (i % 50 + 1))); + + // Apply styling + for (Cell cell : dataRow.getCells()) { + cell.setFillColor(rowColor); + } + + // Right-align numeric columns + numCell.setAlign(HorizontalAlignment.CENTER); + priceCell.setAlign(HorizontalAlignment.RIGHT); + qtyCell.setAlign(HorizontalAlignment.CENTER); + totalCell.setAlign(HorizontalAlignment.RIGHT); + + // Add section markers at page transitions + if (i % 25 == 0) { + Row sectionRow = table.createRow(20f); + Cell sectionCell = sectionRow.createCell(100, + String.format("=== Section %d (Items %d-%d) ===", + (i/25), (i-24), i)); + sectionCell.setFillColor(new Color(52, 152, 219)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + } + + // Summary row + Row summaryRow = table.createRow(20f); + Cell summaryLabel = summaryRow.createCell(85, "TOTAL ITEMS:"); + summaryLabel.setAlign(HorizontalAlignment.RIGHT); + summaryLabel.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + summaryLabel.setFillColor(new Color(46, 204, 113)); + summaryLabel.setTextColor(Color.WHITE); + + Cell summaryValue = summaryRow.createCell(15, "100"); + summaryValue.setAlign(HorizontalAlignment.CENTER); + summaryValue.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + summaryValue.setFillColor(new Color(46, 204, 113)); + summaryValue.setTextColor(Color.WHITE); + + // Draw the table + table.draw(); + + // Get statistics about the generated PDF + int pageCount = document.getNumberOfPages(); + System.out.println("Multi-page table generated " + pageCount + " pages"); + + // Save the document + File file = new File("target/tutorials/Tutorial09_MultiPageTables.pdf"); + System.out.println("Tutorial 09 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java new file mode 100644 index 0000000..02d1b21 --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java @@ -0,0 +1,246 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 10: Nested Tables + * + * This tutorial demonstrates: + * - Creating tables within cells using HTML tag + * - Complex layouts with nested structures + * - Practical examples of nested tables + * - Formatting nested table content + */ +public class Tutorial10_NestedTables { + + @Test + public void demonstrateNestedTables() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 10: Nested Tables"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(211, 84, 0)); // Orange background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Learn how to create tables within cells using HTML
      tags for complex layouts."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Simple Nested Table + addSectionHeader(table, "Simple Nested Table"); + + Row simpleDesc = table.createRow(15f); + simpleDesc.createCell(100, "A basic example of a table within a cell:"); + + Row simpleRow = table.createRow(80f); + simpleRow.createCell(40, "Product Details"); + + // Create a cell with nested table using HTML + String nestedTableHtml = "
      " + + "" + + "" + + "" + + "
      Item:Widget A
      Price:$99.99
      Stock:Available
      "; + Cell nestedCell = simpleRow.createCell(60, nestedTableHtml); + nestedCell.setFillColor(new Color(245, 245, 245)); + + // Section 2: Multiple Nested Tables + addSectionHeader(table, "Multiple Nested Tables"); + + Row multiDesc = table.createRow(15f); + multiDesc.createCell(100, "Multiple cells with nested tables:"); + + Row headerRow = table.createRow(15f); + headerRow.createCell(33.33f, "Product A"); + headerRow.createCell(33.33f, "Product B"); + headerRow.createCell(33.34f, "Product C"); + styleHeaderRow(headerRow); + + Row multiRow = table.createRow(70f); + + // First nested table + String table1 = "" + + "" + + "" + + "" + + "
      Price:$50
      Qty:10
      Total:$500
      "; + Cell cell1 = multiRow.createCell(33.33f, table1); + cell1.setFillColor(new Color(255, 243, 224)); + + // Second nested table + String table2 = "" + + "" + + "" + + "" + + "
      Price:$75
      Qty:8
      Total:$600
      "; + Cell cell2 = multiRow.createCell(33.33f, table2); + cell2.setFillColor(new Color(230, 245, 255)); + + // Third nested table + String table3 = "" + + "" + + "" + + "" + + "
      Price:$100
      Qty:5
      Total:$500
      "; + Cell cell3 = multiRow.createCell(33.34f, table3); + cell3.setFillColor(new Color(255, 235, 238)); + + // Section 3: Complex Nested Structure + addSectionHeader(table, "Complex Nested Structure"); + + Row complexDesc = table.createRow(15f); + complexDesc.createCell(100, "A more complex example with formatting:"); + + Row complexRow = table.createRow(100f); + + // Left cell: Regular content + Cell leftCell = complexRow.createCell(40, + "Order #12345

      " + + "Customer: John Doe
      " + + "Date: 2024-02-07
      " + + "Status: Shipped"); + leftCell.setFillColor(new Color(236, 240, 241)); + + // Right cell: Nested table with order details + String orderTable = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "
      Order Items
      ItemQtyPrice
      Widget A2$99.98
      Widget B1$49.99
      Widget C3$149.97
      Total:$299.94
      "; + Cell rightCell = complexRow.createCell(60, orderTable); + rightCell.setFillColor(Color.WHITE); + + // Section 4: Nested Tables with Lists + addSectionHeader(table, "Nested Tables Combined with Lists"); + + Row listDesc = table.createRow(15f); + listDesc.createCell(100, "Combining nested tables with HTML lists:"); + + Row listRow = table.createRow(90f); + + Cell featuresCell = listRow.createCell(50, + "Product Features:
      " + + "
        " + + "
      • High quality
      • " + + "
      • Durable construction
      • " + + "
      • Easy to use
      • " + + "
      • Great value
      • " + + "
      "); + featuresCell.setFillColor(new Color(255, 243, 224)); + + String specsTable = "Technical Specifications:
      " + + "" + + "" + + "" + + "" + + "" + + "" + + "
      Dimension:10x8x2 cm
      Weight:500g
      Material:Plastic
      Color:Blue
      Warranty:2 years
      "; + Cell specsCell = listRow.createCell(50, specsTable); + specsCell.setFillColor(new Color(230, 245, 255)); + + // Section 5: Practical Invoice Example + addSectionHeader(table, "Practical Example: Invoice"); + + Row invoiceHeader = table.createRow(60f); + + // Company info on left + String companyInfo = "

      ACME Corp

      " + + "123 Business St.
      " + + "New York, NY 10001
      " + + "Tel: (555) 123-4567
      " + + "Email: info@acme.com"; + Cell companyCell = invoiceHeader.createCell(50, companyInfo); + companyCell.setFillColor(new Color(245, 245, 245)); + + // Invoice details on right + String invoiceDetails = "" + + "" + + "" + + "" + + "" + + "
      Invoice #:INV-2024-001
      Date:February 7, 2024
      Due Date:March 7, 2024
      Terms:Net 30
      "; + Cell invoiceCell = invoiceHeader.createCell(50, invoiceDetails); + invoiceCell.setFillColor(Color.WHITE); + + // Bill to section + Row billToRow = table.createRow(50f); + String billToInfo = "Bill To:
      " + + "Jane Smith
      " + + "456 Customer Ave.
      " + + "Boston, MA 02101"; + billToRow.createCell(100, billToInfo); + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial10_NestedTables.pdf"); + System.out.println("Tutorial 10 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial11_FixedHeightRows.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial11_FixedHeightRows.java new file mode 100644 index 0000000..e9ab9cf --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial11_FixedHeightRows.java @@ -0,0 +1,272 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 11: Fixed Height Rows + * + * This tutorial demonstrates: + * - Creating fixed-height rows + * - Auto-fit text in fixed-height cells + * - Flexible vs fixed height rows + * - Font size adjustment for fixed heights + */ +public class Tutorial11_FixedHeightRows { + + @Test + public void demonstrateFixedHeightRows() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 11: Fixed Height Rows"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(192, 57, 43)); // Dark red background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Learn how to create fixed-height rows where text automatically shrinks to fit."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Flexible vs Fixed Height + addSectionHeader(table, "Flexible vs Fixed Height Comparison"); + + Row compHeader = table.createRow(15f); + compHeader.createCell(50, "Row Type"); + compHeader.createCell(50, "Behavior"); + styleHeaderRow(compHeader); + + Row flexDesc = table.createRow(15f); + flexDesc.createCell(50, "Flexible Row"); + flexDesc.createCell(50, "Height expands to fit content"); + + Row fixedDesc = table.createRow(15f); + fixedDesc.createCell(50, "Fixed Height Row"); + fixedDesc.createCell(50, "Text shrinks to fit specified height"); + + // Section 2: Flexible Row Example + addSectionHeader(table, "Flexible Row (Default Behavior)"); + + Row flexDesc2 = table.createRow(15f); + flexDesc2.createCell(100, "This row will grow to accommodate the content:"); + + // Flexible row - will expand + Row flexibleRow = table.createRow(12f); + Cell flexCell = flexibleRow.createCell(100, + "This is a flexible row with a lot of text content that would normally require " + + "more space than the initial 12pt height. The row will automatically expand to " + + "fit all of this text content while maintaining the specified font size."); + flexCell.setFillColor(new Color(174, 214, 241)); + flexCell.setFontSize(12f); + + // Section 3: Fixed Height Row Example + addSectionHeader(table, "Fixed Height Row (Text Shrinks to Fit)"); + + Row fixedDesc2 = table.createRow(15f); + fixedDesc2.createCell(100, "This row will NOT grow - text shrinks instead:"); + + // Fixed height row - text will shrink + Row fixedRow = table.createRow(12f); + fixedRow.setFixedHeight(true); + Cell fixedCell = fixedRow.createCell(100, + "This is a fixed-height row with the same amount of text content. " + + "Instead of expanding, the text will be automatically shrunk to fit " + + "within the specified 12pt height constraint. Notice the smaller font size."); + fixedCell.setFillColor(new Color(255, 243, 224)); + fixedCell.setFontSize(12f); + fixedCell.setTopPadding(1f); + fixedCell.setBottomPadding(1f); + + // Section 4: Multiple Fixed Height Rows + addSectionHeader(table, "Multiple Fixed Height Rows"); + + Row multiDesc = table.createRow(15f); + multiDesc.createCell(100, "Demonstrating various fixed heights:"); + + Row multiHeader = table.createRow(15f); + multiHeader.createCell(20, "Height"); + multiHeader.createCell(80, "Content"); + styleHeaderRow(multiHeader); + + // 10pt fixed height + Row fixed10 = table.createRow(10f); + fixed10.setFixedHeight(true); + fixed10.createCell(20, "10pt"); + Cell content10 = fixed10.createCell(80, + "Fixed at 10pt - Text automatically adjusts to fit this small height."); + content10.setFillColor(new Color(255, 235, 238)); + content10.setTopPadding(1f); + content10.setBottomPadding(1f); + + // 15pt fixed height + Row fixed15 = table.createRow(15f); + fixed15.setFixedHeight(true); + fixed15.createCell(20, "15pt"); + Cell content15 = fixed15.createCell(80, + "Fixed at 15pt - More space allows slightly larger text while still constraining the height."); + content15.setFillColor(new Color(230, 245, 255)); + content15.setTopPadding(1f); + content15.setBottomPadding(1f); + + // 20pt fixed height + Row fixed20 = table.createRow(20f); + fixed20.setFixedHeight(true); + fixed20.createCell(20, "20pt"); + Cell content20 = fixed20.createCell(80, + "Fixed at 20pt - Even more space available, text can be larger but still constrained by the fixed height."); + content20.setFillColor(new Color(255, 250, 240)); + content20.setTopPadding(1f); + content20.setBottomPadding(1f); + + // Section 5: Fixed Height Headers + addSectionHeader(table, "Fixed Height Header Rows"); + + Row headerDesc = table.createRow(15f); + headerDesc.createCell(100, "Headers can also use fixed heights for consistent appearance:"); + + // Create a table with fixed-height header + Row fixedHeader = table.createRow(12f); + fixedHeader.setFixedHeight(true); + Cell hCell1 = fixedHeader.createCell(33.33f, "Column A with Long Name"); + Cell hCell2 = fixedHeader.createCell(33.33f, "Column B Extended Title"); + Cell hCell3 = fixedHeader.createCell(33.34f, "Column C Description"); + hCell1.setFontSize(14f); + hCell2.setFontSize(14f); + hCell3.setFontSize(14f); + hCell1.setTopPadding(1f); + hCell2.setTopPadding(1f); + hCell3.setTopPadding(1f); + hCell1.setBottomPadding(1f); + hCell2.setBottomPadding(1f); + hCell3.setBottomPadding(1f); + styleHeaderRow(fixedHeader); + table.addHeaderRow(fixedHeader); + + // Add data rows + for (int i = 1; i <= 3; i++) { + Row dataRow = table.createRow(15f); + dataRow.createCell(33.33f, "Value A" + i); + dataRow.createCell(33.33f, "Value B" + i); + dataRow.createCell(33.34f, "Value C" + i); + + if (i % 2 == 0) { + for (Cell cell : dataRow.getCells()) { + cell.setFillColor(new Color(236, 240, 241)); + } + } + } + + // Section 6: Practical Use Case + addSectionHeader(table, "Practical Use Case: Compact Data Table"); + + Row practicalDesc = table.createRow(15f); + practicalDesc.createCell(100, + "Fixed heights are useful for creating compact tables with consistent row heights:"); + + // Compact table with fixed-height rows + Row compactHeader = table.createRow(12f); + compactHeader.setFixedHeight(true); + compactHeader.createCell(10, "ID"); + compactHeader.createCell(30, "Name"); + compactHeader.createCell(30, "Email"); + compactHeader.createCell(30, "Department"); + styleHeaderRow(compactHeader); + for (Cell cell : compactHeader.getCells()) { + cell.setFontSize(10f); + cell.setTopPadding(1f); + cell.setBottomPadding(1f); + } + + String[][] compactData = { + {"1", "John Smith", "john@company.com", "Engineering"}, + {"2", "Jane Doe", "jane@company.com", "Marketing"}, + {"3", "Bob Johnson", "bob@company.com", "Sales"}, + {"4", "Alice Williams", "alice@company.com", "HR"}, + {"5", "Charlie Brown", "charlie@company.com", "Finance"} + }; + + for (int i = 0; i < compactData.length; i++) { + Row compactRow = table.createRow(10f); + compactRow.setFixedHeight(true); + for (int j = 0; j < 4; j++) { + Cell cell = compactRow.createCell( + (j == 0) ? 10 : 30, + compactData[i][j] + ); + cell.setFontSize(9f); + cell.setTopPadding(1f); + cell.setBottomPadding(1f); + if (i % 2 == 0) { + cell.setFillColor(new Color(236, 240, 241)); + } + } + } + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial11_FixedHeightRows.pdf"); + System.out.println("Tutorial 11 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java new file mode 100644 index 0000000..878814a --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java @@ -0,0 +1,305 @@ +package be.quodlibet.boxable.tutorial; + +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Cell; +import be.quodlibet.boxable.HorizontalAlignment; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.junit.Test; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; + +/** + * Tutorial 12: Advanced Features + * + * This tutorial demonstrates: + * - Rotated text (90 degrees) + * - Line spacing adjustments + * - Colspan cells (HTML colspan attribute) + * - Mixed advanced features + * - Creative table layouts + */ +public class Tutorial12_AdvancedFeatures { + + @Test + public void demonstrateAdvancedFeatures() throws IOException { + // Initialize PDF Document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Define table dimensions + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = page.getMediaBox().getHeight() - margin; + float bottomMargin = 70; + + // Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Title Row + Row titleRow = table.createRow(30f); + Cell titleCell = titleRow.createCell(100, "Tutorial 12: Advanced Features"); + titleCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + titleCell.setFontSize(16f); + titleCell.setFillColor(new Color(136, 78, 160)); // Purple background + titleCell.setTextColor(Color.WHITE); + titleCell.setAlign(HorizontalAlignment.CENTER); + + // Description + Row descRow = table.createRow(20f); + Cell descCell = descRow.createCell(100, + "Explore advanced Boxable features including rotated text, line spacing, and colspan."); + descCell.setFillColor(new Color(236, 240, 241)); + descCell.setAlign(HorizontalAlignment.CENTER); + + // Section 1: Rotated Text + addSectionHeader(table, "Rotated Text (90 Degrees)"); + + Row rotDesc = table.createRow(15f); + rotDesc.createCell(100, "Text can be rotated 90 degrees for vertical labels:"); + + Row rotRow = table.createRow(80f); + + Cell rotCell1 = rotRow.createCell(10, "VERTICAL"); + rotCell1.setTextRotated(true); + rotCell1.setAlign(HorizontalAlignment.CENTER); + rotCell1.setFillColor(new Color(174, 214, 241)); + + Cell rotCell2 = rotRow.createCell(10, "ROTATED"); + rotCell2.setTextRotated(true); + rotCell2.setAlign(HorizontalAlignment.CENTER); + rotCell2.setFillColor(new Color(255, 243, 224)); + + Cell normalCell = rotRow.createCell(80, + "Regular horizontal text

      " + + "The cells on the left demonstrate rotated text, which is useful for " + + "column headers in tables where space is limited. This feature allows " + + "you to create compact table designs."); + normalCell.setFillColor(Color.WHITE); + + // Section 2: Colspan + addSectionHeader(table, "Colspan - Spanning Multiple Columns"); + + Row colspanDesc = table.createRow(15f); + colspanDesc.createCell(100, "Cells can span multiple columns using HTML colspan attribute:"); + + // Row with colspan + Row colspanRow1 = table.createRow(20f); + Cell spanCell = colspanRow1.createCell(100, + "" + + "" + + "" + + "" + + "
      This cell spans 3 columns
      Column 1Column 2Column 3
      Spans 2 columnsColumn 3
      "); + spanCell.setFillColor(new Color(245, 245, 245)); + + // Section 3: Line Spacing + addSectionHeader(table, "Line Spacing"); + + Row lineDesc = table.createRow(15f); + lineDesc.createCell(100, "Comparing different line spacing:"); + + Row lineHeader = table.createRow(15f); + lineHeader.createCell(50, "Normal Line Spacing"); + lineHeader.createCell(50, "With Line Breaks"); + styleHeaderRow(lineHeader); + + Row lineRow = table.createRow(60f); + + Cell normalSpacing = lineRow.createCell(50, + "This is text with normal line spacing. " + + "Multiple sentences are displayed with standard spacing between them. " + + "This is the default behavior."); + normalSpacing.setFillColor(new Color(230, 245, 255)); + + Cell customSpacing = lineRow.createCell(50, + "First line
      " + + "Second line
      " + + "Third line
      " + + "Fourth line
      " + + "Fifth line"); + customSpacing.setFillColor(new Color(255, 250, 240)); + + // Section 4: Complex Table Layout + addSectionHeader(table, "Complex Layout Example"); + + Row complexDesc = table.createRow(15f); + complexDesc.createCell(100, "Combining multiple advanced features:"); + + // Complex header with rotated text + Row complexHeader = table.createRow(60f); + + Cell rotHeader1 = complexHeader.createCell(10, "Q1"); + rotHeader1.setTextRotated(true); + rotHeader1.setAlign(HorizontalAlignment.CENTER); + rotHeader1.setFillColor(new Color(52, 152, 219)); + rotHeader1.setTextColor(Color.WHITE); + + Cell rotHeader2 = complexHeader.createCell(10, "Q2"); + rotHeader2.setTextRotated(true); + rotHeader2.setAlign(HorizontalAlignment.CENTER); + rotHeader2.setFillColor(new Color(52, 152, 219)); + rotHeader2.setTextColor(Color.WHITE); + + Cell rotHeader3 = complexHeader.createCell(10, "Q3"); + rotHeader3.setTextRotated(true); + rotHeader3.setAlign(HorizontalAlignment.CENTER); + rotHeader3.setFillColor(new Color(52, 152, 219)); + rotHeader3.setTextColor(Color.WHITE); + + Cell rotHeader4 = complexHeader.createCell(10, "Q4"); + rotHeader4.setTextRotated(true); + rotHeader4.setAlign(HorizontalAlignment.CENTER); + rotHeader4.setFillColor(new Color(52, 152, 219)); + rotHeader4.setTextColor(Color.WHITE); + + Cell summaryHeader = complexHeader.createCell(60, + "2024 Quarterly Sales Summary

      " + + "This table demonstrates:
      " + + "• Rotated text for quarter labels
      " + + "• Nested tables for data
      " + + "• HTML formatting"); + summaryHeader.setFillColor(new Color(174, 214, 241)); + + // Data row with nested table + Row complexData = table.createRow(80f); + + Cell q1Data = complexData.createCell(10, + "" + + "" + + "" + + "
      Sales:
      $100K
      "); + q1Data.setAlign(HorizontalAlignment.CENTER); + q1Data.setFillColor(new Color(230, 245, 255)); + + Cell q2Data = complexData.createCell(10, + "" + + "" + + "" + + "
      Sales:
      $120K
      "); + q2Data.setAlign(HorizontalAlignment.CENTER); + q2Data.setFillColor(new Color(230, 245, 255)); + + Cell q3Data = complexData.createCell(10, + "" + + "" + + "" + + "
      Sales:
      $135K
      "); + q3Data.setAlign(HorizontalAlignment.CENTER); + q3Data.setFillColor(new Color(230, 245, 255)); + + Cell q4Data = complexData.createCell(10, + "" + + "" + + "" + + "
      Sales:
      $150K
      "); + q4Data.setAlign(HorizontalAlignment.CENTER); + q4Data.setFillColor(new Color(230, 245, 255)); + + Cell summaryData = complexData.createCell(60, + "Annual Summary:

      " + + "" + + "" + + "" + + "" + + "" + + "
      Total Sales:$505,000
      Growth Rate:+15%
      Best Quarter:Q4
      Target Achievement:102%
      "); + summaryData.setFillColor(Color.WHITE); + + // Section 5: Feature Combination Matrix + addSectionHeader(table, "Feature Combination Matrix"); + + Row matrixDesc = table.createRow(15f); + matrixDesc.createCell(100, "A practical example combining various features:"); + + Row matrixHeader = table.createRow(40f); + matrixHeader.createCell(20, ""); + + Cell mh1 = matrixHeader.createCell(20, "Feature A"); + mh1.setTextRotated(true); + mh1.setAlign(HorizontalAlignment.CENTER); + mh1.setFillColor(new Color(52, 73, 94)); + mh1.setTextColor(Color.WHITE); + + Cell mh2 = matrixHeader.createCell(20, "Feature B"); + mh2.setTextRotated(true); + mh2.setAlign(HorizontalAlignment.CENTER); + mh2.setFillColor(new Color(52, 73, 94)); + mh2.setTextColor(Color.WHITE); + + Cell mh3 = matrixHeader.createCell(20, "Feature C"); + mh3.setTextRotated(true); + mh3.setAlign(HorizontalAlignment.CENTER); + mh3.setFillColor(new Color(52, 73, 94)); + mh3.setTextColor(Color.WHITE); + + Cell mh4 = matrixHeader.createCell(20, "Notes"); + mh4.setAlign(HorizontalAlignment.CENTER); + mh4.setFillColor(new Color(52, 73, 94)); + mh4.setTextColor(Color.WHITE); + + // Matrix data rows + String[][] matrixData = { + {"Product X", "Yes", "Yes", "No", "High priority"}, + {"Product Y", "Yes", "No", "Yes", "Medium priority"}, + {"Product Z", "No", "Yes", "Yes", "Low priority"} + }; + + for (int i = 0; i < matrixData.length; i++) { + Row mRow = table.createRow(20f); + for (int j = 0; j < 5; j++) { + Cell mCell = mRow.createCell(20, matrixData[i][j]); + if (j > 0 && j < 4) { + mCell.setAlign(HorizontalAlignment.CENTER); + } + if (i % 2 == 0) { + mCell.setFillColor(new Color(236, 240, 241)); + } + } + } + + // Draw the table + table.draw(); + + // Save the document + File file = new File("target/tutorials/Tutorial12_AdvancedFeatures.pdf"); + System.out.println("Tutorial 12 PDF saved at: " + file.getAbsolutePath()); + file.getParentFile().mkdirs(); + document.save(file); + document.close(); + } + + /** + * Helper method to add a section header + */ + private void addSectionHeader(BaseTable table, String title) throws IOException { + Row sectionRow = table.createRow(18f); + Cell sectionCell = sectionRow.createCell(100, title); + sectionCell.setFillColor(new Color(44, 62, 80)); + sectionCell.setTextColor(Color.WHITE); + sectionCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + sectionCell.setAlign(HorizontalAlignment.CENTER); + } + + /** + * Helper method to style header rows + */ + private void styleHeaderRow(Row row) { + Color headerColor = new Color(52, 73, 94); + for (Cell cell : row.getCells()) { + cell.setFillColor(headerColor); + cell.setTextColor(Color.WHITE); + cell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); + } + } +} diff --git a/src/test/java/be/quodlibet/boxable/tutorial/TutorialRunner.java b/src/test/java/be/quodlibet/boxable/tutorial/TutorialRunner.java new file mode 100644 index 0000000..1ead15f --- /dev/null +++ b/src/test/java/be/quodlibet/boxable/tutorial/TutorialRunner.java @@ -0,0 +1,216 @@ +package be.quodlibet.boxable.tutorial; + +import org.junit.Test; + +import java.io.File; + +/** + * Tutorial Runner + * + * This class runs all Boxable tutorials and generates all PDF outputs. + * Each tutorial demonstrates different features of the Boxable library. + * + * To run all tutorials, execute this class's main method or run the test. + * All generated PDFs will be saved in the target/tutorials/ directory. + */ +public class TutorialRunner { + + @Test + public void runAllTutorials() throws Exception { + System.out.println("========================================"); + System.out.println(" Boxable Tutorial Runner"); + System.out.println("========================================"); + System.out.println(); + + // Create output directory + File tutorialsDir = new File("target/tutorials"); + if (!tutorialsDir.exists()) { + tutorialsDir.mkdirs(); + System.out.println("Created output directory: " + tutorialsDir.getAbsolutePath()); + } + System.out.println(); + + // Track results + int totalTutorials = 12; + int successful = 0; + int failed = 0; + + System.out.println("Running tutorials..."); + System.out.println(); + + // Tutorial 01: Basic Table + try { + System.out.print("[1/12] Running Tutorial01_BasicTable... "); + new Tutorial01_BasicTable().createBasicTable(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 02: HTML Formatting + try { + System.out.print("[2/12] Running Tutorial02_HtmlFormatting... "); + new Tutorial02_HtmlFormatting().demonstrateHtmlFormatting(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 03: Colors and Transparency + try { + System.out.print("[3/12] Running Tutorial03_ColorsAndTransparency... "); + new Tutorial03_ColorsAndTransparency().demonstrateColorsAndTransparency(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 04: Alignment + try { + System.out.print("[4/12] Running Tutorial04_Alignment... "); + new Tutorial04_Alignment().demonstrateAlignment(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 05: Images + try { + System.out.print("[5/12] Running Tutorial05_Images... "); + new Tutorial05_Images().demonstrateImages(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 06: Borders and Styling + try { + System.out.print("[6/12] Running Tutorial06_BordersAndStyling... "); + new Tutorial06_BordersAndStyling().demonstrateBordersAndStyling(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 07: Header Rows + try { + System.out.print("[7/12] Running Tutorial07_HeaderRows... "); + new Tutorial07_HeaderRows().demonstrateHeaderRows(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 08: Data Import + try { + System.out.print("[8/12] Running Tutorial08_DataImport... "); + new Tutorial08_DataImport().demonstrateDataImport(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 09: Multi-Page Tables + try { + System.out.print("[9/12] Running Tutorial09_MultiPageTables... "); + new Tutorial09_MultiPageTables().demonstrateMultiPageTables(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 10: Nested Tables + try { + System.out.print("[10/12] Running Tutorial10_NestedTables... "); + new Tutorial10_NestedTables().demonstrateNestedTables(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 11: Fixed Height Rows + try { + System.out.print("[11/12] Running Tutorial11_FixedHeightRows... "); + new Tutorial11_FixedHeightRows().demonstrateFixedHeightRows(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Tutorial 12: Advanced Features + try { + System.out.print("[12/12] Running Tutorial12_AdvancedFeatures... "); + new Tutorial12_AdvancedFeatures().demonstrateAdvancedFeatures(); + successful++; + System.out.println("✓ SUCCESS"); + } catch (Exception e) { + failed++; + System.out.println("✗ FAILED: " + e.getMessage()); + } + + // Print summary + System.out.println(); + System.out.println("========================================"); + System.out.println(" Summary"); + System.out.println("========================================"); + System.out.println("Total tutorials: " + totalTutorials); + System.out.println("Successful: " + successful); + System.out.println("Failed: " + failed); + System.out.println(); + System.out.println("Output directory: " + tutorialsDir.getAbsolutePath()); + System.out.println(); + + // List generated files + System.out.println("Generated PDF files:"); + File[] pdfFiles = tutorialsDir.listFiles((dir, name) -> name.endsWith(".pdf")); + if (pdfFiles != null && pdfFiles.length > 0) { + for (File pdfFile : pdfFiles) { + System.out.println(" - " + pdfFile.getName() + + " (" + String.format("%.2f", pdfFile.length() / 1024.0) + " KB)"); + } + } else { + System.out.println(" (No PDF files found)"); + } + + System.out.println(); + System.out.println("========================================"); + System.out.println(" Tutorial runner completed!"); + System.out.println("========================================"); + } + + /** + * Main method to run all tutorials from command line + */ + public static void main(String[] args) { + try { + TutorialRunner runner = new TutorialRunner(); + runner.runAllTutorials(); + } catch (Exception e) { + System.err.println("Error running tutorials: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } +} From 599e9b4ba48b968af4a6ffccd153e6cd5bc2b896 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 14:10:18 +0000 Subject: [PATCH 5/6] Update README and create comprehensive wiki documentation Co-authored-by: quodlibetbv <220320055+quodlibetbv@users.noreply.github.com> --- README.md | 46 ++++- wiki-docs/API-Reference.md | 333 +++++++++++++++++++++++++++++++ wiki-docs/FAQ.md | 311 +++++++++++++++++++++++++++++ wiki-docs/Getting-Started.md | 187 +++++++++++++++++ wiki-docs/HTML-Tags-Reference.md | 293 +++++++++++++++++++++++++++ wiki-docs/Home.md | 103 ++++++++++ 6 files changed, 1272 insertions(+), 1 deletion(-) create mode 100644 wiki-docs/API-Reference.md create mode 100644 wiki-docs/FAQ.md create mode 100644 wiki-docs/Getting-Started.md create mode 100644 wiki-docs/HTML-Tags-Reference.md create mode 100644 wiki-docs/Home.md diff --git a/README.md b/README.md index 3f4db38..ae3e166 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,51 @@ For other build systems, check the [Maven Central Repository](http://search.mave # Tutorial -A tutorial is being created and will be accessible at https://github.com/dhorions/boxable/wiki. +Comprehensive tutorials are now available in the test package! Each tutorial demonstrates specific features with well-documented, runnable examples: + +## Running the Tutorials + +You can run all tutorials at once using the Tutorial Runner: + +```bash +mvn test -Dtest=TutorialRunner +``` + +Or run individual tutorials: + +```bash +mvn test -Dtest=Tutorial01_BasicTable +``` + +All generated PDFs will be saved in the `target/tutorials/` directory. + +## Available Tutorials + +1. **Tutorial01_BasicTable** - Simple table creation, headers, and cell styling +2. **Tutorial02_HtmlFormatting** - All supported HTML tags including `` and `` +3. **Tutorial03_ColorsAndTransparency** - Cell colors, text colors, and alpha channel +4. **Tutorial04_Alignment** - Horizontal and vertical text alignment +5. **Tutorial05_Images** - Images in cells with scaling and padding control +6. **Tutorial06_BordersAndStyling** - Border styles, colors, widths, and selective borders +7. **Tutorial07_HeaderRows** - Single and multiple header rows with page repetition +8. **Tutorial08_DataImport** - Import data from CSV and Java Lists +9. **Tutorial09_MultiPageTables** - Large tables spanning multiple pages +10. **Tutorial10_NestedTables** - Tables within cells using HTML `` tags +11. **Tutorial11_FixedHeightRows** - Fixed-height rows with auto-fit text +12. **Tutorial12_AdvancedFeatures** - Rotated text, line spacing, and colspan + +## Tutorial Source Code + +All tutorial source code is available in `src/test/java/be/quodlibet/boxable/tutorial/`. + +Each tutorial is self-contained and includes: +- Detailed JavaDoc comments explaining the demonstrated features +- Well-structured, readable code +- Generated PDF output for visual reference + +## Wiki Documentation + +Detailed documentation is being created and will be accessible at https://github.com/dhorions/boxable/wiki. If you want to help, please let us know [here](https://github.com/dhorions/boxable/issues/41). # Usage examples diff --git a/wiki-docs/API-Reference.md b/wiki-docs/API-Reference.md new file mode 100644 index 0000000..6519521 --- /dev/null +++ b/wiki-docs/API-Reference.md @@ -0,0 +1,333 @@ +# API Reference + +This reference covers the main classes and methods in Boxable. + +## Core Classes + +### BaseTable + +The main class for creating tables. + +#### Constructor + +```java +BaseTable(float yStart, + float yStartNewPage, + float bottomMargin, + float width, + float margin, + PDDocument document, + PDPage page, + boolean drawLines, + boolean drawContent) +``` + +**Parameters:** +- `yStart` - Starting Y position on the current page +- `yStartNewPage` - Y position for new pages (usually same as yStart) +- `bottomMargin` - Bottom margin (when to create new page) +- `width` - Table width in points +- `margin` - Left margin in points +- `document` - PDDocument instance +- `page` - Current PDPage +- `drawLines` - Whether to draw cell borders +- `drawContent` - Whether to draw cell content + +#### Key Methods + +```java +// Create a new row +Row createRow(float height) + +// Add a header row (repeats on each page) +void addHeaderRow(Row row) + +// Draw the table +float draw() // Returns final Y position + +// Get current page (may change after draw) +PDPage getCurrentPage() + +// Set outer border style +void setOuterBorderStyle(LineStyle style) +``` + +### Row + +Represents a table row. + +#### Key Methods + +```java +// Create a text cell +Cell createCell(float widthPercent, String text) + +// Create an image cell +ImageCell createImageCell(float widthPercent, Image image) + +// Create a table cell (nested table via HTML) +Cell createTableCell(float widthPercent, String htmlTable, + PDDocument doc, PDPage page, float yStart, + float bottomMargin, float margin) + +// Set row height +void setHeight(float height) + +// Set fixed height (auto-shrink text) +void setFixedHeight(boolean fixed) + +// Get all cells in row +List> getCells() +``` + +### Cell + +Represents a table cell. + +#### Styling Methods + +```java +// Colors +void setFillColor(Color color) +void setTextColor(Color color) + +// Text properties +void setFont(PDFont font) +void setFontSize(float size) +void setTextRotated(boolean rotated) + +// Alignment +void setAlign(HorizontalAlignment align) +void setValign(VerticalAlignment align) + +// Borders +void setBorderStyle(LineStyle style) +void setTopBorderStyle(LineStyle style) +void setBottomBorderStyle(LineStyle style) +void setLeftBorderStyle(LineStyle style) +void setRightBorderStyle(LineStyle style) + +// Padding +void setTopPadding(float padding) +void setBottomPadding(float padding) +void setLeftPadding(float padding) +void setRightPadding(float padding) + +// Content +String getText() +void setText(String text) +``` + +### ImageCell + +Extends Cell for image content. + +```java +// Get the image +Image getImage() + +// Inherited from Cell: all styling methods +``` + +### DataTable + +Helper class for importing data. + +#### Constructor + +```java +DataTable(BaseTable table, PDPage page) +DataTable(BaseTable table, PDPage page, List colWidths) +``` + +#### Key Methods + +```java +// Import from CSV +void addCsvToTable(String csvData, boolean hasHeader, char delimiter) + +// Import from List +void addListToTable(List data, boolean hasHeader) + +// Style templates +Cell getHeaderCellTemplate() +Cell getDataCellTemplateEven() +Cell getDataCellTemplateOdd() +List getDataCellTemplateEvenList() +List getDataCellTemplateOddList() +Cell getFirstColumnCellTemplate() +Cell getLastColumnCellTemplate() +``` + +### LineStyle + +Represents border styling. + +#### Constructor + +```java +LineStyle(Color color, float width) +``` + +**Example:** +```java +LineStyle redBorder = new LineStyle(Color.RED, 2f); +cell.setBorderStyle(redBorder); +``` + +### Image + +Wrapper for images in cells. + +#### Constructor + +```java +Image(BufferedImage image) +``` + +**Example:** +```java +BufferedImage buffImg = ImageIO.read(new File("image.png")); +Image image = new Image(buffImg); +ImageCell cell = row.createImageCell(50, image); +``` + +## Enums + +### HorizontalAlignment + +```java +HorizontalAlignment.LEFT +HorizontalAlignment.CENTER +HorizontalAlignment.RIGHT +``` + +### VerticalAlignment + +```java +VerticalAlignment.TOP +VerticalAlignment.MIDDLE +VerticalAlignment.BOTTOM +``` + +## Constants + +### DataTable + +```java +DataTable.HASHEADER // = true (data has header row) +DataTable.NOHEADER // = false (no header row) +``` + +## Common Patterns + +### Creating a Basic Table + +```java +PDDocument doc = new PDDocument(); +PDPage page = new PDPage(); +doc.addPage(page); + +float margin = 50; +float yStart = page.getMediaBox().getHeight() - margin; +float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + +BaseTable table = new BaseTable(yStart, yStart, 70, tableWidth, + margin, doc, page, true, true); + +Row row = table.createRow(20f); +Cell cell = row.createCell(100, "Hello World"); + +table.draw(); +doc.save("output.pdf"); +doc.close(); +``` + +### Styled Header + +```java +Row header = table.createRow(20f); +Cell headerCell = header.createCell(100, "Header"); +headerCell.setFillColor(new Color(52, 152, 219)); +headerCell.setTextColor(Color.WHITE); +headerCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); +headerCell.setAlign(HorizontalAlignment.CENTER); +table.addHeaderRow(header); +``` + +### Alternating Row Colors + +```java +for (int i = 0; i < data.length; i++) { + Row row = table.createRow(15f); + Cell cell = row.createCell(100, data[i]); + + if (i % 2 == 0) { + cell.setFillColor(new Color(236, 240, 241)); + } else { + cell.setFillColor(Color.WHITE); + } +} +``` + +### Custom Borders + +```java +// Thick red border +cell.setBorderStyle(new LineStyle(Color.RED, 3f)); + +// No borders +cell.setBorderStyle(null); + +// Bottom border only +cell.setTopBorderStyle(null); +cell.setBottomBorderStyle(new LineStyle(Color.BLACK, 2f)); +cell.setLeftBorderStyle(null); +cell.setRightBorderStyle(null); + +// Outer border only on table +table.setOuterBorderStyle(new LineStyle(Color.BLACK, 2f)); +``` + +### Transparent Colors + +```java +// Alpha channel: 0 = fully transparent, 255 = fully opaque +Color transparentRed = new Color(255, 0, 0, 128); // 50% transparent +cell.setFillColor(transparentRed); +``` + +### HTML Formatting + +```java +String html = "Bold and italic
      " + + "H2O and E=mc2"; +Cell cell = row.createCell(100, html); +``` + +### Multi-Column Cells + +```java +Row row = table.createRow(20f); +Cell wideCell = row.createCell(70, "Wide cell"); +Cell narrowCell1 = row.createCell(15, "Narrow 1"); +Cell narrowCell2 = row.createCell(15, "Narrow 2"); +``` + +## Best Practices + +1. **Always call `draw()`** before saving the document +2. **Store return value of `draw()`** if creating multiple tables +3. **Check `getCurrentPage()`** after `draw()` for page transitions +4. **Use percentage widths** that sum to 100 +5. **Add header rows before data rows** +6. **Set `drawContent` and `drawLines`** according to your needs +7. **Use templates in DataTable** for consistent styling +8. **Close PDDocument** after saving + +## See Also + +- [Getting Started Guide](Getting-Started) +- [All Tutorials](Tutorial-01-Basic-Table) +- [HTML Tags Reference](HTML-Tags-Reference) +- [FAQ](FAQ) diff --git a/wiki-docs/FAQ.md b/wiki-docs/FAQ.md new file mode 100644 index 0000000..3caf595 --- /dev/null +++ b/wiki-docs/FAQ.md @@ -0,0 +1,311 @@ +# Frequently Asked Questions (FAQ) + +## General Questions + +### What is Boxable? + +Boxable is a Java library that simplifies the creation of tables in PDF documents. It's built on top of Apache PDFBox and provides a high-level API for creating professional tables with rich formatting. + +### What version of Java is required? + +Boxable requires Java 8 or higher. The library is compiled with Java 17 but is compatible with Java 8+. + +### Is Boxable production-ready? + +Yes! Boxable is actively maintained and used in production applications. Version 1.8.2-RC1 is the current release candidate. + +## Installation and Setup + +### How do I add Boxable to my project? + +**Maven:** +```xml + + com.github.dhorions + boxable + 1.8.2-RC1 + +``` + +**Gradle:** +```gradle +implementation 'com.github.dhorions:boxable:1.8.2-RC1' +``` + +### What dependencies does Boxable have? + +Boxable depends on: +- Apache PDFBox 3.0.6 +- Apache Commons CSV (for CSV import) +- JSoup (for HTML parsing) + +These are automatically included when you add Boxable to your project. + +## Table Creation + +### How do I create a simple table? + +See the [Getting Started](Getting-Started) guide or [Tutorial 01](Tutorial-01-Basic-Table) for a complete example. + +### Why isn't my table showing up in the PDF? + +Make sure you call `table.draw()` before saving the document: + +```java +table.draw(); // Don't forget this! +document.save("output.pdf"); +``` + +### How do I control table width? + +The table width is specified when creating the BaseTable: + +```java +float tableWidth = page.getMediaBox().getWidth() - (2 * margin); +BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); +``` + +### Can I create tables without borders? + +Yes! Set `drawLines` to `false` when creating the table: + +```java +BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + false, true); // false = no borders +``` + +You can also set `setOuterBorderStyle()` for custom border control. + +## Content and Formatting + +### How do I add colors to cells? + +Use `setFillColor()` for background and `setTextColor()` for text: + +```java +Cell cell = row.createCell(50, "Content"); +cell.setFillColor(Color.BLUE); +cell.setTextColor(Color.WHITE); +``` + +### Can I use HTML formatting in cells? + +Yes! Boxable supports many HTML tags including ``, ``, ``, ``, `
      `, ``, ``, lists, and more. See [HTML Tags Reference](HTML-Tags-Reference) for details. + +### How do I add images to cells? + +Use `createImageCell()`: + +```java +BufferedImage bufferedImage = ImageIO.read(new File("image.png")); +Image image = new Image(bufferedImage); +ImageCell cell = row.createImageCell(50, image); +``` + +See [Tutorial 05: Images](Tutorial-05-Images) for examples. + +### How do I rotate text? + +Use `setTextRotated(true)`: + +```java +Cell cell = row.createCell(10, "VERTICAL"); +cell.setTextRotated(true); +``` + +### Can I change font size? + +Yes: + +```java +cell.setFontSize(14f); +``` + +## Multi-Page Tables + +### Do tables automatically span multiple pages? + +Yes! When a table reaches the bottom margin, Boxable automatically creates a new page and continues the table. + +### How do I make headers repeat on each page? + +Use `addHeaderRow()`: + +```java +Row headerRow = table.createRow(20f); +// ... create header cells ... +table.addHeaderRow(headerRow); +``` + +Headers added this way automatically repeat on each new page. + +### Can I have multiple header rows? + +Yes! Call `addHeaderRow()` multiple times: + +```java +table.addHeaderRow(headerRow1); +table.addHeaderRow(headerRow2); +table.addHeaderRow(headerRow3); +``` + +See [Tutorial 07: Header Rows](Tutorial-07-Header-Rows). + +## Data Import + +### How do I import data from CSV? + +Use the `DataTable` class: + +```java +String csvData = "Name;Age\\nJohn;30\\nJane;25"; +BaseTable baseTable = new BaseTable(...); +DataTable dataTable = new DataTable(baseTable, page); +dataTable.addCsvToTable(csvData, DataTable.HASHEADER, ';'); +baseTable.draw(); +``` + +### Can I import from Java Lists? + +Yes: + +```java +List data = new ArrayList<>(); +data.add(new ArrayList<>(Arrays.asList("Name", "Age"))); +data.add(new ArrayList<>(Arrays.asList("John", "30"))); + +DataTable dataTable = new DataTable(baseTable, page); +dataTable.addListToTable(data, DataTable.HASHEADER); +``` + +See [Tutorial 08: Data Import](Tutorial-08-Data-Import). + +### How do I control column widths when importing? + +Pass a list of relative widths: + +```java +DataTable dataTable = new DataTable(baseTable, page, + Arrays.asList(3f, 1f, 1f, 1f)); +// First column is 3x wider than others +``` + +## Performance + +### How do I handle very large tables? + +Boxable handles large tables efficiently. For best performance: +- Use `drawContent = true` and `drawLines = true` only when needed +- Consider breaking very large tables into multiple tables +- See [Tutorial 09: Multi-Page Tables](Tutorial-09-MultiPage-Tables) + +### Does Boxable use a lot of memory? + +Boxable is designed to be memory-efficient. It processes rows as they're added rather than storing everything in memory. + +## Advanced Features + +### Can I create nested tables? + +Yes! Use HTML `
      ` tags within cell content: + +```java +String nestedTable = "
      " + + "" + + "" + + "
      NameValue
      Item 1100
      "; +Cell cell = row.createCell(50, nestedTable); +``` + +See [Tutorial 10: Nested Tables](Tutorial-10-Nested-Tables). + +### What are fixed-height rows? + +Fixed-height rows automatically shrink text to fit a specified height: + +```java +Row row = table.createRow(12f); +row.setFixedHeight(true); // Text will shrink to fit 12pt height +``` + +See [Tutorial 11: Fixed Height Rows](Tutorial-11-Fixed-Height-Rows). + +### Can cells span multiple columns? + +Yes, in nested tables using `colspan`: + +```html +" + + +
      Spans 3 columns
      Col1Col2Col3
      " +``` + +## Troubleshooting + +### My text is cut off + +Possible solutions: +- Increase row height +- Use fixed-height rows with auto-shrink +- Add line breaks with `
      ` tags +- Reduce font size + +### Colors aren't showing + +Make sure you set both `drawLines` and `drawContent` to `true`: + +```java +BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); // both true +``` + +### Characters are showing as boxes + +The default font (Helvetica) doesn't support all Unicode characters. Use: +- Standard ASCII characters +- HTML entity references +- Or load a custom font that supports your characters + +### Table positioning is wrong + +Make sure your `yStart` calculation accounts for margins: + +```java +float yStart = page.getMediaBox().getHeight() - margin; +``` + +## Getting Help + +### Where can I find more examples? + +Run the built-in tutorials: + +```bash +mvn test -Dtest=TutorialRunner +``` + +This generates 12 PDF examples covering all features. + +### Where do I report bugs? + +Report issues on GitHub: https://github.com/dhorions/boxable/issues + +### How can I contribute? + +Contributions are welcome! See issue [#41](https://github.com/dhorions/boxable/issues/41) for documentation needs. + +### Is there commercial support? + +Boxable is open source. For commercial support inquiries, contact the maintainers through GitHub. + +## See Also + +- [Getting Started](Getting-Started) +- [All Tutorials](Tutorial-01-Basic-Table) +- [API Reference](API-Reference) +- [HTML Tags Reference](HTML-Tags-Reference) diff --git a/wiki-docs/Getting-Started.md b/wiki-docs/Getting-Started.md new file mode 100644 index 0000000..f1edb31 --- /dev/null +++ b/wiki-docs/Getting-Started.md @@ -0,0 +1,187 @@ +# Getting Started with Boxable + +This guide will help you get started with Boxable and create your first PDF table. + +## Installation + +### Maven + +Add the following dependency to your `pom.xml`: + +```xml + + com.github.dhorions + boxable + 1.8.2-RC1 + +``` + +### Gradle + +Add to your `build.gradle`: + +```gradle +implementation 'com.github.dhorions:boxable:1.8.2-RC1' +``` + +## Your First Table + +Let's create a simple PDF with a table: + +```java +import be.quodlibet.boxable.BaseTable; +import be.quodlibet.boxable.Row; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; + +import java.io.IOException; + +public class FirstTable { + public static void main(String[] args) throws IOException { + // Step 1: Create a PDF document + PDDocument document = new PDDocument(); + PDPage page = new PDPage(); + document.addPage(page); + + // Step 2: Define table parameters + float margin = 50; + float yStart = page.getMediaBox().getHeight() - margin; + float tableWidth = page.getMediaBox().getWidth() - (2 * margin); + float yStartNewPage = yStart; + float bottomMargin = 70; + + // Step 3: Create the table + BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, + tableWidth, margin, document, page, + true, true); + + // Step 4: Create header row + Row headerRow = table.createRow(20f); + headerRow.createCell(50, "Name"); + headerRow.createCell(50, "Age"); + + // Step 5: Create data rows + Row row1 = table.createRow(15f); + row1.createCell(50, "John Doe"); + row1.createCell(50, "30"); + + Row row2 = table.createRow(15f); + row2.createCell(50, "Jane Smith"); + row2.createCell(50, "25"); + + // Step 6: Draw the table + table.draw(); + + // Step 7: Save and close + document.save("first-table.pdf"); + document.close(); + + System.out.println("PDF created successfully!"); + } +} +``` + +## Key Concepts + +### BaseTable + +`BaseTable` is the main class for creating tables. It requires: +- `yStart` - Starting Y position on the page +- `yStartNewPage` - Y position for new pages (usually same as yStart) +- `bottomMargin` - Margin at the bottom of the page +- `tableWidth` - Width of the table +- `margin` - Left margin +- `document` - PDDocument instance +- `page` - Current PDPage +- `drawLines` - Whether to draw cell borders (true/false) +- `drawContent` - Whether to draw cell content (true/false) + +### Row + +`Row` represents a table row. Create rows with: +```java +Row row = table.createRow(heightInPoints); +``` + +### Cell + +`Cell` represents a table cell. Create cells with: +```java +Cell cell = row.createCell(widthPercentage, "Content"); +``` + +The width is specified as a percentage of the table width. + +## Running the Tutorials + +The library includes 12 comprehensive tutorials. Run them all: + +```bash +mvn test -Dtest=TutorialRunner +``` + +Or run individually: + +```bash +mvn test -Dtest=Tutorial01_BasicTable +mvn test -Dtest=Tutorial02_HtmlFormatting +# ... and so on +``` + +## Next Steps + +- Explore the [Basic Table Tutorial](Tutorial-01-Basic-Table) +- Learn about [HTML Formatting](Tutorial-02-HTML-Formatting) +- Check out [Colors and Transparency](Tutorial-03-Colors-And-Transparency) +- View the complete [API Reference](API-Reference) + +## Common Patterns + +### Adding a Header Row + +```java +Row headerRow = table.createRow(20f); +// ... create cells ... +table.addHeaderRow(headerRow); +``` + +Headers automatically repeat on each new page. + +### Setting Cell Colors + +```java +Cell cell = row.createCell(50, "Content"); +cell.setFillColor(Color.BLUE); +cell.setTextColor(Color.WHITE); +``` + +### Importing CSV Data + +```java +String csvData = "Name;Age\\nJohn;30\\nJane;25"; +DataTable dataTable = new DataTable(baseTable, page); +dataTable.addCsvToTable(csvData, DataTable.HASHEADER, ';'); +``` + +## Troubleshooting + +### Table Not Visible + +Make sure you call `table.draw()` before saving the document. + +### Text Overflow + +If text is too large for a cell: +- Increase row height +- Use fixed-height rows with auto-fit +- Wrap text with `
      ` tags + +### Multiple Pages + +Boxable automatically creates new pages when content exceeds the page height. Header rows are automatically repeated. + +## Further Reading + +- [All Tutorials](Tutorial-01-Basic-Table) +- [HTML Tags Reference](HTML-Tags-Reference) +- [FAQ](FAQ) diff --git a/wiki-docs/HTML-Tags-Reference.md b/wiki-docs/HTML-Tags-Reference.md new file mode 100644 index 0000000..68616c2 --- /dev/null +++ b/wiki-docs/HTML-Tags-Reference.md @@ -0,0 +1,293 @@ +# HTML Tags Reference + +Boxable supports a subset of HTML tags for rich text formatting in table cells. This reference covers all supported tags with examples. + +## Text Formatting Tags + +### Bold: `` + +Makes text bold. + +**Example:** +```html +"This is bold text in a cell" +``` + +**Output:** This is **bold text** in a cell + +### Italic: `` + +Makes text italic. + +**Example:** +```html +"This is italic text in a cell" +``` + +**Output:** This is *italic text* in a cell + +### Underline: `` + +Underlines text. + +**Example:** +```html +"This is underlined text in a cell" +``` + +**Output:** This is underlined text in a cell + +### Strikethrough: `` + +Strikes through text. + +**Example:** +```html +"This is strikethrough text in a cell" +``` + +**Output:** This is ~~strikethrough text~~ in a cell + +## Heading Tags + +### Headings: `

      ` through `

      ` + +Creates headings of different sizes. + +**Example:** +```html +"

      Largest Heading

      " +"

      Second Level

      " +"

      Third Level

      " +"
      Smallest Heading
      " +``` + +**Note:** Headings have different font sizes with h1 being the largest. + +## Superscript and Subscript (New in v1.8.2) + +### Superscript: `` + +Raises text above the baseline (useful for exponents, footnotes). + +**Example:** +```html +"E=mc2" +"x2 + y2 = z2" +``` + +**Output:** E=mc² and x² + y² = z² + +**Common Uses:** +- Mathematical exponents +- Ordinal indicators (1ˢᵗ, 2ⁿᵈ) +- Footnote references + +### Subscript: `` + +Lowers text below the baseline (useful for chemical formulas). + +**Example:** +```html +"H2O" +"CO2" +``` + +**Output:** H₂O and CO₂ + +**Common Uses:** +- Chemical formulas +- Mathematical subscripts +- Array indices + +### Combined Super/Subscript + +You can combine both: + +**Example:** +```html +"Ani" +``` + +## Line Breaks and Paragraphs + +### Line Break: `
      ` or `
      ` + +Inserts a line break. + +**Example:** +```html +"First line
      Second line
      Third line" +``` + +**Output:** +``` +First line +Second line +Third line +``` + +### Paragraph: `

      ` + +Creates a paragraph with spacing. + +**Example:** +```html +"

      First paragraph

      Second paragraph

      " +``` + +## Lists + +### Unordered List: `
        ` and `
      • ` + +Creates a bulleted list. + +**Example:** +```html +"
          +
        • First item
        • +
        • Second item
        • +
        • Third item
        • +
        " +``` + +**Output:** +- First item +- Second item +- Third item + +### Ordered List: `
          ` and `
        1. ` + +Creates a numbered list. + +**Example:** +```html +"
            +
          1. First step
          2. +
          3. Second step
          4. +
          5. Third step
          6. +
          " +``` + +**Output:** +1. First step +2. Second step +3. Third step + +## Tables (Nested) + +### Nested Table: ``, ``, `" + "" + "
          ` + +Creates a table within a cell. + +**Example:** +```html +" + + + +
          NameValue
          Item 1100
          Item 2200
          " +``` + +### Colspan in Nested Tables + +**Example:** +```html +" + + +
          Spanning Header
          Col 1Col 2
          " +``` + +## Nesting Tags + +Tags can be nested for combined effects: + +**Example:** +```html +"Bold and Italic" +"Bold Underlined" +"Bold with italic inside" +"Underlined with superscript" +``` + +**Complex Example:** +```html +"Product: Widget X
          +Formula: H2O + CO2
          +Price: $99.99*" +``` + +## Best Practices + +### DO: +- ✓ Close all tags properly +- ✓ Use proper nesting (inner tags close before outer tags) +- ✓ Use semantic tags for meaning (`` for emphasis, `` for exponents) +- ✓ Test complex HTML in the tutorial examples first + +### DON'T: +- ✗ Use unsupported HTML tags (they will be ignored) +- ✗ Use CSS styles (not supported) +- ✗ Nest lists inside lists (not fully supported) +- ✗ Use special Unicode characters not in the default font + +## Tag Support Matrix + +| Tag | Supported | Notes | +|-----|-----------|-------| +| `` | ✓ | Bold text | +| `` | ✓ | Italic text | +| `` | ✓ | Underlined text | +| `` | ✓ | Strikethrough | +| `

          `-`

          ` | ✓ | Different heading sizes | +| `` | ✓ | Superscript (v1.8.2+) | +| `` | ✓ | Subscript (v1.8.2+) | +| `
          ` | ✓ | Line break | +| `

          ` | ✓ | Paragraph | +| `

            `, `
              `, `
            1. ` | ✓ | Lists | +| ``, ``, `" + "" + "
              ` | ✓ | Nested tables | +| `colspan` | ✓ | Column spanning (in nested tables) | +| `` | ✗ | Not supported | +| `
              ` | ✗ | Not supported | +| CSS | ✗ | Not supported | + +## Examples by Use Case + +### Scientific Formulas +```html +"Water: H2O
              +Carbon Dioxide: CO2
              +Einstein's Equation: E=mc2" +``` + +### Product Information +```html +"Widget ProTM
              +The professional choice
              +Only $99.99" +``` + +### Instructions +```html +"
                +
              1. Connect to power
              2. +
              3. Press Start
              4. +
              5. Wait for Ready indicator
              6. +
              " +``` + +### Data Table +```html +" + + + +
              MetricValue
              CPU2.4 GHz
              RAM16 GB
              " +``` + +## See Also + +- [Tutorial 02: HTML Formatting](Tutorial-02-HTML-Formatting) - Live examples +- [Tutorial 10: Nested Tables](Tutorial-10-Nested-Tables) - Nested table examples +- [API Reference](API-Reference) - Cell class documentation diff --git a/wiki-docs/Home.md b/wiki-docs/Home.md new file mode 100644 index 0000000..a084c00 --- /dev/null +++ b/wiki-docs/Home.md @@ -0,0 +1,103 @@ +# Home + +Welcome to the Boxable library documentation! + +## What is Boxable? + +Boxable is a high-level Java library built on top of Apache PDFBox that makes it easy to create tables in PDF documents. It provides a simple API for generating professional-looking tables with rich formatting options. + +## Key Features + +- **Easy table creation** - Simple API for building tables programmatically +- **Rich HTML formatting** - Support for HTML tags including ``, ``, ``, ``, `

              `-`

              `, ``, ``, `
                `, `
                  `, `
                1. `, and more +- **Data import** - Import data from CSV files or Java Lists +- **Multi-page support** - Tables automatically span multiple pages with repeating headers +- **Advanced styling** - Cell colors, borders, alignment, transparency, images, and more +- **Nested tables** - Create complex layouts with tables inside cells +- **Fixed-height rows** - Auto-fit text in constrained spaces +- **Rotated text** - 90-degree rotation for vertical labels + +## Quick Start + +### Maven Dependency + +```xml + + com.github.dhorions + boxable + 1.8.2-RC1 + +``` + +### Simple Example + +```java +// Initialize PDF document +PDDocument document = new PDDocument(); +PDPage page = new PDPage(); +document.addPage(page); + +// Create table +float margin = 50; +float yStart = page.getMediaBox().getHeight() - margin; +float tableWidth = page.getMediaBox().getWidth() - (2 * margin); +float bottomMargin = 70; + +BaseTable table = new BaseTable(yStart, yStart, bottomMargin, + tableWidth, margin, document, page, + true, true); + +// Add rows +Row headerRow = table.createRow(20f); +headerRow.createCell(50, "Name"); +headerRow.createCell(50, "Value"); + +Row dataRow = table.createRow(15f); +dataRow.createCell(50, "Item 1"); +dataRow.createCell(50, "Value 1"); + +// Draw and save +table.draw(); +document.save("output.pdf"); +document.close(); +``` + +## Documentation Structure + +- **[Getting Started](Getting-Started)** - Installation and first steps +- **[Tutorials](Tutorial-01-Basic-Table)** - 12 comprehensive tutorials with examples +- **[API Reference](API-Reference)** - Detailed API documentation +- **[HTML Tags Reference](HTML-Tags-Reference)** - Supported HTML tags +- **[FAQ](FAQ)** - Frequently asked questions + +## Runnable Tutorials + +The library includes 12 runnable tutorials that demonstrate all features: + +1. [Basic Table](Tutorial-01-Basic-Table) - Simple table creation +2. [HTML Formatting](Tutorial-02-HTML-Formatting) - Text formatting with HTML +3. [Colors and Transparency](Tutorial-03-Colors-And-Transparency) - Color management +4. [Alignment](Tutorial-04-Alignment) - Text alignment options +5. [Images](Tutorial-05-Images) - Images in cells +6. [Borders and Styling](Tutorial-06-Borders-And-Styling) - Border customization +7. [Header Rows](Tutorial-07-Header-Rows) - Repeating headers +8. [Data Import](Tutorial-08-Data-Import) - CSV and List imports +9. [Multi-Page Tables](Tutorial-09-MultiPage-Tables) - Page spanning +10. [Nested Tables](Tutorial-10-Nested-Tables) - Tables within cells +11. [Fixed Height Rows](Tutorial-11-Fixed-Height-Rows) - Auto-fit text +12. [Advanced Features](Tutorial-12-Advanced-Features) - Rotated text, colspan + +Run all tutorials: +```bash +mvn test -Dtest=TutorialRunner +``` + +## Community and Support + +- **GitHub Repository**: https://github.com/dhorions/boxable +- **Issues**: https://github.com/dhorions/boxable/issues +- **Contributing**: Contributions are welcome! See issue [#41](https://github.com/dhorions/boxable/issues/41) + +## License + +Licensed under the Apache License, Version 2.0. See the LICENSE file for details. From 3d82a09b51effece3d0fdf961bb73a790b74f5f7 Mon Sep 17 00:00:00 2001 From: Dries Horions Date: Fri, 13 Feb 2026 09:18:01 +0100 Subject: [PATCH 6/6] Tutorials for wiki --- src/main/java/be/quodlibet/boxable/Row.java | 17 + .../boxable/BottomTablePlacementTest.java | 3 - .../tutorial/Tutorial01_BasicTable.java | 12 +- .../tutorial/Tutorial04_Alignment.java | 2 +- .../tutorial/Tutorial07_HeaderRows.java | 8 +- .../tutorial/Tutorial08_DataImport.java | 8 +- .../tutorial/Tutorial09_MultiPageTables.java | 4 +- .../tutorial/Tutorial10_NestedTables.java | 67 +++- .../tutorial/Tutorial12_AdvancedFeatures.java | 12 +- wiki-docs/API-Reference.md | 333 ------------------ wiki-docs/FAQ.md | 311 ---------------- wiki-docs/Getting-Started.md | 187 ---------- wiki-docs/HTML-Tags-Reference.md | 293 --------------- wiki-docs/Home.md | 103 ------ 14 files changed, 99 insertions(+), 1261 deletions(-) delete mode 100644 wiki-docs/API-Reference.md delete mode 100644 wiki-docs/FAQ.md delete mode 100644 wiki-docs/Getting-Started.md delete mode 100644 wiki-docs/HTML-Tags-Reference.md delete mode 100644 wiki-docs/Home.md diff --git a/src/main/java/be/quodlibet/boxable/Row.java b/src/main/java/be/quodlibet/boxable/Row.java index 41085dc..3ff9069 100644 --- a/src/main/java/be/quodlibet/boxable/Row.java +++ b/src/main/java/be/quodlibet/boxable/Row.java @@ -102,6 +102,23 @@ public Cell createImageCell(float width, Image img, HorizontalAlignment align return cell; } + /** + *

                  + * Creates a table cell with provided width and table data, using the table's + * document, page, yStart, and margins. + *

                  + * + * @param width + * Table width + * @param tableData + * Table's data (HTML table tags) + * @return {@link TableCell} with provided width and table data + */ + public TableCell createTableCell(float width, String tableData) { + return createTableCell(width, tableData, table.getDocument(), table.getCurrentPage(), table.yStart, + table.pageTopMargin, table.pageBottomMargin); + } + /** *

                  * Creates a table cell with provided width and table data diff --git a/src/test/java/be/quodlibet/boxable/BottomTablePlacementTest.java b/src/test/java/be/quodlibet/boxable/BottomTablePlacementTest.java index 6258416..b967a4d 100644 --- a/src/test/java/be/quodlibet/boxable/BottomTablePlacementTest.java +++ b/src/test/java/be/quodlibet/boxable/BottomTablePlacementTest.java @@ -2,9 +2,6 @@ import java.io.File; import java.io.IOException; -import be.quodlibet.boxable.page.PageProvider; -import java.util.ArrayList; -import java.util.List; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java index fb86dd5..32478c8 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial01_BasicTable.java @@ -64,10 +64,10 @@ public void createBasicTable() throws IOException { // Step 6: Create header row Row headerRow = table.createRow(20f); - Cell headerCell1 = headerRow.createCell(25, "Product"); - Cell headerCell2 = headerRow.createCell(25, "Category"); - Cell headerCell3 = headerRow.createCell(25, "Price"); - Cell headerCell4 = headerRow.createCell(25, "Stock"); + headerRow.createCell(25, "Product"); + headerRow.createCell(25, "Category"); + headerRow.createCell(25, "Price"); + headerRow.createCell(25, "Stock"); // Style header cells Color headerColor = new Color(52, 152, 219); // Blue @@ -100,8 +100,8 @@ public void createBasicTable() throws IOException { // Alternate row colors for better readability Color rowColor = (i % 2 == 0) ? white : lightGray; - Cell cell1 = dataRow.createCell(25, data[i][0]); - Cell cell2 = dataRow.createCell(25, data[i][1]); + dataRow.createCell(25, data[i][0]); + dataRow.createCell(25, data[i][1]); Cell cell3 = dataRow.createCell(25, data[i][2]); Cell cell4 = dataRow.createCell(25, data[i][3]); diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java index 0649f96..522a397 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial04_Alignment.java @@ -184,7 +184,7 @@ public void demonstrateAlignment() throws IOException { addSectionHeader(table, "Practical Example: Invoice Table"); Row invoiceHeader = table.createRow(15f); - Cell itemHeader = invoiceHeader.createCell(40, "Item"); + invoiceHeader.createCell(40, "Item"); Cell qtyHeader = invoiceHeader.createCell(20, "Qty"); Cell priceHeader = invoiceHeader.createCell(20, "Price"); Cell totalHeader = invoiceHeader.createCell(20, "Total"); diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java index 2311cd5..3cc8a3a 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial07_HeaderRows.java @@ -66,10 +66,10 @@ public void demonstrateHeaderRows() throws IOException { addSectionHeader(table, "Single Header Row"); Row singleHeader = table.createRow(20f); - Cell col1 = singleHeader.createCell(25, "Name"); - Cell col2 = singleHeader.createCell(25, "Age"); - Cell col3 = singleHeader.createCell(25, "City"); - Cell col4 = singleHeader.createCell(25, "Country"); + singleHeader.createCell(25, "Name"); + singleHeader.createCell(25, "Age"); + singleHeader.createCell(25, "City"); + singleHeader.createCell(25, "Country"); styleHeaderRow(singleHeader); table.addHeaderRow(singleHeader); diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java index e8b6c49..7ee3bb3 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial08_DataImport.java @@ -180,10 +180,10 @@ public void demonstrateDataImport() throws IOException { dt4.getHeaderCellTemplate().setTextColor(Color.WHITE); // Customize data cell styling for alternating rows - for (Cell cell : dt4.getDataCellTemplateEvenList()) { + for (Cell cell : dt4.getDataCellTemplateEvenList()) { cell.setFillColor(Color.WHITE); } - for (Cell cell : dt4.getDataCellTemplateOddList()) { + for (Cell cell : dt4.getDataCellTemplateOddList()) { cell.setFillColor(new Color(236, 240, 241)); } @@ -221,10 +221,10 @@ public void demonstrateDataImport() throws IOException { // Style the large table dt5.getHeaderCellTemplate().setFillColor(new Color(155, 89, 182)); dt5.getHeaderCellTemplate().setTextColor(Color.WHITE); - for (Cell cell : dt5.getDataCellTemplateEvenList()) { + for (Cell cell : dt5.getDataCellTemplateEvenList()) { cell.setFillColor(Color.WHITE); } - for (Cell cell : dt5.getDataCellTemplateOddList()) { + for (Cell cell : dt5.getDataCellTemplateOddList()) { cell.setFillColor(new Color(250, 242, 255)); } diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java index c39b21f..f601a6f 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial09_MultiPageTables.java @@ -83,8 +83,8 @@ public void demonstrateMultiPageTables() throws IOException { Color rowColor = (i % 2 == 0) ? white : lightBlue; Cell numCell = dataRow.createCell(10, String.valueOf(i)); - Cell nameCell = dataRow.createCell(25, "Product " + i); - Cell descCell2 = dataRow.createCell(25, + dataRow.createCell(25, "Product " + i); + dataRow.createCell(25, "Description for product number " + i); Cell priceCell = dataRow.createCell(15, String.format("$%.2f", i * 9.99)); diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java index 02d1b21..ae6fd95 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial10_NestedTables.java @@ -76,7 +76,7 @@ public void demonstrateNestedTables() throws IOException { "

              Price:$99.99
              Stock:Available
              "; - Cell nestedCell = simpleRow.createCell(60, nestedTableHtml); + Cell nestedCell = simpleRow.createTableCell(60, nestedTableHtml); nestedCell.setFillColor(new Color(245, 245, 245)); // Section 2: Multiple Nested Tables @@ -99,7 +99,7 @@ public void demonstrateNestedTables() throws IOException { "
          Qty:10
          Total:$500
          "; - Cell cell1 = multiRow.createCell(33.33f, table1); + Cell cell1 = multiRow.createTableCell(33.33f, table1); cell1.setFillColor(new Color(255, 243, 224)); // Second nested table @@ -108,7 +108,7 @@ public void demonstrateNestedTables() throws IOException { "Qty:8" + "Total:$600" + ""; - Cell cell2 = multiRow.createCell(33.33f, table2); + Cell cell2 = multiRow.createTableCell(33.33f, table2); cell2.setFillColor(new Color(230, 245, 255)); // Third nested table @@ -117,7 +117,7 @@ public void demonstrateNestedTables() throws IOException { "Qty:5" + "Total:$500" + ""; - Cell cell3 = multiRow.createCell(33.34f, table3); + Cell cell3 = multiRow.createTableCell(33.34f, table3); cell3.setFillColor(new Color(255, 235, 238)); // Section 3: Complex Nested Structure @@ -145,7 +145,7 @@ public void demonstrateNestedTables() throws IOException { "Widget C3$149.97" + "Total:$299.94" + ""; - Cell rightCell = complexRow.createCell(60, orderTable); + Cell rightCell = complexRow.createTableCell(60, orderTable); rightCell.setFillColor(Color.WHITE); // Section 4: Nested Tables with Lists @@ -174,10 +174,61 @@ public void demonstrateNestedTables() throws IOException { "Color:Blue" + "Warranty:2 years" + ""; - Cell specsCell = listRow.createCell(50, specsTable); + Cell specsCell = listRow.createTableCell(50, specsTable); specsCell.setFillColor(new Color(230, 245, 255)); - // Section 5: Practical Invoice Example + // Section 5: Full Cell Area usage for Inner Table + // Force new page for this example section + table.draw(); + page = new PDPage(PDRectangle.A4); + document.addPage(page); + table = new BaseTable(yStart, yStartNewPage, bottomMargin, tableWidth, margin, document, page, true, true); + + addSectionHeader(table, "Full Cell Area Inner Table"); + + Row fullAreaDesc = table.createRow(15f); + fullAreaDesc.createCell(100, "Using the full cell area for the inner table without padding or margins:"); + + Row fullAreaRow = table.createRow(12f); + fullAreaRow.createCell(30, "Package Info"); + + String innerTableHtml = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "
          PropertyValue
          Tracking IDTRK-99887766
          CarrierFastShip Logistics
          ServicePriority Overnight
          Weight2.5 kg
          Dimensions30x20x15 cm
          InsuranceFull Coverage
          SignatureRequired
          "; + + // Use the new convenience method + be.quodlibet.boxable.TableCell innerTableCell = fullAreaRow.createTableCell(70, innerTableHtml); + + // Configure cell to use full area + innerTableCell.setLeftPadding(0); + innerTableCell.setRightPadding(0); + innerTableCell.setTopPadding(0); + innerTableCell.setBottomPadding(0); + innerTableCell.setMarginBetweenElementsY(0); + innerTableCell.setLeftBorderStyle(null); + innerTableCell.setTopBorderStyle(null); + + // Configure inner table borders and layout + innerTableCell.setInnerTableBorders(false, false, false, false); + innerTableCell.setInnerTableInnerBorders(true, true); + innerTableCell.setInnerTableStartAtTop(true); + innerTableCell.setInnerTableBorderStyle(new be.quodlibet.boxable.line.LineStyle(Color.BLACK, 1)); + innerTableCell.setInnerTableCellPadding(2f, 2f, 2f, 2f); + + // Section 6: Practical Invoice Example + // Force new page for this example section + table.draw(); + page = new PDPage(PDRectangle.A4); + document.addPage(page); + table = new BaseTable(yStart, yStartNewPage, bottomMargin, tableWidth, margin, document, page, true, true); + addSectionHeader(table, "Practical Example: Invoice"); Row invoiceHeader = table.createRow(60f); @@ -198,7 +249,7 @@ public void demonstrateNestedTables() throws IOException { "Due Date:March 7, 2024" + "Terms:Net 30" + ""; - Cell invoiceCell = invoiceHeader.createCell(50, invoiceDetails); + Cell invoiceCell = invoiceHeader.createTableCell(50, invoiceDetails); invoiceCell.setFillColor(Color.WHITE); // Bill to section diff --git a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java index 878814a..5dee46b 100644 --- a/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java +++ b/src/test/java/be/quodlibet/boxable/tutorial/Tutorial12_AdvancedFeatures.java @@ -95,7 +95,7 @@ public void demonstrateAdvancedFeatures() throws IOException { // Row with colspan Row colspanRow1 = table.createRow(20f); - Cell spanCell = colspanRow1.createCell(100, + Cell spanCell = colspanRow1.createTableCell(100, "" + "" + "" + @@ -174,7 +174,7 @@ public void demonstrateAdvancedFeatures() throws IOException { // Data row with nested table Row complexData = table.createRow(80f); - Cell q1Data = complexData.createCell(10, + Cell q1Data = complexData.createTableCell(10, "
          This cell spans 3 columns
          Column 1Column 2Column 3
          " + "" + "" + @@ -182,7 +182,7 @@ public void demonstrateAdvancedFeatures() throws IOException { q1Data.setAlign(HorizontalAlignment.CENTER); q1Data.setFillColor(new Color(230, 245, 255)); - Cell q2Data = complexData.createCell(10, + Cell q2Data = complexData.createTableCell(10, "
          Sales:
          $100K
          " + "" + "" + @@ -190,7 +190,7 @@ public void demonstrateAdvancedFeatures() throws IOException { q2Data.setAlign(HorizontalAlignment.CENTER); q2Data.setFillColor(new Color(230, 245, 255)); - Cell q3Data = complexData.createCell(10, + Cell q3Data = complexData.createTableCell(10, "
          Sales:
          $120K
          " + "" + "" + @@ -198,7 +198,7 @@ public void demonstrateAdvancedFeatures() throws IOException { q3Data.setAlign(HorizontalAlignment.CENTER); q3Data.setFillColor(new Color(230, 245, 255)); - Cell q4Data = complexData.createCell(10, + Cell q4Data = complexData.createTableCell(10, "
          Sales:
          $135K
          " + "" + "" + @@ -206,7 +206,7 @@ public void demonstrateAdvancedFeatures() throws IOException { q4Data.setAlign(HorizontalAlignment.CENTER); q4Data.setFillColor(new Color(230, 245, 255)); - Cell summaryData = complexData.createCell(60, + Cell summaryData = complexData.createTableCell(60, "Annual Summary:

          " + "
          Sales:
          $150K
          " + "" + diff --git a/wiki-docs/API-Reference.md b/wiki-docs/API-Reference.md deleted file mode 100644 index 6519521..0000000 --- a/wiki-docs/API-Reference.md +++ /dev/null @@ -1,333 +0,0 @@ -# API Reference - -This reference covers the main classes and methods in Boxable. - -## Core Classes - -### BaseTable - -The main class for creating tables. - -#### Constructor - -```java -BaseTable(float yStart, - float yStartNewPage, - float bottomMargin, - float width, - float margin, - PDDocument document, - PDPage page, - boolean drawLines, - boolean drawContent) -``` - -**Parameters:** -- `yStart` - Starting Y position on the current page -- `yStartNewPage` - Y position for new pages (usually same as yStart) -- `bottomMargin` - Bottom margin (when to create new page) -- `width` - Table width in points -- `margin` - Left margin in points -- `document` - PDDocument instance -- `page` - Current PDPage -- `drawLines` - Whether to draw cell borders -- `drawContent` - Whether to draw cell content - -#### Key Methods - -```java -// Create a new row -Row createRow(float height) - -// Add a header row (repeats on each page) -void addHeaderRow(Row row) - -// Draw the table -float draw() // Returns final Y position - -// Get current page (may change after draw) -PDPage getCurrentPage() - -// Set outer border style -void setOuterBorderStyle(LineStyle style) -``` - -### Row - -Represents a table row. - -#### Key Methods - -```java -// Create a text cell -Cell createCell(float widthPercent, String text) - -// Create an image cell -ImageCell createImageCell(float widthPercent, Image image) - -// Create a table cell (nested table via HTML) -Cell createTableCell(float widthPercent, String htmlTable, - PDDocument doc, PDPage page, float yStart, - float bottomMargin, float margin) - -// Set row height -void setHeight(float height) - -// Set fixed height (auto-shrink text) -void setFixedHeight(boolean fixed) - -// Get all cells in row -List> getCells() -``` - -### Cell - -Represents a table cell. - -#### Styling Methods - -```java -// Colors -void setFillColor(Color color) -void setTextColor(Color color) - -// Text properties -void setFont(PDFont font) -void setFontSize(float size) -void setTextRotated(boolean rotated) - -// Alignment -void setAlign(HorizontalAlignment align) -void setValign(VerticalAlignment align) - -// Borders -void setBorderStyle(LineStyle style) -void setTopBorderStyle(LineStyle style) -void setBottomBorderStyle(LineStyle style) -void setLeftBorderStyle(LineStyle style) -void setRightBorderStyle(LineStyle style) - -// Padding -void setTopPadding(float padding) -void setBottomPadding(float padding) -void setLeftPadding(float padding) -void setRightPadding(float padding) - -// Content -String getText() -void setText(String text) -``` - -### ImageCell - -Extends Cell for image content. - -```java -// Get the image -Image getImage() - -// Inherited from Cell: all styling methods -``` - -### DataTable - -Helper class for importing data. - -#### Constructor - -```java -DataTable(BaseTable table, PDPage page) -DataTable(BaseTable table, PDPage page, List colWidths) -``` - -#### Key Methods - -```java -// Import from CSV -void addCsvToTable(String csvData, boolean hasHeader, char delimiter) - -// Import from List -void addListToTable(List data, boolean hasHeader) - -// Style templates -Cell getHeaderCellTemplate() -Cell getDataCellTemplateEven() -Cell getDataCellTemplateOdd() -List getDataCellTemplateEvenList() -List getDataCellTemplateOddList() -Cell getFirstColumnCellTemplate() -Cell getLastColumnCellTemplate() -``` - -### LineStyle - -Represents border styling. - -#### Constructor - -```java -LineStyle(Color color, float width) -``` - -**Example:** -```java -LineStyle redBorder = new LineStyle(Color.RED, 2f); -cell.setBorderStyle(redBorder); -``` - -### Image - -Wrapper for images in cells. - -#### Constructor - -```java -Image(BufferedImage image) -``` - -**Example:** -```java -BufferedImage buffImg = ImageIO.read(new File("image.png")); -Image image = new Image(buffImg); -ImageCell cell = row.createImageCell(50, image); -``` - -## Enums - -### HorizontalAlignment - -```java -HorizontalAlignment.LEFT -HorizontalAlignment.CENTER -HorizontalAlignment.RIGHT -``` - -### VerticalAlignment - -```java -VerticalAlignment.TOP -VerticalAlignment.MIDDLE -VerticalAlignment.BOTTOM -``` - -## Constants - -### DataTable - -```java -DataTable.HASHEADER // = true (data has header row) -DataTable.NOHEADER // = false (no header row) -``` - -## Common Patterns - -### Creating a Basic Table - -```java -PDDocument doc = new PDDocument(); -PDPage page = new PDPage(); -doc.addPage(page); - -float margin = 50; -float yStart = page.getMediaBox().getHeight() - margin; -float tableWidth = page.getMediaBox().getWidth() - (2 * margin); - -BaseTable table = new BaseTable(yStart, yStart, 70, tableWidth, - margin, doc, page, true, true); - -Row row = table.createRow(20f); -Cell cell = row.createCell(100, "Hello World"); - -table.draw(); -doc.save("output.pdf"); -doc.close(); -``` - -### Styled Header - -```java -Row header = table.createRow(20f); -Cell headerCell = header.createCell(100, "Header"); -headerCell.setFillColor(new Color(52, 152, 219)); -headerCell.setTextColor(Color.WHITE); -headerCell.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD)); -headerCell.setAlign(HorizontalAlignment.CENTER); -table.addHeaderRow(header); -``` - -### Alternating Row Colors - -```java -for (int i = 0; i < data.length; i++) { - Row row = table.createRow(15f); - Cell cell = row.createCell(100, data[i]); - - if (i % 2 == 0) { - cell.setFillColor(new Color(236, 240, 241)); - } else { - cell.setFillColor(Color.WHITE); - } -} -``` - -### Custom Borders - -```java -// Thick red border -cell.setBorderStyle(new LineStyle(Color.RED, 3f)); - -// No borders -cell.setBorderStyle(null); - -// Bottom border only -cell.setTopBorderStyle(null); -cell.setBottomBorderStyle(new LineStyle(Color.BLACK, 2f)); -cell.setLeftBorderStyle(null); -cell.setRightBorderStyle(null); - -// Outer border only on table -table.setOuterBorderStyle(new LineStyle(Color.BLACK, 2f)); -``` - -### Transparent Colors - -```java -// Alpha channel: 0 = fully transparent, 255 = fully opaque -Color transparentRed = new Color(255, 0, 0, 128); // 50% transparent -cell.setFillColor(transparentRed); -``` - -### HTML Formatting - -```java -String html = "Bold and italic
          " + - "H2O and E=mc2"; -Cell cell = row.createCell(100, html); -``` - -### Multi-Column Cells - -```java -Row row = table.createRow(20f); -Cell wideCell = row.createCell(70, "Wide cell"); -Cell narrowCell1 = row.createCell(15, "Narrow 1"); -Cell narrowCell2 = row.createCell(15, "Narrow 2"); -``` - -## Best Practices - -1. **Always call `draw()`** before saving the document -2. **Store return value of `draw()`** if creating multiple tables -3. **Check `getCurrentPage()`** after `draw()` for page transitions -4. **Use percentage widths** that sum to 100 -5. **Add header rows before data rows** -6. **Set `drawContent` and `drawLines`** according to your needs -7. **Use templates in DataTable** for consistent styling -8. **Close PDDocument** after saving - -## See Also - -- [Getting Started Guide](Getting-Started) -- [All Tutorials](Tutorial-01-Basic-Table) -- [HTML Tags Reference](HTML-Tags-Reference) -- [FAQ](FAQ) diff --git a/wiki-docs/FAQ.md b/wiki-docs/FAQ.md deleted file mode 100644 index 3caf595..0000000 --- a/wiki-docs/FAQ.md +++ /dev/null @@ -1,311 +0,0 @@ -# Frequently Asked Questions (FAQ) - -## General Questions - -### What is Boxable? - -Boxable is a Java library that simplifies the creation of tables in PDF documents. It's built on top of Apache PDFBox and provides a high-level API for creating professional tables with rich formatting. - -### What version of Java is required? - -Boxable requires Java 8 or higher. The library is compiled with Java 17 but is compatible with Java 8+. - -### Is Boxable production-ready? - -Yes! Boxable is actively maintained and used in production applications. Version 1.8.2-RC1 is the current release candidate. - -## Installation and Setup - -### How do I add Boxable to my project? - -**Maven:** -```xml - - com.github.dhorions - boxable - 1.8.2-RC1 - -``` - -**Gradle:** -```gradle -implementation 'com.github.dhorions:boxable:1.8.2-RC1' -``` - -### What dependencies does Boxable have? - -Boxable depends on: -- Apache PDFBox 3.0.6 -- Apache Commons CSV (for CSV import) -- JSoup (for HTML parsing) - -These are automatically included when you add Boxable to your project. - -## Table Creation - -### How do I create a simple table? - -See the [Getting Started](Getting-Started) guide or [Tutorial 01](Tutorial-01-Basic-Table) for a complete example. - -### Why isn't my table showing up in the PDF? - -Make sure you call `table.draw()` before saving the document: - -```java -table.draw(); // Don't forget this! -document.save("output.pdf"); -``` - -### How do I control table width? - -The table width is specified when creating the BaseTable: - -```java -float tableWidth = page.getMediaBox().getWidth() - (2 * margin); -BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, - tableWidth, margin, document, page, - true, true); -``` - -### Can I create tables without borders? - -Yes! Set `drawLines` to `false` when creating the table: - -```java -BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, - tableWidth, margin, document, page, - false, true); // false = no borders -``` - -You can also set `setOuterBorderStyle()` for custom border control. - -## Content and Formatting - -### How do I add colors to cells? - -Use `setFillColor()` for background and `setTextColor()` for text: - -```java -Cell cell = row.createCell(50, "Content"); -cell.setFillColor(Color.BLUE); -cell.setTextColor(Color.WHITE); -``` - -### Can I use HTML formatting in cells? - -Yes! Boxable supports many HTML tags including ``, ``, ``, ``, `
          `, ``, ``, lists, and more. See [HTML Tags Reference](HTML-Tags-Reference) for details. - -### How do I add images to cells? - -Use `createImageCell()`: - -```java -BufferedImage bufferedImage = ImageIO.read(new File("image.png")); -Image image = new Image(bufferedImage); -ImageCell cell = row.createImageCell(50, image); -``` - -See [Tutorial 05: Images](Tutorial-05-Images) for examples. - -### How do I rotate text? - -Use `setTextRotated(true)`: - -```java -Cell cell = row.createCell(10, "VERTICAL"); -cell.setTextRotated(true); -``` - -### Can I change font size? - -Yes: - -```java -cell.setFontSize(14f); -``` - -## Multi-Page Tables - -### Do tables automatically span multiple pages? - -Yes! When a table reaches the bottom margin, Boxable automatically creates a new page and continues the table. - -### How do I make headers repeat on each page? - -Use `addHeaderRow()`: - -```java -Row headerRow = table.createRow(20f); -// ... create header cells ... -table.addHeaderRow(headerRow); -``` - -Headers added this way automatically repeat on each new page. - -### Can I have multiple header rows? - -Yes! Call `addHeaderRow()` multiple times: - -```java -table.addHeaderRow(headerRow1); -table.addHeaderRow(headerRow2); -table.addHeaderRow(headerRow3); -``` - -See [Tutorial 07: Header Rows](Tutorial-07-Header-Rows). - -## Data Import - -### How do I import data from CSV? - -Use the `DataTable` class: - -```java -String csvData = "Name;Age\\nJohn;30\\nJane;25"; -BaseTable baseTable = new BaseTable(...); -DataTable dataTable = new DataTable(baseTable, page); -dataTable.addCsvToTable(csvData, DataTable.HASHEADER, ';'); -baseTable.draw(); -``` - -### Can I import from Java Lists? - -Yes: - -```java -List data = new ArrayList<>(); -data.add(new ArrayList<>(Arrays.asList("Name", "Age"))); -data.add(new ArrayList<>(Arrays.asList("John", "30"))); - -DataTable dataTable = new DataTable(baseTable, page); -dataTable.addListToTable(data, DataTable.HASHEADER); -``` - -See [Tutorial 08: Data Import](Tutorial-08-Data-Import). - -### How do I control column widths when importing? - -Pass a list of relative widths: - -```java -DataTable dataTable = new DataTable(baseTable, page, - Arrays.asList(3f, 1f, 1f, 1f)); -// First column is 3x wider than others -``` - -## Performance - -### How do I handle very large tables? - -Boxable handles large tables efficiently. For best performance: -- Use `drawContent = true` and `drawLines = true` only when needed -- Consider breaking very large tables into multiple tables -- See [Tutorial 09: Multi-Page Tables](Tutorial-09-MultiPage-Tables) - -### Does Boxable use a lot of memory? - -Boxable is designed to be memory-efficient. It processes rows as they're added rather than storing everything in memory. - -## Advanced Features - -### Can I create nested tables? - -Yes! Use HTML `
          Total Sales:$505,000
          ` tags within cell content: - -```java -String nestedTable = "
          " + - "" + - "" + - "
          NameValue
          Item 1100
          "; -Cell cell = row.createCell(50, nestedTable); -``` - -See [Tutorial 10: Nested Tables](Tutorial-10-Nested-Tables). - -### What are fixed-height rows? - -Fixed-height rows automatically shrink text to fit a specified height: - -```java -Row row = table.createRow(12f); -row.setFixedHeight(true); // Text will shrink to fit 12pt height -``` - -See [Tutorial 11: Fixed Height Rows](Tutorial-11-Fixed-Height-Rows). - -### Can cells span multiple columns? - -Yes, in nested tables using `colspan`: - -```html -" - - -
          Spans 3 columns
          Col1Col2Col3
          " -``` - -## Troubleshooting - -### My text is cut off - -Possible solutions: -- Increase row height -- Use fixed-height rows with auto-shrink -- Add line breaks with `
          ` tags -- Reduce font size - -### Colors aren't showing - -Make sure you set both `drawLines` and `drawContent` to `true`: - -```java -BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, - tableWidth, margin, document, page, - true, true); // both true -``` - -### Characters are showing as boxes - -The default font (Helvetica) doesn't support all Unicode characters. Use: -- Standard ASCII characters -- HTML entity references -- Or load a custom font that supports your characters - -### Table positioning is wrong - -Make sure your `yStart` calculation accounts for margins: - -```java -float yStart = page.getMediaBox().getHeight() - margin; -``` - -## Getting Help - -### Where can I find more examples? - -Run the built-in tutorials: - -```bash -mvn test -Dtest=TutorialRunner -``` - -This generates 12 PDF examples covering all features. - -### Where do I report bugs? - -Report issues on GitHub: https://github.com/dhorions/boxable/issues - -### How can I contribute? - -Contributions are welcome! See issue [#41](https://github.com/dhorions/boxable/issues/41) for documentation needs. - -### Is there commercial support? - -Boxable is open source. For commercial support inquiries, contact the maintainers through GitHub. - -## See Also - -- [Getting Started](Getting-Started) -- [All Tutorials](Tutorial-01-Basic-Table) -- [API Reference](API-Reference) -- [HTML Tags Reference](HTML-Tags-Reference) diff --git a/wiki-docs/Getting-Started.md b/wiki-docs/Getting-Started.md deleted file mode 100644 index f1edb31..0000000 --- a/wiki-docs/Getting-Started.md +++ /dev/null @@ -1,187 +0,0 @@ -# Getting Started with Boxable - -This guide will help you get started with Boxable and create your first PDF table. - -## Installation - -### Maven - -Add the following dependency to your `pom.xml`: - -```xml - - com.github.dhorions - boxable - 1.8.2-RC1 - -``` - -### Gradle - -Add to your `build.gradle`: - -```gradle -implementation 'com.github.dhorions:boxable:1.8.2-RC1' -``` - -## Your First Table - -Let's create a simple PDF with a table: - -```java -import be.quodlibet.boxable.BaseTable; -import be.quodlibet.boxable.Row; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDPage; - -import java.io.IOException; - -public class FirstTable { - public static void main(String[] args) throws IOException { - // Step 1: Create a PDF document - PDDocument document = new PDDocument(); - PDPage page = new PDPage(); - document.addPage(page); - - // Step 2: Define table parameters - float margin = 50; - float yStart = page.getMediaBox().getHeight() - margin; - float tableWidth = page.getMediaBox().getWidth() - (2 * margin); - float yStartNewPage = yStart; - float bottomMargin = 70; - - // Step 3: Create the table - BaseTable table = new BaseTable(yStart, yStartNewPage, bottomMargin, - tableWidth, margin, document, page, - true, true); - - // Step 4: Create header row - Row headerRow = table.createRow(20f); - headerRow.createCell(50, "Name"); - headerRow.createCell(50, "Age"); - - // Step 5: Create data rows - Row row1 = table.createRow(15f); - row1.createCell(50, "John Doe"); - row1.createCell(50, "30"); - - Row row2 = table.createRow(15f); - row2.createCell(50, "Jane Smith"); - row2.createCell(50, "25"); - - // Step 6: Draw the table - table.draw(); - - // Step 7: Save and close - document.save("first-table.pdf"); - document.close(); - - System.out.println("PDF created successfully!"); - } -} -``` - -## Key Concepts - -### BaseTable - -`BaseTable` is the main class for creating tables. It requires: -- `yStart` - Starting Y position on the page -- `yStartNewPage` - Y position for new pages (usually same as yStart) -- `bottomMargin` - Margin at the bottom of the page -- `tableWidth` - Width of the table -- `margin` - Left margin -- `document` - PDDocument instance -- `page` - Current PDPage -- `drawLines` - Whether to draw cell borders (true/false) -- `drawContent` - Whether to draw cell content (true/false) - -### Row - -`Row` represents a table row. Create rows with: -```java -Row row = table.createRow(heightInPoints); -``` - -### Cell - -`Cell` represents a table cell. Create cells with: -```java -Cell cell = row.createCell(widthPercentage, "Content"); -``` - -The width is specified as a percentage of the table width. - -## Running the Tutorials - -The library includes 12 comprehensive tutorials. Run them all: - -```bash -mvn test -Dtest=TutorialRunner -``` - -Or run individually: - -```bash -mvn test -Dtest=Tutorial01_BasicTable -mvn test -Dtest=Tutorial02_HtmlFormatting -# ... and so on -``` - -## Next Steps - -- Explore the [Basic Table Tutorial](Tutorial-01-Basic-Table) -- Learn about [HTML Formatting](Tutorial-02-HTML-Formatting) -- Check out [Colors and Transparency](Tutorial-03-Colors-And-Transparency) -- View the complete [API Reference](API-Reference) - -## Common Patterns - -### Adding a Header Row - -```java -Row headerRow = table.createRow(20f); -// ... create cells ... -table.addHeaderRow(headerRow); -``` - -Headers automatically repeat on each new page. - -### Setting Cell Colors - -```java -Cell cell = row.createCell(50, "Content"); -cell.setFillColor(Color.BLUE); -cell.setTextColor(Color.WHITE); -``` - -### Importing CSV Data - -```java -String csvData = "Name;Age\\nJohn;30\\nJane;25"; -DataTable dataTable = new DataTable(baseTable, page); -dataTable.addCsvToTable(csvData, DataTable.HASHEADER, ';'); -``` - -## Troubleshooting - -### Table Not Visible - -Make sure you call `table.draw()` before saving the document. - -### Text Overflow - -If text is too large for a cell: -- Increase row height -- Use fixed-height rows with auto-fit -- Wrap text with `
          ` tags - -### Multiple Pages - -Boxable automatically creates new pages when content exceeds the page height. Header rows are automatically repeated. - -## Further Reading - -- [All Tutorials](Tutorial-01-Basic-Table) -- [HTML Tags Reference](HTML-Tags-Reference) -- [FAQ](FAQ) diff --git a/wiki-docs/HTML-Tags-Reference.md b/wiki-docs/HTML-Tags-Reference.md deleted file mode 100644 index 68616c2..0000000 --- a/wiki-docs/HTML-Tags-Reference.md +++ /dev/null @@ -1,293 +0,0 @@ -# HTML Tags Reference - -Boxable supports a subset of HTML tags for rich text formatting in table cells. This reference covers all supported tags with examples. - -## Text Formatting Tags - -### Bold: `` - -Makes text bold. - -**Example:** -```html -"This is bold text in a cell" -``` - -**Output:** This is **bold text** in a cell - -### Italic: `` - -Makes text italic. - -**Example:** -```html -"This is italic text in a cell" -``` - -**Output:** This is *italic text* in a cell - -### Underline: `` - -Underlines text. - -**Example:** -```html -"This is underlined text in a cell" -``` - -**Output:** This is underlined text in a cell - -### Strikethrough: `` - -Strikes through text. - -**Example:** -```html -"This is strikethrough text in a cell" -``` - -**Output:** This is ~~strikethrough text~~ in a cell - -## Heading Tags - -### Headings: `

          ` through `

          ` - -Creates headings of different sizes. - -**Example:** -```html -"

          Largest Heading

          " -"

          Second Level

          " -"

          Third Level

          " -"
          Smallest Heading
          " -``` - -**Note:** Headings have different font sizes with h1 being the largest. - -## Superscript and Subscript (New in v1.8.2) - -### Superscript: `` - -Raises text above the baseline (useful for exponents, footnotes). - -**Example:** -```html -"E=mc2" -"x2 + y2 = z2" -``` - -**Output:** E=mc² and x² + y² = z² - -**Common Uses:** -- Mathematical exponents -- Ordinal indicators (1ˢᵗ, 2ⁿᵈ) -- Footnote references - -### Subscript: `` - -Lowers text below the baseline (useful for chemical formulas). - -**Example:** -```html -"H2O" -"CO2" -``` - -**Output:** H₂O and CO₂ - -**Common Uses:** -- Chemical formulas -- Mathematical subscripts -- Array indices - -### Combined Super/Subscript - -You can combine both: - -**Example:** -```html -"Ani" -``` - -## Line Breaks and Paragraphs - -### Line Break: `
          ` or `
          ` - -Inserts a line break. - -**Example:** -```html -"First line
          Second line
          Third line" -``` - -**Output:** -``` -First line -Second line -Third line -``` - -### Paragraph: `

          ` - -Creates a paragraph with spacing. - -**Example:** -```html -"

          First paragraph

          Second paragraph

          " -``` - -## Lists - -### Unordered List: `
            ` and `
          • ` - -Creates a bulleted list. - -**Example:** -```html -"
              -
            • First item
            • -
            • Second item
            • -
            • Third item
            • -
            " -``` - -**Output:** -- First item -- Second item -- Third item - -### Ordered List: `
              ` and `
            1. ` - -Creates a numbered list. - -**Example:** -```html -"
                -
              1. First step
              2. -
              3. Second step
              4. -
              5. Third step
              6. -
              " -``` - -**Output:** -1. First step -2. Second step -3. Third step - -## Tables (Nested) - -### Nested Table: ``, ``, `
              ` - -Creates a table within a cell. - -**Example:** -```html -" - - - -
              NameValue
              Item 1100
              Item 2200
              " -``` - -### Colspan in Nested Tables - -**Example:** -```html -" - - -
              Spanning Header
              Col 1Col 2
              " -``` - -## Nesting Tags - -Tags can be nested for combined effects: - -**Example:** -```html -"Bold and Italic" -"Bold Underlined" -"Bold with italic inside" -"Underlined with superscript" -``` - -**Complex Example:** -```html -"Product: Widget X
              -Formula: H2O + CO2
              -Price: $99.99*" -``` - -## Best Practices - -### DO: -- ✓ Close all tags properly -- ✓ Use proper nesting (inner tags close before outer tags) -- ✓ Use semantic tags for meaning (`` for emphasis, `` for exponents) -- ✓ Test complex HTML in the tutorial examples first - -### DON'T: -- ✗ Use unsupported HTML tags (they will be ignored) -- ✗ Use CSS styles (not supported) -- ✗ Nest lists inside lists (not fully supported) -- ✗ Use special Unicode characters not in the default font - -## Tag Support Matrix - -| Tag | Supported | Notes | -|-----|-----------|-------| -| `` | ✓ | Bold text | -| `` | ✓ | Italic text | -| `` | ✓ | Underlined text | -| `` | ✓ | Strikethrough | -| `

              `-`

              ` | ✓ | Different heading sizes | -| `` | ✓ | Superscript (v1.8.2+) | -| `` | ✓ | Subscript (v1.8.2+) | -| `
              ` | ✓ | Line break | -| `

              ` | ✓ | Paragraph | -| `

                `, `
                  `, `
                1. ` | ✓ | Lists | -| ``, ``, `
                  ` | ✓ | Nested tables | -| `colspan` | ✓ | Column spanning (in nested tables) | -| `` | ✗ | Not supported | -| `
                  ` | ✗ | Not supported | -| CSS | ✗ | Not supported | - -## Examples by Use Case - -### Scientific Formulas -```html -"Water: H2O
                  -Carbon Dioxide: CO2
                  -Einstein's Equation: E=mc2" -``` - -### Product Information -```html -"Widget ProTM
                  -The professional choice
                  -Only $99.99" -``` - -### Instructions -```html -"
                    -
                  1. Connect to power
                  2. -
                  3. Press Start
                  4. -
                  5. Wait for Ready indicator
                  6. -
                  " -``` - -### Data Table -```html -" - - - -
                  MetricValue
                  CPU2.4 GHz
                  RAM16 GB
                  " -``` - -## See Also - -- [Tutorial 02: HTML Formatting](Tutorial-02-HTML-Formatting) - Live examples -- [Tutorial 10: Nested Tables](Tutorial-10-Nested-Tables) - Nested table examples -- [API Reference](API-Reference) - Cell class documentation diff --git a/wiki-docs/Home.md b/wiki-docs/Home.md deleted file mode 100644 index a084c00..0000000 --- a/wiki-docs/Home.md +++ /dev/null @@ -1,103 +0,0 @@ -# Home - -Welcome to the Boxable library documentation! - -## What is Boxable? - -Boxable is a high-level Java library built on top of Apache PDFBox that makes it easy to create tables in PDF documents. It provides a simple API for generating professional-looking tables with rich formatting options. - -## Key Features - -- **Easy table creation** - Simple API for building tables programmatically -- **Rich HTML formatting** - Support for HTML tags including ``, ``, ``, ``, `

                  `-`

                  `, ``, ``, `
                    `, `
                      `, `
                    1. `, and more -- **Data import** - Import data from CSV files or Java Lists -- **Multi-page support** - Tables automatically span multiple pages with repeating headers -- **Advanced styling** - Cell colors, borders, alignment, transparency, images, and more -- **Nested tables** - Create complex layouts with tables inside cells -- **Fixed-height rows** - Auto-fit text in constrained spaces -- **Rotated text** - 90-degree rotation for vertical labels - -## Quick Start - -### Maven Dependency - -```xml - - com.github.dhorions - boxable - 1.8.2-RC1 - -``` - -### Simple Example - -```java -// Initialize PDF document -PDDocument document = new PDDocument(); -PDPage page = new PDPage(); -document.addPage(page); - -// Create table -float margin = 50; -float yStart = page.getMediaBox().getHeight() - margin; -float tableWidth = page.getMediaBox().getWidth() - (2 * margin); -float bottomMargin = 70; - -BaseTable table = new BaseTable(yStart, yStart, bottomMargin, - tableWidth, margin, document, page, - true, true); - -// Add rows -Row headerRow = table.createRow(20f); -headerRow.createCell(50, "Name"); -headerRow.createCell(50, "Value"); - -Row dataRow = table.createRow(15f); -dataRow.createCell(50, "Item 1"); -dataRow.createCell(50, "Value 1"); - -// Draw and save -table.draw(); -document.save("output.pdf"); -document.close(); -``` - -## Documentation Structure - -- **[Getting Started](Getting-Started)** - Installation and first steps -- **[Tutorials](Tutorial-01-Basic-Table)** - 12 comprehensive tutorials with examples -- **[API Reference](API-Reference)** - Detailed API documentation -- **[HTML Tags Reference](HTML-Tags-Reference)** - Supported HTML tags -- **[FAQ](FAQ)** - Frequently asked questions - -## Runnable Tutorials - -The library includes 12 runnable tutorials that demonstrate all features: - -1. [Basic Table](Tutorial-01-Basic-Table) - Simple table creation -2. [HTML Formatting](Tutorial-02-HTML-Formatting) - Text formatting with HTML -3. [Colors and Transparency](Tutorial-03-Colors-And-Transparency) - Color management -4. [Alignment](Tutorial-04-Alignment) - Text alignment options -5. [Images](Tutorial-05-Images) - Images in cells -6. [Borders and Styling](Tutorial-06-Borders-And-Styling) - Border customization -7. [Header Rows](Tutorial-07-Header-Rows) - Repeating headers -8. [Data Import](Tutorial-08-Data-Import) - CSV and List imports -9. [Multi-Page Tables](Tutorial-09-MultiPage-Tables) - Page spanning -10. [Nested Tables](Tutorial-10-Nested-Tables) - Tables within cells -11. [Fixed Height Rows](Tutorial-11-Fixed-Height-Rows) - Auto-fit text -12. [Advanced Features](Tutorial-12-Advanced-Features) - Rotated text, colspan - -Run all tutorials: -```bash -mvn test -Dtest=TutorialRunner -``` - -## Community and Support - -- **GitHub Repository**: https://github.com/dhorions/boxable -- **Issues**: https://github.com/dhorions/boxable/issues -- **Contributing**: Contributions are welcome! See issue [#41](https://github.com/dhorions/boxable/issues/41) - -## License - -Licensed under the Apache License, Version 2.0. See the LICENSE file for details.