From dba296d322bc1fe708e4fd2c1f196452ee0df993 Mon Sep 17 00:00:00 2001 From: Nick Boyd Date: Fri, 3 Feb 2023 13:36:21 +0100 Subject: [PATCH 1/4] Pruned changes down to Minimal required set. Branch is dependant on changes to core mentioned in: RES-725 Signed-off-by: Nick Boyd --- .../itextpdf/rups/shims/RupsPdfString.java | 39 +++++++++++++++++++ .../contextmenu/CopyToClipboardAction.java | 31 +++++++++++---- .../view/contextmenu/PdfTreeContextMenu.java | 4 ++ .../itext/treenodes/PdfObjectTreeNode.java | 11 ++++++ 4 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/itextpdf/rups/shims/RupsPdfString.java diff --git a/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java b/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java new file mode 100644 index 00000000..83e1b42b --- /dev/null +++ b/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java @@ -0,0 +1,39 @@ +package com.itextpdf.rups.shims; + +import com.itextpdf.kernel.pdf.PdfString; + +public class RupsPdfString extends PdfString { + public RupsPdfString(String value, String encoding) { + super(value, encoding); + } + + public RupsPdfString(String value) { + super(value); + } + + public RupsPdfString(byte[] content) { + super(content); + } + + public RupsPdfString(PdfString unpatchedPdfString){ + this(unpatchedPdfString.getValueBytes()); + this.setHexWriting(unpatchedPdfString.isHexWriting()); + this.encoding = unpatchedPdfString.getEncoding(); + this.directOnly = !unpatchedPdfString.isIndirect(); + this.indirectReference = unpatchedPdfString.getIndirectReference(); + } + + protected RupsPdfString(byte[] content, boolean hexWriting) { + super(content, hexWriting); + } + + @Override + public String toString() { + String wrapper; + if(isHexWriting()) + wrapper = "<%s>"; + else + wrapper = "(%s)"; + return String.format(wrapper, getValue()); + } +} diff --git a/src/main/java/com/itextpdf/rups/view/contextmenu/CopyToClipboardAction.java b/src/main/java/com/itextpdf/rups/view/contextmenu/CopyToClipboardAction.java index 8080b892..8c195f59 100644 --- a/src/main/java/com/itextpdf/rups/view/contextmenu/CopyToClipboardAction.java +++ b/src/main/java/com/itextpdf/rups/view/contextmenu/CopyToClipboardAction.java @@ -42,8 +42,14 @@ This file is part of the iText (R) project. */ package com.itextpdf.rups.view.contextmenu; +import com.itextpdf.rups.view.itext.PdfTree; +import com.itextpdf.rups.view.itext.treenodes.PdfObjectTreeNode; + import javax.swing.JTextPane; import java.awt.Component; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; /** @@ -54,23 +60,32 @@ This file is part of the iText (R) project. public class CopyToClipboardAction extends AbstractRupsAction { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + public CopyToClipboardAction(String name, Component invoker) { super(name, invoker); } public void actionPerformed(ActionEvent e) { boolean nothingSelected = false; - JTextPane textPane = (JTextPane) invoker; + + if (invoker instanceof JTextPane) { + JTextPane textPane = (JTextPane) invoker; - if (textPane.getSelectedText() == null || textPane.getSelectedText().trim().length() == 0) { - nothingSelected = true; - textPane.selectAll(); - } + if (textPane.getSelectedText() == null || textPane.getSelectedText().trim().length() == 0) { + nothingSelected = true; + textPane.selectAll(); + } - textPane.copy(); + textPane.copy(); - if (nothingSelected) { - textPane.select(0, 0); + if (nothingSelected) { + textPane.select(0, 0); + } + } else if (invoker instanceof PdfTree) { + PdfTree tree = (PdfTree) invoker; + PdfObjectTreeNode selectionNode = (PdfObjectTreeNode) tree.getSelectionPath().getLastPathComponent(); + clipboard.setContents(new StringSelection(selectionNode.getPdfObject().toString()), null); } } } diff --git a/src/main/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenu.java b/src/main/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenu.java index 1ee055af..c8943c64 100644 --- a/src/main/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenu.java +++ b/src/main/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenu.java @@ -67,6 +67,10 @@ public static JPopupMenu getPopupMenu(Component component) { new SaveToFilePdfTreeAction(Language.SAVE_RAW_BYTES_TO_FILE.getString(), component, true) )); + popup.add(getJMenuItem( + new CopyToClipboardAction(Language.COPY_TO_CLIPBOARD.getString(), component) + )); + popup.add(getJMenuItem( new SaveToFilePdfTreeAction(Language.SAVE_TO_FILE.getString(), component, false) )); diff --git a/src/main/java/com/itextpdf/rups/view/itext/treenodes/PdfObjectTreeNode.java b/src/main/java/com/itextpdf/rups/view/itext/treenodes/PdfObjectTreeNode.java index fad819b1..f785565e 100644 --- a/src/main/java/com/itextpdf/rups/view/itext/treenodes/PdfObjectTreeNode.java +++ b/src/main/java/com/itextpdf/rups/view/itext/treenodes/PdfObjectTreeNode.java @@ -48,6 +48,7 @@ This file is part of the iText (R) project. import com.itextpdf.kernel.pdf.PdfObject; import com.itextpdf.kernel.pdf.PdfString; import com.itextpdf.rups.model.LoggerHelper; +import com.itextpdf.rups.shims.RupsPdfString; import com.itextpdf.rups.view.Language; import com.itextpdf.rups.view.icons.IconFetcher; import com.itextpdf.rups.view.icons.IconTreeNode; @@ -132,6 +133,8 @@ protected PdfObjectTreeNode(PdfObject object) { break; case PdfObject.STRING: icon = IconFetcher.getIcon(STRING_ICON); + // Patch to normalise PdfString's toString() behaviour with the remainder of iText's serialization. + this.object = new RupsPdfString((PdfString) object); break; } } @@ -398,4 +401,12 @@ public PdfName getPdfDictionaryType() { } return null; } + + /** + * Returns the Key that forms the node's final path component. + * @return a {@link PdfName} object or {@code null} + */ + public PdfName getKey() { + return key; + } } From d498a05c3d28f72198a9b7c12307fa74f03474fc Mon Sep 17 00:00:00 2001 From: Nick Boyd Date: Mon, 6 Feb 2023 10:52:35 +0100 Subject: [PATCH 2/4] Implemented tests for Tree Popup Menu and Shim UI and Content integration tests still to be implemented. Signed-off-by: Nick Boyd --- .../rups/shims/RupsPdfStringTest.java | 17 +++++++ .../contextmenu/PdfTreeContextMenuTest.java | 47 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java create mode 100644 src/test/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenuTest.java diff --git a/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java b/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java new file mode 100644 index 00000000..a1dcdeb1 --- /dev/null +++ b/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java @@ -0,0 +1,17 @@ +package com.itextpdf.rups.shims; + +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(UnitTest.class) +public class RupsPdfStringTest { + + @Test + public void toStringBasicTest() { + RupsPdfString pdfString = new RupsPdfString("Test"); + + Assert.assertEquals("String is () Delimited.","(Test)", pdfString.toString()); + } +} diff --git a/src/test/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenuTest.java b/src/test/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenuTest.java new file mode 100644 index 00000000..49b61ec1 --- /dev/null +++ b/src/test/java/com/itextpdf/rups/view/contextmenu/PdfTreeContextMenuTest.java @@ -0,0 +1,47 @@ +package com.itextpdf.rups.view.contextmenu; + +import com.itextpdf.test.annotations.type.UnitTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.MenuElement; +import java.util.Arrays; + +@Category(UnitTest.class) +public class PdfTreeContextMenuTest { + + @Test + public void jMenuLengthTest() { + JPopupMenu popupMenu = PdfTreeContextMenu.getPopupMenu(null); + + MenuElement[] subElements = popupMenu.getSubElements(); + Assert.assertEquals(4, subElements.length); + } + + @Test + public void jMenuSubItemTypeTest() { + JPopupMenu popupMenu = PdfTreeContextMenu.getPopupMenu(null); + + MenuElement[] subElements = popupMenu.getSubElements(); + + Assert.assertTrue(Arrays.stream(subElements).allMatch(menuElement -> menuElement instanceof JMenuItem)); + } + + @Test + public void assignedActionsTest() { + JPopupMenu popupMenu = PdfTreeContextMenu.getPopupMenu(null); + + MenuElement[] subElements = popupMenu.getSubElements(); + + Assert.assertTrue(Arrays.stream(subElements).anyMatch(element -> ((JMenuItem) element).getAction() instanceof InspectObjectAction)); + + Assert.assertTrue(Arrays.stream(subElements).anyMatch(element -> ((JMenuItem) element).getAction() instanceof SaveToFilePdfTreeAction)); + + Assert.assertTrue(Arrays.stream(subElements).anyMatch(element -> ((JMenuItem) element).getAction() instanceof CopyToClipboardAction)); + + Assert.assertTrue(Arrays.stream(subElements).anyMatch(element -> ((JMenuItem) element).getAction() instanceof SaveToFilePdfTreeAction)); + } +} From b4dfd733fa0a9e83903658c0344e4528423fee1a Mon Sep 17 00:00:00 2001 From: Nick Boyd Date: Mon, 6 Feb 2023 14:57:40 +0100 Subject: [PATCH 3/4] RupsPdfString.toString() modified to correctly encode Hex, Tests Added Signed-off-by: Nick Boyd --- .../com/itextpdf/rups/shims/RupsPdfString.java | 2 +- .../itextpdf/rups/shims/RupsPdfStringTest.java | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java b/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java index 83e1b42b..270a7579 100644 --- a/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java +++ b/src/main/java/com/itextpdf/rups/shims/RupsPdfString.java @@ -34,6 +34,6 @@ public String toString() { wrapper = "<%s>"; else wrapper = "(%s)"; - return String.format(wrapper, getValue()); + return String.format(wrapper, new String(encodeBytes(getValueBytes()))); } } diff --git a/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java b/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java index a1dcdeb1..bfabac9b 100644 --- a/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java +++ b/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java @@ -12,6 +12,22 @@ public class RupsPdfStringTest { public void toStringBasicTest() { RupsPdfString pdfString = new RupsPdfString("Test"); - Assert.assertEquals("String is () Delimited.","(Test)", pdfString.toString()); + Assert.assertEquals("String is () Delimited.", "(Test)", pdfString.toString()); + } + + @Test + public void toStringHexTest() { + byte[] hexArray = "Test".getBytes(); + StringBuilder hexString = new StringBuilder("<"); + for (byte b : hexArray) { + hexString.append(Integer.toHexString(b)); + } + hexString.append(">"); + + RupsPdfString pdfString = new RupsPdfString(hexArray); + pdfString.setHexWriting(true); + + Assert.assertEquals("String is <> Delimited.", hexString.toString(), pdfString.toString()); } } + From 78c92a8d1e0c567eebd21bac1196734fd7bd70a9 Mon Sep 17 00:00:00 2001 From: Nick Boyd Date: Mon, 6 Feb 2023 15:40:50 +0100 Subject: [PATCH 4/4] RupsPdfString.toString() modified to correctly encode Hex, Tests Added Signed-off-by: Nick Boyd --- pom.xml | 26 ++++++++-------- .../rups/shims/RupsPdfStringTest.java | 30 +++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index eab2bbbb..4c8a0cbc 100644 --- a/pom.xml +++ b/pom.xml @@ -309,18 +309,6 @@ sh.tak.appbundler appbundle-maven-plugin 1.2.0 - - - org.codehaus.plexus - plexus-archiver - 3.6.0 - - - org.apache.velocity - velocity-tools - 2.0 - - package @@ -329,6 +317,18 @@ + + + org.apache.velocity + velocity-tools + 2.0 + + + org.codehaus.plexus + plexus-archiver + 3.6.0 + + com.itextpdf.rups.RupsLauncher Info.plist @@ -340,4 +340,4 @@ - \ No newline at end of file + diff --git a/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java b/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java index bfabac9b..71c6190c 100644 --- a/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java +++ b/src/test/java/com/itextpdf/rups/shims/RupsPdfStringTest.java @@ -29,5 +29,35 @@ public void toStringHexTest() { Assert.assertEquals("String is <> Delimited.", hexString.toString(), pdfString.toString()); } + + @Test + public void toStringBalancedTest(){ + String balanced = "Test (of paretheses)"; + RupsPdfString pdfString = new RupsPdfString(balanced); + Assert.assertEquals("Balanced parens are escaped:", "(Test \\(of paretheses\\))", pdfString.toString()); + // Note: This is optional, but performed this way in iText to avoid too much overhead evaluating the balance of symbols. + } + + @Test + public void toStringUnbalancedTest() { + String unbalanced = "Test :-)"; + RupsPdfString pdfString = new RupsPdfString(unbalanced); + Assert.assertEquals("Unbalanced parens are escaped:", "(Test :-\\))", pdfString.toString()); + } + + @Test + public void toStringUnbalancedTest_Two() { + String unbalanced_two = ")Test :-("; + RupsPdfString pdfString_two = new RupsPdfString(unbalanced_two); + Assert.assertEquals("Unbalanced parens are escaped:", "(\\)Test :-\\()", pdfString_two.toString()); + } + + @Test + public void toStringUnbalancedTest_Three(){ + String unbalanced_three = "@<----(( Robin Hood Test"; + RupsPdfString pdfString_three = new RupsPdfString(unbalanced_three); + Assert.assertEquals("Unbalanced parens are escaped:", "(@<----\\(\\( Robin Hood Test)", pdfString_three.toString()); + } + }