From b7bf6b6dcbb83739c59e08cf1e95628622267f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Demey?= Date: Tue, 5 Apr 2022 08:41:19 +0200 Subject: [PATCH] Add support for multiple files in RUPS. RES-662 --- src/main/java/com/itextpdf/rups/Rups.java | 77 ++-- .../java/com/itextpdf/rups/RupsLauncher.java | 2 +- .../rups/controller/PdfReaderController.java | 6 +- .../rups/controller/RupsController.java | 427 +----------------- .../controller/RupsInstanceController.java | 381 ++++++++++++++++ .../com/itextpdf/rups/io/FileOpenAction.java | 2 +- .../itextpdf/rups/io/OpenInViewerAction.java | 36 ++ .../com/itextpdf/rups/view/MessageAction.java | 34 +- .../itextpdf/rups/view/RupsDropTarget.java | 64 +++ .../com/itextpdf/rups/view/RupsMenuBar.java | 69 +-- .../com/itextpdf/rups/view/RupsPanel.java | 28 ++ .../itextpdf/rups/view/RupsTabbedPane.java | 57 +++ .../rups/controller/RupsControllerTest.java | 72 +++ 13 files changed, 742 insertions(+), 513 deletions(-) create mode 100644 src/main/java/com/itextpdf/rups/controller/RupsInstanceController.java create mode 100644 src/main/java/com/itextpdf/rups/io/OpenInViewerAction.java create mode 100644 src/main/java/com/itextpdf/rups/view/RupsDropTarget.java create mode 100644 src/main/java/com/itextpdf/rups/view/RupsPanel.java create mode 100644 src/main/java/com/itextpdf/rups/view/RupsTabbedPane.java create mode 100644 src/test/java/com/itextpdf/rups/controller/RupsControllerTest.java diff --git a/src/main/java/com/itextpdf/rups/Rups.java b/src/main/java/com/itextpdf/rups/Rups.java index c714814b..d3df8de8 100644 --- a/src/main/java/com/itextpdf/rups/Rups.java +++ b/src/main/java/com/itextpdf/rups/Rups.java @@ -43,30 +43,16 @@ This file is part of the iText (R) project. package com.itextpdf.rups; import com.itextpdf.kernel.actions.data.ITextCoreProductData; -import com.itextpdf.kernel.utils.CompareTool; import com.itextpdf.rups.controller.RupsController; +import com.itextpdf.rups.view.RupsTabbedPane; import com.itextpdf.rups.view.icons.FrameIconUtil; -import java.awt.Dimension; -import java.awt.Toolkit; +import javax.swing.*; +import java.awt.*; import java.io.File; -import javax.swing.JFrame; -import javax.swing.SwingUtilities; public class Rups { - private RupsController controller; - - private volatile CompareTool.CompareResult lastCompareResult = null; - - protected Rups() { - this.controller = null; - } - - protected void setController(RupsController controller) { - this.controller = controller; - } - /** * Initializes the main components of the Rups application. * @@ -74,47 +60,44 @@ protected void setController(RupsController controller) { * @param onCloseOperation the close operation */ public static void startNewApplication(final File f, final int onCloseOperation) { - final Rups rups = new Rups(); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - JFrame frame = new JFrame(); - // defines the size and location - initFrameDim(frame); - RupsController controller = new RupsController(frame.getSize(), frame, false); - initApplication(frame, controller, onCloseOperation); - rups.setController(controller); - if (null != f && f.canRead()) { - rups.loadDocumentFromFile(f, false); - } - } + SwingUtilities.invokeLater(() -> { + JFrame frame = new JFrame(); + setLookandFeel(); + initApplication(frame, onCloseOperation); }); } - public void loadDocumentFromFile(final File f, final boolean readOnly) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - controller.loadFile(f, readOnly); + static void setLookandFeel() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + try { + UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + } catch (Exception ex) { + // WELP IDK } - }); + } } - static void initApplication(JFrame frame, RupsController controller, final int onCloseOperation) { + static void initApplication(JFrame frame, final int onCloseOperation) { + Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); + frame.setSize((int) (screen.getWidth() * .90), (int) (screen.getHeight() * .90)); + frame.setLocation((int) (screen.getWidth() * .05), (int) (screen.getHeight() * .05)); + frame.setResizable(true); + // title bar - frame.setTitle("iText RUPS " + ITextCoreProductData.getInstance().getVersion()); + frame.setTitle("iText RUPS " + ITextCoreProductData.getInstance().getVersion() + " - Research Edition"); frame.setIconImages(FrameIconUtil.loadFrameIcons()); frame.setDefaultCloseOperation(onCloseOperation); + + RupsTabbedPane tabbedPane = new RupsTabbedPane(screen); + + // menu bar + RupsController rupsController = new RupsController(tabbedPane); + frame.setJMenuBar(rupsController.getMenuBar()); // the content - frame.setJMenuBar(controller.getMenuBar()); - frame.getContentPane().add(controller.getMasterComponent(), java.awt.BorderLayout.CENTER); + frame.getContentPane().add(tabbedPane, BorderLayout.CENTER); frame.setVisible(true); } - static void initFrameDim(JFrame frame) { - Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); - frame.setSize((int) (screen.getWidth() * .90), (int) (screen.getHeight() * .90)); - frame.setLocation((int) (screen.getWidth() * .05), (int) (screen.getHeight() * .05)); - frame.setResizable(true); - } - } diff --git a/src/main/java/com/itextpdf/rups/RupsLauncher.java b/src/main/java/com/itextpdf/rups/RupsLauncher.java index a628da8f..85fe6502 100644 --- a/src/main/java/com/itextpdf/rups/RupsLauncher.java +++ b/src/main/java/com/itextpdf/rups/RupsLauncher.java @@ -42,7 +42,7 @@ This file is part of the iText (R) project. */ package com.itextpdf.rups; -import javax.swing.*; +import javax.swing.WindowConstants; import java.io.File; /** diff --git a/src/main/java/com/itextpdf/rups/controller/PdfReaderController.java b/src/main/java/com/itextpdf/rups/controller/PdfReaderController.java index 0704cd85..63099684 100644 --- a/src/main/java/com/itextpdf/rups/controller/PdfReaderController.java +++ b/src/main/java/com/itextpdf/rups/controller/PdfReaderController.java @@ -70,10 +70,10 @@ This file is part of the iText (R) project. import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import java.util.Observable; -import java.util.Observer; -import java.util.Stack; +import java.util.*; /** * Controls the components that get their content from iText's PdfReader. diff --git a/src/main/java/com/itextpdf/rups/controller/RupsController.java b/src/main/java/com/itextpdf/rups/controller/RupsController.java index 726b1d07..cd6e44c5 100644 --- a/src/main/java/com/itextpdf/rups/controller/RupsController.java +++ b/src/main/java/com/itextpdf/rups/controller/RupsController.java @@ -42,36 +42,12 @@ This file is part of the iText (R) project. */ package com.itextpdf.rups.controller; -import com.itextpdf.kernel.actions.data.ITextCoreProductData; -import com.itextpdf.kernel.exceptions.PdfException; -import com.itextpdf.kernel.pdf.PdfDocument; -import com.itextpdf.kernel.pdf.PdfReader; -import com.itextpdf.kernel.utils.CompareTool; import com.itextpdf.rups.event.*; import com.itextpdf.rups.model.*; -import com.itextpdf.rups.view.Console; -import com.itextpdf.rups.view.NewIndirectPdfObjectDialog; -import com.itextpdf.rups.view.PageSelectionListener; -import com.itextpdf.rups.view.RupsMenuBar; -import com.itextpdf.rups.view.contextmenu.ConsoleContextMenu; -import com.itextpdf.rups.view.contextmenu.ContextMenuMouseListener; -import com.itextpdf.rups.view.itext.treenodes.PdfObjectTreeNode; -import com.itextpdf.rups.view.itext.treenodes.PdfTrailerTreeNode; +import com.itextpdf.rups.view.*; -import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; import java.awt.*; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetDropEvent; import java.io.*; -import java.net.URL; -import java.net.URLDecoder; -import java.util.List; import java.util.*; /** @@ -79,139 +55,30 @@ This file is part of the iText (R) project. * the RUPS application: the menu bar, the panels,... */ public class RupsController extends Observable - implements TreeSelectionListener, PageSelectionListener, Observer { + implements Observer { // member variables /* file and controller */ - /** - * The Pdf file that is currently open in the application. - */ - protected PdfFile pdfFile; - protected StringBuilder rawText = new StringBuilder(); - /** - * Object with the GUI components for iText. - * - * @since iText 5.0.0 (renamed from reader which was confusing because reader is normally used for a PdfReader instance) - */ - protected PdfReaderController readerController; /* main components */ /** * The JMenuBar for the RUPS application. */ protected RupsMenuBar menuBar; - /** - * Contains all other components: the page panel, the outline tree, etc. - */ - protected JSplitPane masterComponent; - - protected JPanel masterPanel; - - protected JPanel treePanel; - - protected Frame ownedFrame; - - private boolean pluginMode; - - private ObjectLoader loader; + private final RupsTabbedPane rupsTabbedPane; // constructor /** * Constructs the GUI components of the RUPS application. * - * @param dimension the dimension - * @param frame the frame - * @param pluginMode the plugin mode + * @param rupsTabbedPane rupstabbedpane */ - public RupsController(Dimension dimension, Frame frame, boolean pluginMode) { - // creating components and controllers - this.pluginMode = pluginMode; - this.ownedFrame = frame; - menuBar = new RupsMenuBar(this); - addObserver(menuBar); - Console console = Console.getInstance(); - addObserver(console); - console.addObserver(this); - readerController = new PdfReaderController(this, this, pluginMode); - addObserver(readerController); - masterPanel = new JPanel(new BorderLayout()); - - // creating the master component - masterComponent = new JSplitPane(); - masterComponent.setOrientation(JSplitPane.VERTICAL_SPLIT); - masterComponent.setDividerLocation((int) (dimension.getHeight() * .70)); - masterComponent.setDividerSize(2); - - JSplitPane content = new JSplitPane(); - masterComponent.add(content, JSplitPane.TOP); - JSplitPane info = new JSplitPane(); - masterComponent.add(info, JSplitPane.BOTTOM); + public RupsController(RupsTabbedPane rupsTabbedPane) { + this.rupsTabbedPane = rupsTabbedPane; - content.setOrientation(JSplitPane.HORIZONTAL_SPLIT); - content.setDividerLocation((int) (dimension.getWidth() * .6)); - content.setDividerSize(1); - treePanel = new JPanel(new BorderLayout()); - treePanel.add(new JScrollPane(readerController.getPdfTree()), BorderLayout.CENTER); - content.add(treePanel, JSplitPane.LEFT); - content.add(readerController.getNavigationTabs(), JSplitPane.RIGHT); - - info.setDividerLocation((int) (dimension.getWidth() * .3)); - info.setDividerSize(1); - info.add(readerController.getObjectPanel(), JSplitPane.LEFT); - JTabbedPane editorPane = readerController.getEditorTabs(); - JScrollPane cons = new JScrollPane(console.getTextArea()); - console.getTextArea().addMouseListener(new ContextMenuMouseListener(ConsoleContextMenu.getPopupMenu(console.getTextArea()), console.getTextArea())); - editorPane.addTab("Console", null, cons, "Console window (System.out/System.err)"); - editorPane.setSelectedComponent(cons); - info.add(editorPane, JSplitPane.RIGHT); - - //application specific features - if (!pluginMode) { - masterComponent.setDropTarget(new DropTarget() { - // drag and drop for opening files - public synchronized void drop(DropTargetDropEvent dtde) { - dtde.acceptDrop(DnDConstants.ACTION_COPY); - Transferable t = dtde.getTransferable(); - List files = null; - - try { - if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { - files = (List) t.getTransferData(DataFlavor.javaFileListFlavor); - } - if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { // fix for Linux - - String urls = (String) t.getTransferData(DataFlavor.stringFlavor); - files = new LinkedList<>(); - StringTokenizer tokens = new StringTokenizer(urls); - while (tokens.hasMoreTokens()) { - String urlString = tokens.nextToken(); - URL url = new URL(urlString); - files.add(new File(URLDecoder.decode(url.getFile(), "UTF-8"))); - } - } - - if (files == null || files.size() != 1) { - JOptionPane.showMessageDialog(masterComponent, "You can only open one file!", "Error", JOptionPane.ERROR_MESSAGE); - } else { - loadFile(files.get(0), false); - } - } catch (HeadlessException | UnsupportedFlavorException | IOException e) { - JOptionPane.showMessageDialog(masterComponent, "Error opening file: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); - } - - dtde.dropComplete(true); - } - }); - } - - masterPanel.add(masterComponent, BorderLayout.CENTER); - } - - public RupsController(Dimension dimension, File f, Frame frame, boolean pluginMode) { - this(dimension, frame, pluginMode); - loadFile(f, false); + this.menuBar = new RupsMenuBar(this); } /** @@ -229,299 +96,33 @@ public RupsMenuBar getMenuBar() { * @return the master component */ public Component getMasterComponent() { - return masterPanel; - } - - public Component getTreePanel() { - return treePanel; + return rupsTabbedPane; } + @Override public void update(Observable o, Object arg) { //Events that have come from non observable classes: ObjectLoader and FileChooserAction if (o == null && arg instanceof RupsEvent) { RupsEvent event = (RupsEvent) arg; switch (event.getType()) { case RupsEvent.CLOSE_DOCUMENT_EVENT: - closeRoutine(); + this.rupsTabbedPane.closeCurrentFile(); break; case RupsEvent.OPEN_FILE_EVENT: - loadFile((File) event.getContent(), false); + this.rupsTabbedPane.openNewFile(((File) event.getContent()), false); break; case RupsEvent.SAVE_TO_FILE_EVENT: - saveFile((File) event.getContent()); - break; - case RupsEvent.COMPARE_WITH_FILE_EVENT: - highlightChanges(null); - CompareTool.CompareResult result = compareWithFile((File) event.getContent()); - highlightChanges(result); + this.rupsTabbedPane.saveCurrentFile((File) event.getContent()); break; case RupsEvent.OPEN_DOCUMENT_POST_EVENT: setChanged(); super.notifyObservers(event); break; - case RupsEvent.NEW_INDIRECT_OBJECT_EVENT: - showNewIndirectDialog(); - break; - } - } - //Events from observable classes - if (o != null && arg instanceof RupsEvent) { - RupsEvent event = (RupsEvent) arg; - if (RupsEvent.CONSOLE_WRITE_EVENT == event.getType()) { - readerController.getEditorTabs().setSelectedIndex(readerController.getEditorTabs().getComponentCount() - 1); - } - } - } - - /** - * @param file the file to load - * @param readOnly open the file read only or not - */ - public void loadFile(File file, boolean readOnly) { - try { - byte[] contents = readFileToByteArray(file); - loadRawContent(contents, file.getName(), file.getParentFile(), readOnly); - } catch (IOException ioe) { - JOptionPane.showMessageDialog(masterComponent, ioe.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); - } - } - - public void loadFileFromStream(InputStream is, String fileName, File directory, boolean readOnly) { - try { - byte[] contents = readStreamToByteArray(is); - loadRawContent(contents, fileName, directory, readOnly); - } catch (IOException ioe) { - JOptionPane.showMessageDialog(masterComponent, ioe.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); - } - } - - public void loadRawContent(byte[] contents, String fileName, File directory, boolean readOnly) { - closeRoutine(); - try { - pdfFile = new PdfFile(contents, readOnly); - pdfFile.setFilename(fileName); - pdfFile.setDirectory(directory); - startObjectLoader(); - if (!pluginMode) { - String directoryPath = directory == null ? "" : directory.getCanonicalPath() + File.separator; - ownedFrame.setTitle("iText RUPS - " + directoryPath + fileName + " - " + ITextCoreProductData.getInstance().getVersion()); - } - readerController.getParser().setDocument(pdfFile.getPdfDocument()); - } catch (IOException | PdfException | com.itextpdf.io.exceptions.IOException ioe) { - JOptionPane.showMessageDialog(masterComponent, ioe.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); - } - } - - /** - * Reads a File to a byte[] - * - * @param file java.io.File - * @return the file as a byte array - * @throws IOException - */ - private byte[] readFileToByteArray(File file) throws IOException { - byte[] res; - InputStream inputStream = null; - try { - inputStream = new FileInputStream(file); - res = readStreamToByteArray(inputStream); - } finally { - try { - if (inputStream != null) - inputStream.close(); - } catch (IOException e) { - LoggerHelper.error(LoggerMessages.CLOSING_STREAM_ERROR, e, getClass()); - } - } - return res; - } - - private byte[] readStreamToByteArray(InputStream inputStream) throws IOException { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - int read; - byte[] buffer = new byte[4096]; - try { - while ((read = inputStream.read(buffer)) != -1) { - byteArrayOutputStream.write(buffer, 0, read); - } - } finally { - try { - byteArrayOutputStream.close(); - } catch (IOException e) { - LoggerHelper.error(LoggerMessages.CLOSING_STREAM_ERROR, e, getClass()); } } - return byteArrayOutputStream.toByteArray(); } - /** - * Saves the pdf to the disk - * - * @param file java.io.File file to save - */ - public void saveFile(File file) { - FileOutputStream fos = null; - try { - if (!file.getName().endsWith(".pdf")) { - file = new File(file.getPath() + ".pdf"); - } - - if (file.exists()) { - int choice = JOptionPane.showConfirmDialog(masterComponent, "File already exists, would you like to overwrite file?", "Warning", JOptionPane.YES_NO_CANCEL_OPTION); - if (choice == JOptionPane.NO_OPTION || choice == JOptionPane.CANCEL_OPTION) { - return; - } - } - - ByteArrayOutputStream bos = pdfFile.getByteArrayOutputStream(); - pdfFile.getPdfDocument().setFlushUnusedObjects(false); - closeRoutine(); - if (bos != null) { - bos.close(); - fos = new FileOutputStream(file); - bos.writeTo(fos); - } - - JOptionPane.showMessageDialog(masterComponent, "File saved.", "Dialog", JOptionPane.INFORMATION_MESSAGE); - loadFile(file, false); - } catch (PdfException | IOException | com.itextpdf.io.exceptions.IOException de) { - JOptionPane.showMessageDialog(masterComponent, de.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); - } finally { - try { - if (fos != null) { - fos.close(); - } - } catch (IOException e) { - LoggerHelper.error(LoggerMessages.CLOSING_STREAM_ERROR, e, getClass()); - } - } - } - - public void closeRoutine() { - loader = null; - PdfDocument docToClose = null; - if (pdfFile != null && pdfFile.getPdfDocument() != null) - docToClose = pdfFile.getPdfDocument(); - pdfFile = null; - setChanged(); - super.notifyObservers(new CloseDocumentEvent()); - if (docToClose != null) { - docToClose.close(); - } - if (!pluginMode) { - ownedFrame.setTitle("iText RUPS " + ITextCoreProductData.getInstance().getVersion()); - } - readerController.getParser().setDocument(null); - } - - public CompareTool.CompareResult compareWithDocument(PdfDocument document) { - if (getPdfFile() == null || getPdfFile().getPdfDocument() == null) { - LoggerHelper.warn(LoggerMessages.NO_OPEN_DOCUMENT, getClass()); - } else if (document == null) { - LoggerHelper.warn(LoggerMessages.COMPARED_DOCUMENT_IS_NULL, getClass()); - } else if (document.isClosed()) { - LoggerHelper.warn(LoggerMessages.COMPARED_DOCUMENT_IS_CLOSED, getClass()); - } else { - CompareTool compareTool = new CompareTool().setCompareByContentErrorsLimit(100).disableCachedPagesComparison(); - return compareTool.compareByCatalog(getPdfFile().getPdfDocument(), document); - } - return null; - } - - public CompareTool.CompareResult compareWithFile(File file) { - try (PdfReader readerPdf = new PdfReader(file.getAbsolutePath()); - PdfDocument cmpDocument = new PdfDocument(readerPdf)) { - return compareWithDocument(cmpDocument); - } catch (IOException e) { - LoggerHelper.warn(LoggerMessages.CREATE_COMPARE_DOC_ERROR, e, getClass()); - return null; - } - } - - public CompareTool.CompareResult compareWithStream(InputStream is) { - try (PdfReader reader = new PdfReader(is); - PdfDocument cmpDocument = new PdfDocument(reader)) { - reader.setCloseStream(false); - return compareWithDocument(cmpDocument); - } catch (IOException e) { - LoggerHelper.warn(LoggerMessages.CREATE_COMPARE_DOC_ERROR, e, getClass()); - return null; - } - } - - /** - * Clear all previous highlights and highlights the changes from the compare result. - * If compare result is null will just clear all previous highlights. - * - * @param compareResult the compare result - */ - public void highlightChanges(CompareTool.CompareResult compareResult) { - readerController.update(this, new PostCompareEvent(compareResult)); - if (compareResult != null) { - if (compareResult.isOk()) { - LoggerHelper.info("Documents are equal", getClass()); - } else { - LoggerHelper.info(compareResult.getReport(), getClass()); - } - } - } - - private void startObjectLoader() { - final ProgressDialog dialog = new ProgressDialog(getMasterComponent(), "Reading PDF document...", ownedFrame, pluginMode); - if (!pluginMode) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }); - } - loader = new ObjectLoader(this, pdfFile, pdfFile.getFilename(), dialog); - } - - // tree selection - - /** - * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent) - */ - public void valueChanged(TreeSelectionEvent evt) { - Object selectednode = readerController.getPdfTree().getLastSelectedPathComponent(); - if (selectednode instanceof PdfTrailerTreeNode) { - if (!pluginMode) { - menuBar.update(this, new RootNodeClickedEvent()); - } - readerController.getPdfTree().clearSelection(); - return; - } - if (selectednode instanceof PdfObjectTreeNode) { - readerController.update(this, new TreeNodeClickedEvent((PdfObjectTreeNode) selectednode)); - } - } - - // page navigation - - /** - * @see com.itextpdf.rups.view.PageSelectionListener#gotoPage(int) - */ - public int gotoPage(int pageNumber) { - readerController.gotoPage(pageNumber); - return pageNumber; - } - - /** - * Getter for the pdfFile - * - * @return pdfFile - */ - public PdfFile getPdfFile() { - return pdfFile; - } - - private void showNewIndirectDialog() { - NewIndirectPdfObjectDialog dialog = new NewIndirectPdfObjectDialog(ownedFrame, "Create new indirect object", readerController.getParser()); - dialog.setVisible(true); - if (dialog.getResult() != null) { - setChanged(); - notifyObservers(new PostNewIndirectObjectEvent(dialog.getResult())); - } + public PdfFile getCurrentFile() { + return this.rupsTabbedPane.getCurrentFile(); } } diff --git a/src/main/java/com/itextpdf/rups/controller/RupsInstanceController.java b/src/main/java/com/itextpdf/rups/controller/RupsInstanceController.java new file mode 100644 index 00000000..4ad44f98 --- /dev/null +++ b/src/main/java/com/itextpdf/rups/controller/RupsInstanceController.java @@ -0,0 +1,381 @@ +package com.itextpdf.rups.controller; + +import com.itextpdf.kernel.exceptions.PdfException; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.utils.CompareTool; +import com.itextpdf.rups.event.CloseDocumentEvent; +import com.itextpdf.rups.event.PostCompareEvent; +import com.itextpdf.rups.event.RupsEvent; +import com.itextpdf.rups.event.TreeNodeClickedEvent; +import com.itextpdf.rups.model.*; +import com.itextpdf.rups.view.Console; +import com.itextpdf.rups.view.PageSelectionListener; +import com.itextpdf.rups.view.contextmenu.ConsoleContextMenu; +import com.itextpdf.rups.view.contextmenu.ContextMenuMouseListener; +import com.itextpdf.rups.view.itext.treenodes.PdfObjectTreeNode; +import com.itextpdf.rups.view.itext.treenodes.PdfTrailerTreeNode; + +import javax.swing.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import java.awt.*; +import java.io.*; +import java.util.Observable; +import java.util.Observer; + +public class RupsInstanceController extends Observable implements TreeSelectionListener, PageSelectionListener, Observer { + private final boolean pluginMode; + + + /* file and controller */ + /** + * The Pdf file that is currently open in the application. + */ + protected PdfFile pdfFile; + + protected StringBuilder rawText = new StringBuilder(); + /** + * Object with the GUI components for iText. + * + * @since iText 5.0.0 (renamed from reader which was confusing because reader is normally used for a PdfReader instance) + */ + protected PdfReaderController readerController; + + /* main components */ + /** + * Contains all other components: the page panel, the outline tree, etc. + */ + protected JSplitPane masterComponent; + + protected JPanel treePanel; + + protected JPanel ownerPanel; + private ObjectLoader loader; + + // constructor + + /** + * Constructs the GUI components of the RUPS application. + * + * @param dimension the dimension + * @param owner the jpanel + * @param pluginMode the plugin mode + */ + public RupsInstanceController(Dimension dimension, JPanel owner, boolean pluginMode) { + // creating components and controllers + this.ownerPanel = owner; + this.pluginMode = pluginMode; + Console console = Console.getInstance(); + addObserver(console); + console.addObserver(this); + readerController = new PdfReaderController(this, this, pluginMode); + addObserver(readerController); + + // creating the master component + masterComponent = new JSplitPane(); + masterComponent.setOrientation(JSplitPane.VERTICAL_SPLIT); + masterComponent.setDividerLocation((int) (dimension.getHeight() * .70)); + masterComponent.setDividerSize(2); + + JSplitPane content = new JSplitPane(); + masterComponent.add(content, JSplitPane.TOP); + JSplitPane info = new JSplitPane(); + masterComponent.add(info, JSplitPane.BOTTOM); + + content.setOrientation(JSplitPane.HORIZONTAL_SPLIT); + content.setDividerLocation((int) (dimension.getWidth() * .6)); + content.setDividerSize(1); + treePanel = new JPanel(new BorderLayout()); + treePanel.add(new JScrollPane(readerController.getPdfTree()), BorderLayout.CENTER); + content.add(treePanel, JSplitPane.LEFT); + content.add(readerController.getNavigationTabs(), JSplitPane.RIGHT); + + info.setDividerLocation((int) (dimension.getWidth() * .3)); + info.setDividerSize(1); + info.add(readerController.getObjectPanel(), JSplitPane.LEFT); + JTabbedPane editorPane = readerController.getEditorTabs(); + JScrollPane cons = new JScrollPane(console.getTextArea()); + console.getTextArea().addMouseListener(new ContextMenuMouseListener(ConsoleContextMenu.getPopupMenu(console.getTextArea()), console.getTextArea())); + editorPane.addTab("Console", null, cons, "Console window (System.out/System.err)"); + editorPane.setSelectedComponent(cons); + info.add(editorPane, JSplitPane.RIGHT); + + ownerPanel.add(masterComponent, BorderLayout.CENTER); + } + + public RupsInstanceController(Dimension dimension, File f, JPanel owner, boolean pluginMode) { + this(dimension, owner, pluginMode); + loadFile(f, false); + } + + /** + * Getter for the master component. + * + * @return the master component + */ + public Component getMasterComponent() { + return ownerPanel; + } + + public Component getTreePanel() { + return treePanel; + } + + public void update(Observable o, Object arg) { + //Events that have come from non observable classes: ObjectLoader and FileChooserAction + if (o == null && arg instanceof RupsEvent) { + RupsEvent event = (RupsEvent) arg; + switch (event.getType()) { + case RupsEvent.OPEN_DOCUMENT_POST_EVENT: + setChanged(); + super.notifyObservers(event); + break; + } + } + //Events from observable classes + if (o != null && arg instanceof RupsEvent) { + RupsEvent event = (RupsEvent) arg; + if (RupsEvent.CONSOLE_WRITE_EVENT == event.getType()) { + readerController.getEditorTabs().setSelectedIndex(readerController.getEditorTabs().getComponentCount() - 1); + } + } + } + + /** + * @param file the file to load + * @param readOnly open the file read only or not + */ + public void loadFile(File file, boolean readOnly) { + try { + byte[] contents = readFileToByteArray(file); + loadRawContent(contents, file.getName(), file.getParentFile(), readOnly); + } catch (IOException ioe) { + JOptionPane.showMessageDialog(masterComponent, ioe.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); + } + } + + public void loadFileFromStream(InputStream is, String fileName, File directory, boolean readOnly) { + try { + byte[] contents = readStreamToByteArray(is); + loadRawContent(contents, fileName, directory, readOnly); + } catch (IOException ioe) { + JOptionPane.showMessageDialog(masterComponent, ioe.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); + } + } + + public void loadRawContent(byte[] contents, String fileName, File directory, boolean readOnly) { + closeRoutine(); + try { + pdfFile = new PdfFile(contents, readOnly); + pdfFile.setFilename(fileName); + pdfFile.setDirectory(directory); + startObjectLoader(); + if (!pluginMode) { + String directoryPath = directory == null ? "" : directory.getCanonicalPath() + File.separator; + } + readerController.getParser().setDocument(pdfFile.getPdfDocument()); + } catch (IOException | PdfException | com.itextpdf.io.exceptions.IOException ioe) { + JOptionPane.showMessageDialog(masterComponent, ioe.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); + } + } + + /** + * Reads a File to a byte[] + * + * @param file java.io.File + * @return the file as a byte array + * @throws IOException + */ + private byte[] readFileToByteArray(File file) throws IOException { + byte[] res; + InputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + res = readStreamToByteArray(inputStream); + } finally { + try { + if (inputStream != null) + inputStream.close(); + } catch (IOException e) { + LoggerHelper.error(LoggerMessages.CLOSING_STREAM_ERROR, e, getClass()); + } + } + return res; + } + + private byte[] readStreamToByteArray(InputStream inputStream) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + int read; + byte[] buffer = new byte[4096]; + try { + while ((read = inputStream.read(buffer)) != -1) { + byteArrayOutputStream.write(buffer, 0, read); + } + } finally { + try { + byteArrayOutputStream.close(); + } catch (IOException e) { + LoggerHelper.error(LoggerMessages.CLOSING_STREAM_ERROR, e, getClass()); + } + } + return byteArrayOutputStream.toByteArray(); + } + + /** + * Saves the pdf to the disk + * + * @param file java.io.File file to save + */ + public void saveFile(File file) { + FileOutputStream fos = null; + try { + if (!file.getName().endsWith(".pdf")) { + file = new File(file.getPath() + ".pdf"); + } + + if (file.exists()) { + int choice = JOptionPane.showConfirmDialog(masterComponent, "File already exists, would you like to overwrite file?", "Warning", JOptionPane.YES_NO_CANCEL_OPTION); + if (choice == JOptionPane.NO_OPTION || choice == JOptionPane.CANCEL_OPTION) { + return; + } + } + + ByteArrayOutputStream bos = pdfFile.getByteArrayOutputStream(); + pdfFile.getPdfDocument().setFlushUnusedObjects(false); + closeRoutine(); + if (bos != null) { + bos.close(); + fos = new FileOutputStream(file); + bos.writeTo(fos); + } + + JOptionPane.showMessageDialog(masterComponent, "File saved.", "Dialog", JOptionPane.INFORMATION_MESSAGE); + loadFile(file, false); + } catch (PdfException | IOException | com.itextpdf.io.exceptions.IOException de) { + JOptionPane.showMessageDialog(masterComponent, de.getMessage(), "Dialog", JOptionPane.ERROR_MESSAGE); + } finally { + try { + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + LoggerHelper.error(LoggerMessages.CLOSING_STREAM_ERROR, e, getClass()); + } + } + } + + public void closeRoutine() { + loader = null; + PdfDocument docToClose = null; + if (pdfFile != null && pdfFile.getPdfDocument() != null) + docToClose = pdfFile.getPdfDocument(); + pdfFile = null; + setChanged(); + super.notifyObservers(new CloseDocumentEvent()); + if (docToClose != null) { + docToClose.close(); + } + readerController.getParser().setDocument(null); + } + + public CompareTool.CompareResult compareWithDocument(PdfDocument document) { + if (getPdfFile() == null || getPdfFile().getPdfDocument() == null) { + LoggerHelper.warn(LoggerMessages.NO_OPEN_DOCUMENT, getClass()); + } else if (document == null) { + LoggerHelper.warn(LoggerMessages.COMPARED_DOCUMENT_IS_NULL, getClass()); + } else if (document.isClosed()) { + LoggerHelper.warn(LoggerMessages.COMPARED_DOCUMENT_IS_CLOSED, getClass()); + } else { + CompareTool compareTool = new CompareTool().setCompareByContentErrorsLimit(100).disableCachedPagesComparison(); + return compareTool.compareByCatalog(getPdfFile().getPdfDocument(), document); + } + return null; + } + + public CompareTool.CompareResult compareWithFile(File file) { + try (PdfReader readerPdf = new PdfReader(file.getAbsolutePath()); + PdfDocument cmpDocument = new PdfDocument(readerPdf)) { + return compareWithDocument(cmpDocument); + } catch (IOException e) { + LoggerHelper.warn(LoggerMessages.CREATE_COMPARE_DOC_ERROR, e, getClass()); + return null; + } + } + + public CompareTool.CompareResult compareWithStream(InputStream is) { + try (PdfReader reader = new PdfReader(is); + PdfDocument cmpDocument = new PdfDocument(reader)) { + reader.setCloseStream(false); + return compareWithDocument(cmpDocument); + } catch (IOException e) { + LoggerHelper.warn(LoggerMessages.CREATE_COMPARE_DOC_ERROR, e, getClass()); + return null; + } + } + + /** + * Clear all previous highlights and highlights the changes from the compare result. + * If compare result is null will just clear all previous highlights. + * + * @param compareResult the compare result + */ + public void highlightChanges(CompareTool.CompareResult compareResult) { + readerController.update(this, new PostCompareEvent(compareResult)); + if (compareResult != null) { + if (compareResult.isOk()) { + LoggerHelper.info("Documents are equal", getClass()); + } else { + LoggerHelper.info(compareResult.getReport(), getClass()); + } + } + } + + private void startObjectLoader() { + final ProgressDialog dialog = new ProgressDialog(getMasterComponent(), "Reading PDF document...", null, pluginMode); + if (!pluginMode) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + dialog.setVisible(true); + } + }); + } + loader = new ObjectLoader(this, pdfFile, pdfFile.getFilename(), dialog); + } + + // tree selection + + /** + * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent) + */ + public void valueChanged(TreeSelectionEvent evt) { + Object selectednode = readerController.getPdfTree().getLastSelectedPathComponent(); + if (selectednode instanceof PdfTrailerTreeNode) { + readerController.getPdfTree().clearSelection(); + return; + } + if (selectednode instanceof PdfObjectTreeNode) { + readerController.update(this, new TreeNodeClickedEvent((PdfObjectTreeNode) selectednode)); + } + } + + // page navigation + + /** + * @see com.itextpdf.rups.view.PageSelectionListener#gotoPage(int) + */ + public int gotoPage(int pageNumber) { + readerController.gotoPage(pageNumber); + return pageNumber; + } + + /** + * Getter for the pdfFile + * + * @return pdfFile + */ + public PdfFile getPdfFile() { + return pdfFile; + } + +} diff --git a/src/main/java/com/itextpdf/rups/io/FileOpenAction.java b/src/main/java/com/itextpdf/rups/io/FileOpenAction.java index 40e8fdf4..bcbcd6c0 100644 --- a/src/main/java/com/itextpdf/rups/io/FileOpenAction.java +++ b/src/main/java/com/itextpdf/rups/io/FileOpenAction.java @@ -58,7 +58,7 @@ public class FileOpenAction extends FileChooserAction { * @param parent a parent Component for chooser dialog */ public FileOpenAction(Observer observer, FileFilter filter, Component parent) { - super(observer, "Open", filter, parent); + super(observer, "Open New File", filter, parent); } @Override diff --git a/src/main/java/com/itextpdf/rups/io/OpenInViewerAction.java b/src/main/java/com/itextpdf/rups/io/OpenInViewerAction.java new file mode 100644 index 00000000..3d296126 --- /dev/null +++ b/src/main/java/com/itextpdf/rups/io/OpenInViewerAction.java @@ -0,0 +1,36 @@ +package com.itextpdf.rups.io; + +import com.itextpdf.rups.controller.RupsController; +import com.itextpdf.rups.model.PdfFile; +import com.itextpdf.rups.view.RupsMenuBar; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; + +public class OpenInViewerAction implements ActionListener { + + private final RupsController controller; + + public OpenInViewerAction(RupsController controller) { + this.controller = controller; + } + + public void actionPerformed(ActionEvent e) { + if (!Desktop.isDesktopSupported()) { + return; + } + try { + PdfFile pdfFile = this.controller.getCurrentFile(); + if (pdfFile == null || pdfFile.getDirectory() == null) { + return; + } + File myFile = new File(pdfFile.getDirectory(), pdfFile.getFilename()); + Desktop.getDesktop().open(myFile); + } catch (IOException ex) { + // no application registered for PDFs + } + } +} diff --git a/src/main/java/com/itextpdf/rups/view/MessageAction.java b/src/main/java/com/itextpdf/rups/view/MessageAction.java index 90645aa2..a9de3000 100644 --- a/src/main/java/com/itextpdf/rups/view/MessageAction.java +++ b/src/main/java/com/itextpdf/rups/view/MessageAction.java @@ -42,27 +42,31 @@ This file is part of the iText (R) project. */ package com.itextpdf.rups.view; -import com.itextpdf.kernel.actions.data.ITextCoreProductData; - import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +/** + * Displays a given message to the user using a {@link JOptionPane}. + */ public class MessageAction implements ActionListener { - public void actionPerformed(ActionEvent evt) { - String message; - switch (evt.getActionCommand()) { - case RupsMenuBar.ABOUT: - message = "RUPS is a tool by iText Group NV.\nIt uses iText, a Free Java-PDF Library.\nVisit http://www.itextpdf.com/ for more info."; - break; - case RupsMenuBar.VERSION: - message = ITextCoreProductData.getInstance().getVersion(); - break; - default: - message = "Unspecified message"; - } - JOptionPane.showMessageDialog(null, message); + /** + * The message to eb displayed. + */ + private String message; + + /** + * Default constructor taking a string to display to the user. + * + * @param message the message to be displayed + */ + public MessageAction(String message) { + this.message = message; } + @Override + public void actionPerformed(ActionEvent evt) { + JOptionPane.showMessageDialog(null, this.message); + } } diff --git a/src/main/java/com/itextpdf/rups/view/RupsDropTarget.java b/src/main/java/com/itextpdf/rups/view/RupsDropTarget.java new file mode 100644 index 00000000..9079ece5 --- /dev/null +++ b/src/main/java/com/itextpdf/rups/view/RupsDropTarget.java @@ -0,0 +1,64 @@ +package com.itextpdf.rups.view; + +import com.itextpdf.rups.io.filters.PdfFilter; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDropEvent; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * Drag and drop implementation for RUPS. + */ +public class RupsDropTarget extends DropTarget { + private RupsTabbedPane rupsTabbedPane; + + public RupsDropTarget(RupsTabbedPane rupsTabbedPane) { + this.rupsTabbedPane = rupsTabbedPane; + } + + public synchronized void drop(DropTargetDropEvent dtde) { + dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); + Transferable t = dtde.getTransferable(); + List files = null; + + try { + if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + files = (List) t.getTransferData(DataFlavor.javaFileListFlavor); + } + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { // fix for Linux + String urls = (String) t.getTransferData(DataFlavor.stringFlavor); + files = new LinkedList<>(); + StringTokenizer tokens = new StringTokenizer(urls); + while (tokens.hasMoreTokens()) { + String urlString = tokens.nextToken(); + URL url = new URL(urlString); + files.add(new File(URLDecoder.decode(url.getFile(), "UTF-8"))); + } + } + + PdfFilter pdfFilter = PdfFilter.INSTANCE; + + for ( File file : files ) { + if (pdfFilter.accept(file)) { + this.rupsTabbedPane.openNewFile(file, false); + } + } + } catch (HeadlessException | UnsupportedFlavorException | IOException e) { + JOptionPane.showMessageDialog(rupsTabbedPane, "Error opening file: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + + dtde.dropComplete(true); + } +} diff --git a/src/main/java/com/itextpdf/rups/view/RupsMenuBar.java b/src/main/java/com/itextpdf/rups/view/RupsMenuBar.java index 32ea4be0..89eea168 100644 --- a/src/main/java/com/itextpdf/rups/view/RupsMenuBar.java +++ b/src/main/java/com/itextpdf/rups/view/RupsMenuBar.java @@ -42,12 +42,10 @@ This file is part of the iText (R) project. */ package com.itextpdf.rups.view; +import com.itextpdf.kernel.actions.data.ITextCoreProductData; import com.itextpdf.rups.controller.RupsController; import com.itextpdf.rups.event.RupsEvent; -import com.itextpdf.rups.io.FileCloseAction; -import com.itextpdf.rups.io.FileCompareAction; -import com.itextpdf.rups.io.FileOpenAction; -import com.itextpdf.rups.io.FileSaveAction; +import com.itextpdf.rups.io.*; import com.itextpdf.rups.io.filters.PdfFilter; import com.itextpdf.rups.model.PdfFile; @@ -68,10 +66,18 @@ public class RupsMenuBar extends JMenuBar implements Observer { * Caption for the file menu. */ public static final String FILE_MENU = "File"; + /** + * Caption for the Edit Menu. + */ + public static final String EDIT_MENU = "Edit"; + /** + * Caption for View Menu + */ + public static final String VIEW_MENU = "View"; /** * Caption for "Open file". */ - public static final String OPEN = "Open"; + public static final String OPEN = "Open New File"; /** * Caption for "Open in PDF Viewer". */ @@ -79,7 +85,7 @@ public class RupsMenuBar extends JMenuBar implements Observer { /** * Caption for "Close file". */ - public static final String CLOSE = "Close"; + public static final String CLOSE = "Close File"; /** * Caption for "Save as..." */ @@ -111,6 +117,14 @@ public class RupsMenuBar extends JMenuBar implements Observer { * The action needed to open a file. */ protected FileOpenAction fileOpenAction; + /** + * The action needed to close a file/tab. + */ + protected FileCloseAction fileCloseAction; + /** + * The action needed to open a file in the system viewer. + */ + protected OpenInViewerAction openInViewerAction; /** * The action needed to save a file. */ @@ -124,47 +138,36 @@ public class RupsMenuBar extends JMenuBar implements Observer { /** * Creates a JMenuBar. - * - * @param controller the controller to which this menu bar is added */ public RupsMenuBar(RupsController controller) { this.controller = controller; items = new HashMap<>(); + fileOpenAction = new FileOpenAction(this.controller, PdfFilter.INSTANCE, this.controller.getMasterComponent()); + fileCloseAction = new FileCloseAction(this.controller); + openInViewerAction = new OpenInViewerAction(this.controller); fileSaverAction = new FileSaveAction(this.controller, PdfFilter.INSTANCE, this.controller.getMasterComponent()); fileCompareAction = new FileCompareAction(this.controller, PdfFilter.INSTANCE, this.controller.getMasterComponent()); - MessageAction message = new MessageAction(); + JMenu file = new JMenu(FILE_MENU); addItem(file, OPEN, fileOpenAction, KeyStroke.getKeyStroke('O', KeyEvent.CTRL_DOWN_MASK)); - addItem(file, CLOSE, new FileCloseAction(this.controller), KeyStroke.getKeyStroke('W', KeyEvent.CTRL_DOWN_MASK)); addItem(file, SAVE_AS, fileSaverAction, KeyStroke.getKeyStroke('S', KeyEvent.CTRL_DOWN_MASK)); - addItem(file, COMPARE_WITH, fileCompareAction, KeyStroke.getKeyStroke('Q', KeyEvent.CTRL_DOWN_MASK)); file.addSeparator(); - addItem(file, OPENINVIEWER, new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (!Desktop.isDesktopSupported()) { - return; - } - try { - PdfFile pdfFile = RupsMenuBar.this.controller.getPdfFile(); - if (pdfFile == null || pdfFile.getDirectory() == null) { - return; - } - File myFile = new File(pdfFile.getDirectory(), pdfFile.getFilename()); - Desktop.getDesktop().open(myFile); - } catch (IOException ex) { - // no application registered for PDFs - } - } - }, KeyStroke.getKeyStroke('E', KeyEvent.CTRL_DOWN_MASK)); - addItem(file, NEW_INDIRECT, new NewIndirectPdfObjectDialog.AddNewIndirectAction(controller), KeyStroke.getKeyStroke('N', KeyEvent.CTRL_DOWN_MASK)); + addItem(file, CLOSE, fileCloseAction, KeyStroke.getKeyStroke('W', KeyEvent.CTRL_DOWN_MASK)); add(file); - add(Box.createGlue()); + + addItem(file, COMPARE_WITH, fileCompareAction, KeyStroke.getKeyStroke('Q', KeyEvent.CTRL_DOWN_MASK)); + addItem(file, NEW_INDIRECT, new NewIndirectPdfObjectDialog.AddNewIndirectAction(controller), KeyStroke.getKeyStroke('N', KeyEvent.CTRL_DOWN_MASK)); + + JMenu view = new JMenu(VIEW_MENU); + addItem(view, OPENINVIEWER, openInViewerAction, KeyStroke.getKeyStroke('E', KeyEvent.CTRL_DOWN_MASK)); + add(view); + JMenu help = new JMenu(HELP_MENU); - addItem(help, ABOUT, message); - addItem(help, VERSION, message); + addItem(help, ABOUT, new MessageAction("RUPS is a tool by iText Group NV.\nIt uses iText, a Free Java-PDF Library.\nVisit http://www.itextpdf.com/ for more info.\n\nThis experimental build is the Research Edition of RUPS.\n Functionality may break or behave unexpectedly.\n If so, please notify the Research Team at #research on Slack.")); + addItem(help, VERSION, new MessageAction(ITextCoreProductData.getInstance().getVersion() + " - Research Edition")); add(help); - enableItems(false); +// enableItems(false); } /** diff --git a/src/main/java/com/itextpdf/rups/view/RupsPanel.java b/src/main/java/com/itextpdf/rups/view/RupsPanel.java new file mode 100644 index 00000000..e96fa5bf --- /dev/null +++ b/src/main/java/com/itextpdf/rups/view/RupsPanel.java @@ -0,0 +1,28 @@ +package com.itextpdf.rups.view; + +import com.itextpdf.rups.controller.RupsInstanceController; +import com.itextpdf.rups.model.PdfFile; + +import javax.swing.*; +import java.awt.*; + +public class RupsPanel extends JPanel { + + private RupsInstanceController rupsInstanceController; + + public RupsPanel() { + setLayout(new BorderLayout()); + } + + public void setRupsInstanceController(RupsInstanceController rupsInstanceController) { + this.rupsInstanceController = rupsInstanceController; + } + + public PdfFile getPdfFile() { + return this.rupsInstanceController.getPdfFile(); + } + + public RupsInstanceController getRupsInstanceController() { + return this.rupsInstanceController; + } +} diff --git a/src/main/java/com/itextpdf/rups/view/RupsTabbedPane.java b/src/main/java/com/itextpdf/rups/view/RupsTabbedPane.java new file mode 100644 index 00000000..cac1b80b --- /dev/null +++ b/src/main/java/com/itextpdf/rups/view/RupsTabbedPane.java @@ -0,0 +1,57 @@ +package com.itextpdf.rups.view; + +import com.itextpdf.rups.controller.RupsInstanceController; +import com.itextpdf.rups.model.PdfFile; + +import javax.swing.*; +import java.awt.*; +import java.io.File; + +public class RupsTabbedPane extends JTabbedPane { + + private Dimension dimension; + private JPanel defaultTab; + private static final String DEFAULT_TAB_TEXT = "Drag and drop to open new file(s)."; + private static final String DEFAULT_TAB_TITLE = "New File"; + + public RupsTabbedPane(Dimension dimension) { + setDropTarget(new RupsDropTarget(this)); + defaultTab = new JPanel(); + defaultTab.add(new JLabel(DEFAULT_TAB_TEXT)); + super.addTab(DEFAULT_TAB_TITLE, defaultTab); + + this.dimension = dimension; + } + + public void openNewFile(File file, boolean readonly) { + if ( this.defaultTab.equals(getSelectedComponent())) { + removeTabAt(getSelectedIndex()); + } + + RupsPanel rupsPanel = new RupsPanel(); + RupsInstanceController rupsInstanceController = new RupsInstanceController(this.dimension, rupsPanel, false); + rupsPanel.setRupsInstanceController(rupsInstanceController); + rupsInstanceController.loadFile(file, readonly); + this.addTab(file.getName(), null, rupsPanel); + this.setSelectedComponent(rupsPanel); + } + + public void closeCurrentFile() { + this.removeTabAt(this.getSelectedIndex()); + + if ( getTabCount() == 0 ) { + this.addTab(DEFAULT_TAB_TITLE, this.defaultTab); + } + } + + public PdfFile getCurrentFile() { + Component currentComponent = this.getSelectedComponent(); + RupsPanel currentRupsPanel = (RupsPanel) currentComponent; + return currentRupsPanel.getPdfFile(); + } + + public void saveCurrentFile(File file) { + RupsPanel currentRupsPanel = (RupsPanel) this.getSelectedComponent(); + currentRupsPanel.getRupsInstanceController().saveFile(file); + } +} diff --git a/src/test/java/com/itextpdf/rups/controller/RupsControllerTest.java b/src/test/java/com/itextpdf/rups/controller/RupsControllerTest.java new file mode 100644 index 00000000..be809061 --- /dev/null +++ b/src/test/java/com/itextpdf/rups/controller/RupsControllerTest.java @@ -0,0 +1,72 @@ +package com.itextpdf.rups.controller; + +import com.itextpdf.rups.event.CloseDocumentEvent; +import com.itextpdf.rups.event.OpenFileEvent; +import com.itextpdf.rups.event.RupsEvent; +import com.itextpdf.rups.event.SaveToFileEvent; +import com.itextpdf.rups.view.RupsTabbedPane; +import org.junit.Assert; +import org.junit.Test; +import org.mozilla.javascript.tools.debugger.Dim; + +import java.awt.*; +import java.io.File; + +public class RupsControllerTest { + + @Test + public void closeTest() { + MockRupsTabbedPane rupsTabbedPane = new MockRupsTabbedPane(new Dimension()); + RupsController rupsController = new RupsController(rupsTabbedPane); + + rupsController.update(null, new CloseDocumentEvent()); + Assert.assertTrue(rupsTabbedPane.closed); + Assert.assertFalse(rupsTabbedPane.opened); + Assert.assertFalse(rupsTabbedPane.saved); + } + + @Test + public void saveTest() { + MockRupsTabbedPane rupsTabbedPane = new MockRupsTabbedPane(new Dimension()); + RupsController rupsController = new RupsController(rupsTabbedPane); + + rupsController.update(null, new SaveToFileEvent(new File(""))); + Assert.assertTrue(rupsTabbedPane.saved); + Assert.assertFalse(rupsTabbedPane.opened); + Assert.assertFalse(rupsTabbedPane.closed); + } + + @Test + public void openTest() { + MockRupsTabbedPane rupsTabbedPane = new MockRupsTabbedPane(new Dimension()); + RupsController rupsController = new RupsController(rupsTabbedPane); + + rupsController.update(null, new OpenFileEvent(new File(""))); + Assert.assertTrue(rupsTabbedPane.opened); + Assert.assertFalse(rupsTabbedPane.saved); + Assert.assertFalse(rupsTabbedPane.closed); + } + + + class MockRupsTabbedPane extends RupsTabbedPane { + private boolean closed, saved, opened; + public MockRupsTabbedPane(Dimension dimension) { + super(dimension); + } + + @Override + public void closeCurrentFile() { + closed = true; + } + + @Override + public void saveCurrentFile(File file) { + saved = true; + } + + @Override + public void openNewFile(File file, boolean readonly) { + opened = true; + } + } +}