/*
* Copyright (c) 1997-2026 IDRsolutions (https://www.idrsolutions.com)
*/
package org.jpedal.examples.viewer;
import org.jpedal.PdfDecoderInt;
import org.jpedal.display.Display;
import org.jpedal.examples.viewer.commands.AccelerationOff;
import org.jpedal.examples.viewer.commands.AccelerationOn;
import org.jpedal.examples.viewer.commands.AlwaysShowMouse;
import org.jpedal.examples.viewer.commands.AutoScroll;
import org.jpedal.examples.viewer.commands.BitMap;
import org.jpedal.examples.viewer.commands.Bookmark;
import org.jpedal.examples.viewer.commands.Buy;
import org.jpedal.examples.viewer.commands.ChangeLineArt;
import org.jpedal.examples.viewer.commands.Continuous;
import org.jpedal.examples.viewer.commands.ContinuousFacing;
import org.jpedal.examples.viewer.commands.Copy;
import org.jpedal.examples.viewer.commands.DeSelectAll;
import org.jpedal.examples.viewer.commands.DeletePropertiesOnExit;
import org.jpedal.examples.viewer.commands.DocInfo;
import org.jpedal.examples.viewer.commands.Exit;
import org.jpedal.examples.viewer.commands.ExtractImages;
import org.jpedal.examples.viewer.commands.ExtractSelectionAsImage;
import org.jpedal.examples.viewer.commands.ExtractText;
import org.jpedal.examples.viewer.commands.Facing;
import org.jpedal.examples.viewer.commands.Find;
import org.jpedal.examples.viewer.commands.FullScreen;
import org.jpedal.examples.viewer.commands.Help;
import org.jpedal.examples.viewer.commands.Highlight;
import org.jpedal.examples.viewer.commands.Info;
import org.jpedal.examples.viewer.commands.Manipulate;
import org.jpedal.examples.viewer.commands.MouseModeCommand;
import org.jpedal.examples.viewer.commands.NavigateDocuments;
import org.jpedal.examples.viewer.commands.NextResults;
import org.jpedal.examples.viewer.commands.OpenFile;
import org.jpedal.examples.viewer.commands.OpenInSystemDefault;
import org.jpedal.examples.viewer.commands.PageCount;
import org.jpedal.examples.viewer.commands.PageFlow;
import org.jpedal.examples.viewer.commands.PageGrouping;
import org.jpedal.examples.viewer.commands.PageNavigator;
import org.jpedal.examples.viewer.commands.PanMode;
import org.jpedal.examples.viewer.commands.Preferences;
import org.jpedal.examples.viewer.commands.PreviousResult;
import org.jpedal.examples.viewer.commands.Print;
import org.jpedal.examples.viewer.commands.ReplaceTextColor;
import org.jpedal.examples.viewer.commands.Reset;
import org.jpedal.examples.viewer.commands.Rotation;
import org.jpedal.examples.viewer.commands.RotationLeft;
import org.jpedal.examples.viewer.commands.RotationRight;
import org.jpedal.examples.viewer.commands.SaveFile;
import org.jpedal.examples.viewer.commands.SaveForm;
import org.jpedal.examples.viewer.commands.Scaling;
import org.jpedal.examples.viewer.commands.Scroll;
import org.jpedal.examples.viewer.commands.SelectAll;
import org.jpedal.examples.viewer.commands.SeparateCover;
import org.jpedal.examples.viewer.commands.SetDisplayBackground;
import org.jpedal.examples.viewer.commands.SetEnhanceFractionalLines;
import org.jpedal.examples.viewer.commands.SetHideLineWeights;
import org.jpedal.examples.viewer.commands.SetHighlightFormFields;
import org.jpedal.examples.viewer.commands.SetPageColor;
import org.jpedal.examples.viewer.commands.SetReplacementThreshold;
import org.jpedal.examples.viewer.commands.SetTextColor;
import org.jpedal.examples.viewer.commands.SetUndrawnPageColor;
import org.jpedal.examples.viewer.commands.ShowFormNames;
import org.jpedal.examples.viewer.commands.Sign;
import org.jpedal.examples.viewer.commands.Single;
import org.jpedal.examples.viewer.commands.Snapshot;
import org.jpedal.examples.viewer.commands.Text;
import org.jpedal.examples.viewer.commands.TextSelect;
import org.jpedal.examples.viewer.commands.Tip;
import org.jpedal.examples.viewer.commands.TriggerGC;
import org.jpedal.examples.viewer.commands.UpdateGUILayout;
import org.jpedal.examples.viewer.commands.ViewStack;
import org.jpedal.examples.viewer.commands.Viewable;
import org.jpedal.examples.viewer.commands.VisitWebsite;
import org.jpedal.examples.viewer.commands.ZoomIn;
import org.jpedal.examples.viewer.commands.ZoomOut;
import org.jpedal.examples.viewer.gui.SwingGUI;
import org.jpedal.examples.viewer.gui.swing.SearchList;
import org.jpedal.examples.viewer.gui.swing.SwingSearchWindow;
import org.jpedal.examples.viewer.gui.swing.SwingThumbnailPanel;
import org.jpedal.examples.viewer.utils.Printer;
import org.jpedal.examples.viewer.utils.PropertiesFile;
import org.jpedal.external.JPedalActionHandler;
import org.jpedal.external.Options;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.Messages;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
/**
* <h2><b>Commands</b></h2>
* <br>
* <p>This class contains code to execute the actual commands :
* <a href="https://www.idrsolutions.com/docs/jpedal/tutorials/viewer/access-pdf-viewer-features-from-your-code">Access
* PDF Viewer features from your code.</a></p>
*/
@SuppressWarnings({"WeakerAccess", "OverlyLongMethod"})
public class Commands {
/**
* used to store the IE views so we can go back to previous views and store changes
*/
protected final ViewStack viewStack = new ViewStack();
/**
* True while the Viewer is waiting for the user to drag an area to extract as an image, after {@link #SNAPSHOT}. It
* is set back to false once the area has been extracted.
*/
public boolean extractingAsImage;
private final Printer currentPrinter;
/*
* Important! You must also update ViewerCommands.java
*/
//0-50 handled in executeMenuBarCommands(final int ID, Object[] args)
/** Show the About dialog with the version details. Does nothing if arguments are passed. */
public static final int ABOUT = 1;
/** Show a dialog to export a range of pages as images. Does nothing if arguments are passed. */
public static final int BITMAP = 2;
/** Show a dialog to extract the images embedded in a range of pages. Does nothing if arguments are passed. */
public static final int IMAGES = 3;
/** Show a dialog to extract the text from a range of pages. Does nothing if arguments are passed. */
public static final int TEXT = 4;
/** Show a dialog to save the open file. Does nothing if arguments are passed. */
public static final int SAVE = 5;
/** Show the print dialog for the open document. Does nothing if arguments are passed. */
public static final int PRINT = 6;
/**
* Close the document and the Viewer, saving the Viewer settings and warning about unsaved forms first. The JVM
* exits if {@link Viewer#exitOnClose} is true. Does nothing if arguments are passed.
*/
public static final int EXIT = 7;
/**
* Toggle auto scrolling, which scrolls the view when the mouse is dragged past its edge. Does nothing if arguments
* are passed.
*/
public static final int AUTOSCROLL = 8;
/** Show the document properties dialog. Does nothing if arguments are passed. */
public static final int DOCINFO = 9;
/**
* Open a file. With no arguments a file chooser is shown. Otherwise, args are a File or String path, optionally
* followed by a String named destination to go to; an InputStream, optionally followed by a String file name; or a
* byte[] followed by a String file name. The file name's extension decides whether it is opened as a PDF or an
* image.
*/
public static final int OPENFILE = 10;
/** Go to the page of a bookmark. The arg is the String bookmark title and must be passed. */
public static final int BOOKMARK = 11;
/**
* Search the document. With no arguments the search window is shown, filled in with any highlighted text. Otherwise,
* args are the String search term, optionally followed by all three of an Integer of
* {@link org.jpedal.grouping.SearchType} flags, a Boolean for whether the term holds several words to search for
* separately, and a Boolean for whether to search only the current page. If all 3 optional values aren't present only the first is used.
*/
public static final int FIND = 12;
/**
* Let the user drag an area of the page to extract as an image. Only works in single page view. Returns a Boolean
* that is true while waiting for the user to drag the area.
*/
public static final int SNAPSHOT = 13;
/** Open a PDF from a URL. With no arguments a dialog asks for the URL. Otherwise, the arg is the String URL. */
public static final int OPENURL = 14;
/** Open the IDRsolutions website in the default browser. Does nothing if arguments are passed. */
public static final int VISITWEBSITE = 15;
/** Open the previous document in the recent documents list. Does nothing if arguments are passed. */
public static final int PREVIOUSDOCUMENT = 16;
/** Open the next document in the recent documents list. Does nothing if arguments are passed. */
public static final int NEXTDOCUMENT = 17;
/**
* Show the previous search result, wrapping round to the last result. Returns {@link #SEARCH_RETURNED_TO_START},
* {@link #SEARCH_NOT_FOUND}, {@link #FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN} or null. Does nothing if arguments are
* passed.
*/
public static final int PREVIOUSRESULT = 18;
/**
* Show the next search result, wrapping round to the first result. Returns {@link #SEARCH_RETURNED_TO_START},
* {@link #SEARCH_NOT_FOUND}, {@link #FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN} or null. Does nothing if arguments are
* passed.
*/
public static final int NEXTRESULT = 19;
/** Show the Tip of the Day dialog. Does nothing if arguments are passed. */
public static final int TIP = 20;
/** Show the preferences dialog. Does nothing if arguments are passed. */
public static final int PREFERENCES = 24;
/** Copy the highlighted text to the clipboard. Arguments are ignored. */
public static final int COPY = 25;
/** Highlight all the text on the current page. Only works in single page view. Arguments are ignored. */
public static final int SELECTALL = 26;
/** Clear all highlighted text and images. Only works in single page view. Arguments are ignored. */
public static final int DESELECTALL = 27;
/**
* Show or hide part of the Viewer's GUI. Args are the String property name of the component and a Boolean for
* whether to show it. Does nothing unless exactly 2 arguments are passed.
*/
public static final int UPDATEGUILAYOUT = 28;
/**
* Toggle the mouse between selecting text and panning the page. Not available in facing or page flow view. Does
* nothing if arguments are passed.
*/
public static final int MOUSEMODE = 29;
/** Set the mouse to pan the page. Does nothing if arguments are passed. */
public static final int PANMODE = 30;
/** Set the mouse to select text. Does nothing if arguments are passed. */
public static final int TEXTSELECT = 31;
/**
* Toggle whether the first page is shown on its own in facing views, and save the setting. Does nothing if
* arguments are passed.
*/
public static final int SEPARATECOVER = 32;
/** Show a dialog to extract the highlighted text. Does nothing if arguments are passed. */
public static final int EXTRACTTEXT = 33;
/** Show a preview of the selected area as an image, which can be copied or saved. Arguments are ignored. */
public static final int EXTRACTASIMAGE = 34;
/** Rotate the display 90 degrees anticlockwise. Arguments are ignored. */
public static final int ROTATELEFT = 35;
/** Rotate the display 90 degrees clockwise. Arguments are ignored. */
public static final int ROTATERIGHT = 36;
/**
* Open the current file in the operating system's default application. Optionally the arg is a String path of a
* different file to open.
*/
public static final int OPENINSYSTEMDEFAULT = 37;
/** Show the dialog to digitally sign the open file. Does nothing if arguments are passed. */
public static final int SIGN = 40;
//0-49 handled in executeMenuBarCommands(final int ID, Object[] args)
//50-249 handled in executeDisplayCommands(final int ID, Object[] args)
/** Go to the first page. Does nothing if arguments are passed. */
public static final int FIRSTPAGE = 50;
/** Go back 10 pages, stopping at the first page. Does nothing if arguments are passed. */
public static final int FBACKPAGE = 51;
/** Go back 1 page. Optionally the arg is the number of pages to go back, as a String. */
public static final int BACKPAGE = 52;
/** Go forward 1 page. Optionally the arg is the number of pages to go forward, as a String. */
public static final int FORWARDPAGE = 53;
/** Go forward 10 pages, stopping at the last page. Does nothing if arguments are passed. */
public static final int FFORWARDPAGE = 54;
/** Go to the last page. Does nothing if arguments are passed. */
public static final int LASTPAGE = 55;
/**
* Go to a page. With no arguments a dialog asks for the page number. Otherwise the arg is the page number as a
* String.
*/
public static final int GOTO = 56;
/** Show one page at a time and set the mouse to select text. Does nothing if arguments are passed. */
public static final int SINGLE = 57;
/**
* Show the pages in a continuous vertical column and set the mouse to pan. Does nothing if arguments are passed.
*/
public static final int CONTINUOUS = 58;
/**
* Show the pages in a continuous column of facing pairs, fit to the page, and set the mouse to pan. Does nothing if
* arguments are passed.
*/
public static final int CONTINUOUS_FACING = 59;
/**
* Show the pages as facing pairs, fit to the page, and set the mouse to pan. Does nothing if arguments are passed.
*/
public static final int FACING = 60;
/** Show the pages in the page flow view, which needs JavaFX. Does nothing if arguments are passed. */
public static final int PAGEFLOW = 61;
/** Toggle full screen mode, if supported. Does nothing if arguments are passed. */
public static final int FULLSCREEN = 62;
/** Zoom in to the next preset scaling, up to 1000%. Does nothing if arguments are passed. */
public static final int ZOOMIN = 63;
/** Zoom out to the next preset scaling, down to 25%. Does nothing if arguments are passed. */
public static final int ZOOMOUT = 64;
/** Show a PDF portfolio's files as a detailed list. Arguments are ignored. */
public static final int PORTFOLIO_DETAIL = 65;
/** Show a PDF portfolio's files as tiles. Arguments are ignored. */
public static final int PORTFOLIO_TILES = 66;
//50-249 handled in executeDisplayCommands(final int ID, Object[] args)
//250-299 handled in executeComboCommands(final int ID, Object[] args)
//combo boxes start at 250
/**
* Rotate the display. With no arguments the rotation selected in the toolbar is applied. Otherwise, the arg is the
* rotation in degrees as a String: 0, 90, 180 or 270.
*/
public static final int ROTATION = 251;
/**
* Set the scaling. With no arguments the scaling selected in the toolbar is applied. Otherwise, the arg is the
* scaling as a percentage number or one of the toolbar's text options, such as "Fit Width".
*/
public static final int SCALING = 252;
//250-299 handled in executeComboCommands(final int ID, Object[] args)
//300-499 not handled here
/**
* Identifies the whole Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a command does
* nothing.
*/
public static final int CURRENTMENU = 300;
/**
* Identifies the Content menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int CONTENTMENU = 304;
/** Not used by the Viewer. Running it as a command does nothing. */
public static final int PDFMENU = 306;
/**
* Identifies the Export menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int EXPORTMENU = 307;
/** Not used by the Viewer. Running it as a command does nothing. */
public static final int WINDOWMENU = 308;
/**
* Identifies the Page Layout menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it
* as a command does nothing.
*/
public static final int PAGELAYOUTMENU = 309;
/**
* Identifies the Edit menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int EDITMENU = 310;
/**
* Identifies the Go To menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int GOTOMENU = 311;
/**
* Identifies the View menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int VIEWMENU = 312;
/**
* Identifies the Open menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int OPENMENU = 316;
/**
* Identifies the File menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int FILEMENU = 317;
/** Not used by the Viewer. The Help menu is identified by {@link #HELP}. Running it as a command does nothing. */
public static final int HELPFORUM = 318;
/**
* Identifies the Portfolio menu, which is only shown for PDF portfolios, in the Swing menu bar, for showing,
* hiding, enabling or disabling it. Running it as a command does nothing.
*/
public static final int PORTFOLIOMENU = 319;
/**
* Identifies the Tools menu in the Swing menu bar, for showing, hiding, enabling or disabling it. Running it as a
* command does nothing.
*/
public static final int TOOLSMENU = 320;
//300-499 not handled here
// external menu options start at 500 - add your own CONSTANT here
// and refer to action using name at ALL times
//500-599 (existing values) handled in executeExternalCommands(final int ID, Object[] args)
/**
* Show a dialog to save the document after annotations have been added. If no annotation has been added, no file is
* written. Does nothing if arguments are passed.
*/
public static final int SAVEFORM = 500;
//500-599 (existing values) handled in executeExternalCommands(final int ID, Object[] args)
//600-699 handled in executePageCommands(final int ID, Object[] args)
/**
* Clear the current text highlights, then highlight areas on a page. Args are an int[][] of {x, y, width, height}
* rectangles in PDF coordinates, the Integer page, and an optional Boolean, default true, where true highlights the
* rectangles and false highlights whole lines from the top left to the bottom right. With no arguments the
* highlights are only cleared.
*/
public static final int HIGHLIGHT = 600;
/**
* Scroll an area of a page into view. Args are an int[] {x, y, width, height} rectangle and an optional Integer
* page, default the current page. Does nothing with no arguments.
*/
public static final int SCROLL = 601;
//600-699 handled in executePageCommands(final int ID, Object[] args)
//700-899 handled in executeViewerFunctionalityCommands(final int ID, Object[] args)
// commands for the forward and back tracking of views, ie when a page changes
/**
* Add a view to the history used by {@link #FORWARD} and {@link #BACK}. Args are the Integer page, the Rectangle
* location and the Integer scaling type.
*/
public static final int ADDVIEW = 700;
/** Go forward to the next view in the history added by {@link #ADDVIEW}. Arguments are ignored. */
public static final int FORWARD = 701;
/** Go back to the previous view in the history added by {@link #ADDVIEW}. Arguments are ignored. */
public static final int BACK = 702;
/**
* Return the number of pages in the open document as an Integer, or -1 if there is no decoder. Arguments are
* ignored.
*/
public static final int PAGECOUNT = 703;
/** Return the current page number as an Integer. Arguments are ignored. */
public static final int CURRENTPAGE = 704;
/** Rebuild the bookmarks and return the outline (bookmarks) panel. Arguments are ignored. */
public static final int GETOUTLINEPANEL = 705;
/** Return the thumbnail panel. Arguments are ignored. */
public static final int GETTHUMBNAILPANEL = 706;
/** Return the page number text field from the navigation bar. Arguments are ignored. */
public static final int GETPAGECOUNTER = 707;
/**
* Return the text grouping object for a page, decoding the page in the background if it is not the page being
* displayed. The arg is the Integer page. Returns null with no arguments or if an error occurs.
*/
public static final int PAGEGROUPING = 708;
/** Set the page background colour and repaint. The arg is the colour as an Integer RGB value. */
public static final int SETPAGECOLOR = 709;
/** Set the colour shown for pages that have not been drawn yet. The arg is the colour as an Integer RGB value. */
public static final int SETUNDRAWNPAGECOLOR = 710;
/**
* Set the colour all text is drawn in, without repainting. The arg is the colour as an Integer RGB value.
* {@link #SETTEXTCOLOR} does the same and repaints.
*/
public static final int REPLACETEXTCOLOR = 711;
/** Set the colour all text is drawn in and repaint. The arg is the colour as an Integer RGB value. */
public static final int SETTEXTCOLOR = 712;
/**
* Set whether shapes and line art are recoloured along with the text when a text colour is set, then repaint. The
* arg is a Boolean.
*/
public static final int CHANGELINEART = 713;
/**
* Set the background colour of the display area around the pages. The arg is the colour as an Integer RGB value.
*/
public static final int SETDISPLAYBACKGROUND = 714;
/**
* Set the threshold that decides which text is recoloured when a text colour is set. The arg is the threshold as an
* Integer.
*/
public static final int SETREPLACEMENTCOLORTHRESHOLD = 715;
/** Set whether lines thinner than 1 pixel are widened so they stay visible, then repaint. The arg is a Boolean. */
public static final int SETENHANCEFRACTIONALLINES = 717;
/** Set whether all shapes are drawn with a 1 pixel stroke after scaling, then repaint. The arg is a Boolean. */
public static final int SETHIDELINEWEIGHTS = 718;
/** Set whether interactive form fields are highlighted, then repaint. The arg is a Boolean. */
public static final int SETHIGHLIGHTFORMFIELDS = 719;
/** Remove the version number from the window title. Arguments are ignored. */
public static final int HIDEVERSIONNUMBER = 720;
/** Show the version number in the window title. Arguments are ignored. */
public static final int SHOWVERSIONNUMBER = 721;
//700-899 handled in executeViewerFunctionalityCommands(final int ID, Object[] args)
//997-999 handled in executeDemoVersionCommands(final int ID, Object[] args)
/** Open the JPedal documentation in the default browser. Does nothing if arguments are passed. */
public static final int HELP = 998;
/** Open the JPedal pricing page in the default browser. Does nothing if arguments are passed. */
public static final int BUY = 999;
//997-999 handled in executeDemoVersionCommands(final int ID, Object[] args)
//1000-1099 handled in executeDebugCommands(final int ID, Object[] args)
/**
* Debug command that resets the Viewer's internal viewport scale and offsets. Does nothing if arguments are passed.
*/
public static final int RESET = 1_002;
/**
* Debug command that turns on hardware acceleration for screen rendering and repaints. Does nothing if arguments
* are passed.
*/
public static final int ACCELERATIONON = 1_003;
/**
* Debug command that turns off hardware acceleration for screen rendering and repaints. Does nothing if arguments
* are passed.
*/
public static final int ACCELERATIONOFF = 1_004;
/** Debug command that prints the names of all form fields to standard out. Does nothing if arguments are passed. */
public static final int SHOWFORMNAMES = 1_006;
/**
* Debug command that makes the Viewer delete its properties file when its window is closed. Does nothing if
* arguments are passed.
*/
public static final int DELETEPROPERTIESONEXIT = 1_007;
/** Debug command that toggles whether the mouse cursor is always shown. Does nothing if arguments are passed. */
public static final int ALWAYSSHOWMOUSE = 1_008;
/** Debug command that calls {@link System#gc()}. Does nothing if arguments are passed. */
public static final int TRIGGERGC = 1_009;
//1000-1099 handled in executeDebugCommands(final int ID, Object[] args)
//1100-1199 handle in executeToolsCommands(final int ID, Object[] args)
// manipulations and sanitizations
/**
* Show a dialog to insert blank pages of a chosen size, then save the document (asking whether to overwrite the
* open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int ADDPAGE = 1_101;
/**
* Show a dialog to choose pages and an image, then let the user drag the area to place it in, then save the
* document (asking whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int ADDIMAGE = 1_102;
/**
* Show a dialog to copy a page to another position, then save the document (asking whether to overwrite the open
* file) and reopen it. Does nothing if arguments are passed.
*/
public static final int COPYPAGE = 1_103;
/**
* Show a dialog to crop pages, then save the document (asking whether to overwrite the open file) and reopen it.
* Does nothing if arguments are passed.
*/
public static final int CROPPAGE = 1_104;
/**
* Show a dialog to embed a file in the document as an attachment, then save the document (asking whether to
* overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int EMBEDFILE = 1_105;
/**
* Show a dialog to choose pages to keep, removing all the others, then save the document (asking whether to
* overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int ISOLATEPAGE = 1_106;
/**
* Show a dialog to combine several pages onto each page in a grid of rows and columns, then save the document
* (asking whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int NUP = 1_107;
/**
* Show a dialog to remove pages, then save the document (asking whether to overwrite the open file) and reopen it.
* Does nothing if arguments are passed.
*/
public static final int REMOVEPAGE = 1_108;
/**
* Show a dialog to rotate pages, then save the document (asking whether to overwrite the open file) and reopen it.
* Does nothing if arguments are passed.
*/
public static final int ROTATEPAGE = 1_109;
/**
* Show a dialog to scale pages, then save the document (asking whether to overwrite the open file) and reopen it.
* Does nothing if arguments are passed.
*/
public static final int SCALEPAGE = 1_110;
/**
* Show a dialog to edit the document information, which is written to both the Info dictionary and the XMP
* metadata, then save the document (asking whether to overwrite the open file) and reopen it. Does nothing if
* arguments are passed.
*/
public static final int SETDOCUMENTINFO = 1_112;
/**
* Show a dialog to set the page, page layout and page mode the document opens with, then save the document (asking
* whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int SETINITIALVIEW = 1_113;
/**
* Remove all bookmarks, then save the document (asking whether to overwrite the open file) and reopen it. Does
* nothing if arguments are passed.
*/
public static final int REMOVEBOOKMARKS = 1_114;
/**
* Remove all embedded files, then save the document (asking whether to overwrite the open file) and reopen it. Does
* nothing if arguments are passed.
*/
public static final int REMOVEEMBEDDEDFILES = 1_115;
/**
* Remove the initial view settings, then save the document (asking whether to overwrite the open file) and reopen
* it. Does nothing if arguments are passed.
*/
public static final int REMOVEINITIALVIEW = 1_116;
/**
* Remove all JavaScript, then save the document (asking whether to overwrite the open file) and reopen it. Does
* nothing if arguments are passed.
*/
public static final int REMOVEJAVASCRIPT = 1_117;
/**
* Remove all links, then save the document (asking whether to overwrite the open file) and reopen it. Does nothing
* if arguments are passed.
*/
public static final int REMOVELINKS = 1_118;
/**
* Remove the document metadata, then save the document (asking whether to overwrite the open file) and reopen it.
* Does nothing if arguments are passed.
*/
public static final int REMOVEMETADATA = 1_119;
/**
* Show a dialog to move a page to another position, then save the document (asking whether to overwrite the open
* file) and reopen it. Does nothing if arguments are passed.
*/
public static final int MOVEPAGE = 1_120;
/**
* Show a dialog to choose pages to remove annotations from, then save the document (asking whether to overwrite the
* open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int REMOVEANNOTATIONS = 1_121;
/**
* Reverse the page order, then save the document (asking whether to overwrite the open file) and reopen it. Does
* nothing if arguments are passed.
*/
public static final int REVERSEPAGES = 1_122;
/**
* Show a dialog to choose pages, then let the user drag the area of text to redact, then save the document (asking
* whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int REDACT = 1_123;
/**
* Downsample all images using the default settings, then save the document (asking whether to overwrite the open
* file) and reopen it. Does nothing if arguments are passed.
*/
public static final int DOWNSAMPLEIMAGES = 1_124;
/**
* Flatten all layers, removing hidden layers and making visible layers permanent, then save the document (asking
* whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int FLATTENLAYERS = 1_125;
/**
* Optimise image colour palettes to fit an indexed colour space, losslessly reducing image size, then save the
* document (asking whether to overwrite the open file) and reopen it. Does nothing if arguments are passed.
*/
public static final int OPTIMIZECOLORPALETTE = 1_126;
/**
* Remove blank pages, then save the document (asking whether to overwrite the open file) and reopen it. Does
* nothing if arguments are passed.
*/
public static final int REMOVEBLANKPAGES = 1_127;
/**
* Remove all digital signatures, then save the document (asking whether to overwrite the open file) and reopen it.
* Does nothing if arguments are passed.
*/
public static final int REMOVEDIGITALSIGNATURES = 1_128;
//1100-1199 handle in executeToolsCommands(final int ID, Object[] args)
//status values returned by command
/**
* Returned by {@link #NEXTRESULT} and {@link #PREVIOUSRESULT} when the first search result in the document is now
* shown.
*/
public static final Integer FIRST_DOCUMENT_SEARCH_RESULT_NOW_SHOWN = 1;
/**
* Returned by {@link #NEXTRESULT} and {@link #PREVIOUSRESULT} when the search wrapped round past the end or start
* of the document.
*/
public static final Integer SEARCH_RETURNED_TO_START = 2;
/** Returned by {@link #NEXTRESULT} and {@link #PREVIOUSRESULT} when no page has any search results. */
public static final Integer SEARCH_NOT_FOUND = 3;
protected final Values commonValues;
protected final SwingGUI currentGUI;
protected final PdfDecoderInt decode_pdf;
protected final SwingThumbnailPanel thumbnails;
protected final PropertiesFile properties;
protected final SwingSearchWindow searchFrame;
/**
* tracks mouse operation mode currently selected
*/
protected final MouseMode mouseMode = new MouseMode();
/**
* Create the command handler for a Viewer. The Viewer creates this itself, so most code should get it from the
* Viewer rather than constructing one.
*
* @param commonValues the Viewer's shared state, such as the open file and current page
* @param currentGUI the Swing GUI the commands act on
* @param decode_pdf the decoder displaying the PDF
* @param thumbnails the thumbnail panel
* @param properties the Viewer's preferences
* @param searchFrame the search window used by the find and search result commands
*/
public Commands(final Values commonValues, final SwingGUI currentGUI, final PdfDecoderInt decode_pdf, final SwingThumbnailPanel thumbnails,
final PropertiesFile properties, final SwingSearchWindow searchFrame) {
this.commonValues = commonValues;
this.currentGUI = currentGUI;
this.decode_pdf = decode_pdf;
this.thumbnails = thumbnails;
this.properties = properties;
this.searchFrame = searchFrame;
//Define printer here as it is only required for the Swing Viewer
currentPrinter = new Printer();
}
private Object commandExecutor(final int ID, Object[] args) {
//teat null and Object[]{null} as both null
if (args != null && ((args.length == 1 && args[0] == null) || args.length == 0)) {
args = null;
}
final Map<Integer, Object> jpedalActionHandlers = (Map<Integer, Object>) decode_pdf.getExternalHandler(Options.JPedalActionHandlers);
if (jpedalActionHandlers != null) {
final JPedalActionHandler jpedalAction = (JPedalActionHandler) jpedalActionHandlers.get(ID);
if (jpedalAction != null) {
jpedalAction.actionPerformed(currentGUI, this);
return null;
}
}
Object status = null;
if (ID < FIRSTPAGE) {
status = executeMenuBarCommands(ID, args);
} else if (ID < ROTATION) {
executeDisplayCommands(ID, args);
} else if (ID < CURRENTMENU) {
executeComboCommands(ID, args);
} else if (ID < HIGHLIGHT) {
executeExternalCommands(ID, args);
} else if (ID < ADDVIEW) {
executePageCommands(ID, args);
} else if (ID < 997) {
status = executeViewerFunctionalityCommands(ID, args);
} else if (ID < 1_000) { //Use hard coded value for a debug value remvoed during build
executeDemoVersionCommands(ID, args);
} else if (ID < 1_100) {
executeDebugCommands(ID, args);
} else {
executeToolsCommands(ID, args, commonValues, searchFrame,
currentGUI, decode_pdf, properties, thumbnails);
}
return status;
}
/**
* Run a Viewer command. A null, empty or single-null {@code args} array is treated as no arguments, which for most
* commands means they use the current Viewer state or show a dialog. If a {@link JPedalActionHandler} has been
* registered for the command with {@link Options#JPedalActionHandlers}, that handler is run instead and null is
* returned.
*
* @param command the command to run
* @param args the arguments for the command, or null
*
* @return the command's result for commands that return one (such as {@link #PAGECOUNT} or the search result
* commands), otherwise null
*/
public Object executeCommand(final ViewerCommands command, final Object[] args) {
return commandExecutor(command.commandID, args);
}
/**
* Returns a value from the Viewer.
*
* @param value the value to get
*
* @return the page count or current page as an Integer, the open file name as a String, the scaling as a float,
* the page layout or the rotation as an int, or null for an unknown value
*/
public Object getValue(final ViewerValues value) {
return switch (value) {
case PAGECOUNT -> commandExecutor(PAGECOUNT, null);
case PDFNAME -> commonValues.getSelectedFile();
case CURRENTPAGE -> commandExecutor(CURRENTPAGE, null);
case SCALE -> decode_pdf.getScaling();
case PAGELAYOUT -> decode_pdf.getDisplayView();
case ROTATION -> decode_pdf.getDisplayRotation();
};
}
/**
* Open a file dropped onto the Viewer. Any unsaved form changes are handled first, then this waits until no other
* dropped file is opening and the Viewer is not processing. A message is shown if a local file does not exist.
*
* @param file the path or http/https URL of the file to open
*/
public void handleTransferedFile(final String file) {
//Before anything handle any unsaved forms
SaveFile.handleUnsaveForms(currentGUI, commonValues);
while (Values.getOpeningTransferedFile() || Values.isProcessing()) {
try {
Thread.sleep(250);
} catch (final InterruptedException e) {
LogWriter.error(e, "Exception thrown, waiting for transferred file to open interrupted");
}
}
Values.setOpeningTransferedFile(true);
try {
final boolean isURL = file.startsWith("http:") || file.startsWith("https:");
if (!isURL && Files.notExists(Paths.get(file))) {
currentGUI.showMessageDialog(Messages.getMessage("PdfViewerFile.text") + file + Messages.getMessage("PdfViewerNotExist"));
return;
}
commonValues.setFileIsURL(isURL);
if (!isURL) {
commonValues.setFileSize(new File(file).length() >> 10);
}
commonValues.setSelectedFile(file);
currentGUI.setViewerTitle();
if (!Values.isProcessing()) {
OpenFile.executeOpenFile(new Object[] {commonValues.getSelectedFile()}, commonValues, searchFrame, currentGUI, decode_pdf, properties, thumbnails);
}
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " opening transferred file");
} finally {
Values.setOpeningTransferedFile(false);
}
}
/**
* Rebuild the recent documents menu from the list stored in the Viewer's preferences.
*/
public void recentDocumentsOption() {
currentGUI.setRecentDocument();
final String[] recentDocs = properties.getRecentDocuments();
if (recentDocs == null) {
return;
}
for (int i = 0; i < PropertiesFile.getNoRecentDocumentsToDisplay(); i++) {
if (recentDocs[i] == null) {
recentDocs[i] = "";
}
try {
final String fileNameToAdd = recentDocs[i];
currentGUI.getRecentDocument().createMenuItems(fileNameToAdd, i, currentGUI, commonValues);
} catch (final Exception ee) {
LogWriter.error(ee, "Error generating recent documents list for Viewer");
}
}
}
/**
* Returns the searchList of the last search preformed. If currently searching this method will return the results
* for last completed search
*
* @return SearchList of all results, all data but the actual highlgiht areas
*/
public SearchList getSearchList() {
return searchFrame.getResults();
}
/**
* {@return the mouse mode, which records whether the mouse is selecting text or panning the page}
*/
public MouseMode getMouseMode() {
return mouseMode;
}
/**
* examine first few bytes to see if linearized and return true linearized file
*
* @param pdfUrl is of type String
*
* @return the isLinear
*/
public static boolean isPDFLinearized(final String pdfUrl) {
if (pdfUrl.startsWith("jar")) {
return false;
}
//read first few bytes
try (InputStream is = new URI(pdfUrl).toURL().openStream()) {
// Download buffer
final byte[] buffer = new byte[128];
is.read(buffer);
is.close();
//scan for Linearized in text
final int lim = buffer.length - 6;
for (int i = 0; i < lim; i++) {
if (buffer[i] == '/' && buffer[i + 1] == 'L' && buffer[i + 2] == 'i' && buffer[i + 3] == 'n' && buffer[i + 4] == 'e' && buffer[i + 5] == 'a' && buffer[i + 6] == 'r') {
return true;
}
}
} catch (final IOException | URISyntaxException e) {
LogWriter.writeLog("[PDF] Exception " + e + " scanning URL " + pdfUrl);
}
return false;
}
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
private Object executeMenuBarCommands(final int ID, final Object[] args) {
Object status = null;
switch (ID) {
case ABOUT -> Info.execute(args, currentGUI); //Gets the info box
case BITMAP -> BitMap.execute(args, currentGUI, commonValues, decode_pdf);
case IMAGES -> ExtractImages.execute(args, currentGUI, commonValues, decode_pdf);
case TEXT -> Text.execute(args, currentGUI, commonValues, decode_pdf);
case SAVE -> SaveFile.execute(args, currentGUI, commonValues);
case PRINT -> Print.execute(args, currentGUI, commonValues, properties, currentPrinter, decode_pdf);
case EXIT -> Exit.execute(args, thumbnails, currentGUI, commonValues, decode_pdf, properties);
case AUTOSCROLL -> AutoScroll.execute(args, currentGUI);
case DOCINFO -> DocInfo.execute(args, currentGUI, commonValues, decode_pdf);
case OPENFILE -> OpenFile.executeOpenFile(args, commonValues, searchFrame, currentGUI,
decode_pdf, properties, thumbnails);
case BOOKMARK -> Bookmark.execute(args, currentGUI);
case FIND -> Find.execute(args, commonValues, currentGUI, decode_pdf, searchFrame);
case SNAPSHOT -> {
status = Snapshot.execute(args, currentGUI, decode_pdf, extractingAsImage);
//we need to sync value
extractingAsImage = (Boolean) status;
}
case OPENURL -> OpenFile.executeOpenURL(args, commonValues, searchFrame, currentGUI,
decode_pdf, properties, thumbnails);
case VISITWEBSITE -> VisitWebsite.execute(args, currentGUI);
case PREVIOUSDOCUMENT -> NavigateDocuments.executePrevDoc(args, currentGUI);
case NEXTDOCUMENT -> NavigateDocuments.executeNextDoc(args, currentGUI);
case PREVIOUSRESULT ->
status = PreviousResult.execute(args, commonValues, currentGUI, decode_pdf, searchFrame);
case NEXTRESULT -> status = NextResults.execute(args, commonValues, searchFrame, currentGUI, decode_pdf);
case TIP -> Tip.execute(args, currentGUI, properties);
case PREFERENCES -> Preferences.execute(args, currentGUI);
case COPY -> Copy.execute(currentGUI, decode_pdf, commonValues);
case SELECTALL -> SelectAll.execute(currentGUI, decode_pdf, commonValues);
case DESELECTALL -> DeSelectAll.execute(currentGUI, decode_pdf);
case UPDATEGUILAYOUT -> UpdateGUILayout.execute(args, currentGUI);
case MOUSEMODE -> MouseModeCommand.execute(args, currentGUI, mouseMode, decode_pdf);
case PANMODE -> PanMode.execute(args, currentGUI, mouseMode, decode_pdf);
case TEXTSELECT -> TextSelect.execute(args, currentGUI, mouseMode);
case SEPARATECOVER -> SeparateCover.execute(args, decode_pdf, properties, currentGUI, commonValues);
case EXTRACTTEXT -> ExtractText.execute(args, currentGUI, decode_pdf, commonValues);
case EXTRACTASIMAGE -> ExtractSelectionAsImage.execute(commonValues, currentGUI, decode_pdf);
case ROTATELEFT -> RotationLeft.execute(currentGUI, commonValues);
case ROTATERIGHT -> RotationRight.execute(currentGUI, commonValues);
case OPENINSYSTEMDEFAULT -> OpenInSystemDefault.execute(args, currentGUI, commonValues);
case SIGN -> Sign.execute(args, currentGUI, commonValues);
}
return status;
}
private void executeDisplayCommands(final int ID, final Object[] args) {
switch (ID) {
case FIRSTPAGE -> PageNavigator.goFirstPage(args, commonValues, decode_pdf, currentGUI);
case FBACKPAGE -> PageNavigator.goFBackPage(args, commonValues, decode_pdf, currentGUI);
case BACKPAGE -> PageNavigator.goBackPage(args, commonValues, decode_pdf, currentGUI);
case FORWARDPAGE -> PageNavigator.goForwardPage(args, commonValues, decode_pdf, currentGUI);
case FFORWARDPAGE -> PageNavigator.goFForwardPage(args, commonValues, decode_pdf, currentGUI);
case LASTPAGE -> PageNavigator.goLastPage(args, commonValues, decode_pdf, currentGUI);
case GOTO -> PageNavigator.goPage(args, currentGUI, commonValues, decode_pdf);
case SINGLE -> {
Single.execute(args, decode_pdf, currentGUI);
TextSelect.execute(args, currentGUI, mouseMode); //Enable text selection
}
case CONTINUOUS -> {
Continuous.execute(decode_pdf, currentGUI, args);
PanMode.execute(args, currentGUI, mouseMode, decode_pdf); //Enables Panning of document
}
case CONTINUOUS_FACING -> {
ContinuousFacing.execute(args, decode_pdf, currentGUI, commonValues);
PanMode.execute(args, currentGUI, mouseMode, decode_pdf); //Enables Panning of document
}
case FACING -> {
Facing.execute(args, decode_pdf, currentGUI, commonValues);
PanMode.execute(args, currentGUI, mouseMode, decode_pdf); //Enables Panning of document
}
case PAGEFLOW -> PageFlow.execute(args, currentGUI, commonValues, decode_pdf, properties, searchFrame);
case FULLSCREEN -> FullScreen.execute(args, currentGUI);
case ZOOMIN -> ZoomIn.execute(args, currentGUI, decode_pdf);
case ZOOMOUT -> ZoomOut.execute(args, currentGUI, decode_pdf);
case PORTFOLIO_DETAIL -> currentGUI.setDisplayView(Display.PORTFOLIO_DETAIL, Display.DISPLAY_CENTERED);
case PORTFOLIO_TILES -> currentGUI.setDisplayView(Display.PORTFOLIO_TILE, Display.DISPLAY_CENTERED);
}
}
private void executeDemoVersionCommands(final int ID, final Object[] args) {
switch (ID) {
case HELP -> Help.execute(args); //gets the help box
case BUY -> Buy.execute(args, currentGUI); //takes user to pricing page
}
}
private void executeComboCommands(final int ID, final Object[] args) {
switch (ID) {
case SCALING -> Scaling.execute(args, commonValues, decode_pdf, currentGUI, viewStack);
case ROTATION -> Rotation.execute(args, currentGUI, commonValues);
}
}
private void executeExternalCommands(final int ID, final Object[] args) {
if (ID == SAVEFORM) {
SaveForm.execute(args, currentGUI, decode_pdf, commonValues);
}
}
private void executePageCommands(final int ID, final Object[] args) {
switch (ID) {
case HIGHLIGHT -> Highlight.execute(args, decode_pdf);
case SCROLL -> Scroll.execute(args, currentGUI, commonValues, decode_pdf);
}
}
@SuppressWarnings("java:S138")
private Object executeViewerFunctionalityCommands(final int ID, final Object[] args) {
Object status = null;
switch (ID) {
case ADDVIEW -> viewStack.add((Integer) args[0], (Rectangle) args[1], (Integer) args[2]);
case FORWARD -> {
//go forward to next viewed location
final Viewable next = viewStack.forward();
if (next != null) {
decode_pdf.getFormRenderer().getActionHandler().changeTo(null, next.getPage(),
next.getLocation(), next.getType(), false);
}
}
case BACK -> {
//go back to last viewed location
final Viewable previous = viewStack.back();
if (previous != null) {
decode_pdf.getFormRenderer().getActionHandler().changeTo(null, previous.getPage(),
previous.getLocation(), previous.getType(), false);
}
}
case PAGECOUNT -> status = PageCount.execute(decode_pdf);
case CURRENTPAGE -> status = currentGUI.getValues().getCurrentPage();
case GETOUTLINEPANEL -> {
//ensure setup
currentGUI.setBookmarks(true);
status = currentGUI.getOutlinePanel();
}
case GETTHUMBNAILPANEL -> {
//ensure setup
currentGUI.setBookmarks(true);
status = currentGUI.getThumbnailPanel();
}
case GETPAGECOUNTER -> status = currentGUI.getPageCounter(SwingGUI.PageCounter.PAGECOUNTER2);
case PAGEGROUPING -> status = PageGrouping.execute(args, decode_pdf); //Group Pages
case SETPAGECOLOR -> SetPageColor.execute(args, decode_pdf);
case SETUNDRAWNPAGECOLOR -> SetUndrawnPageColor.execute(args, decode_pdf);
case REPLACETEXTCOLOR -> ReplaceTextColor.execute(args, decode_pdf);
case SETTEXTCOLOR -> SetTextColor.execute(args, decode_pdf);
case CHANGELINEART -> ChangeLineArt.execute(args, decode_pdf);
case SETDISPLAYBACKGROUND -> SetDisplayBackground.execute(args, decode_pdf);
case SETREPLACEMENTCOLORTHRESHOLD -> SetReplacementThreshold.execute(args, decode_pdf);
case SETENHANCEFRACTIONALLINES -> //Used for JavaFX Netbeans PDF Viewer Plugin.
SetEnhanceFractionalLines.execute(args, decode_pdf);
case SETHIDELINEWEIGHTS -> SetHideLineWeights.execute(args, decode_pdf);
case SETHIGHLIGHTFORMFIELDS -> SetHighlightFormFields.execute(args, decode_pdf);
case HIDEVERSIONNUMBER -> currentGUI.hideVersionNumber();
case SHOWVERSIONNUMBER -> currentGUI.showVersionNumber();
}
return status;
}
private void executeDebugCommands(final int ID, final Object[] args) {
switch (ID) {
case RESET -> Reset.execute(args, commonValues);
case ACCELERATIONON -> AccelerationOn.execute(args, decode_pdf);
case ACCELERATIONOFF -> AccelerationOff.execute(args, decode_pdf);
case SHOWFORMNAMES -> ShowFormNames.execute(args, decode_pdf);
case DELETEPROPERTIESONEXIT -> DeletePropertiesOnExit.execute(args);
case ALWAYSSHOWMOUSE -> AlwaysShowMouse.execute(args);
case TRIGGERGC -> TriggerGC.execute(args);
}
}
/**
* Handle commands for the {@link org.jpedal.manipulator.PdfManipulator}
*/
private static void executeToolsCommands(final int ID, final Object[] args, final Values commonValues,
final SwingSearchWindow searchFrame, final SwingGUI currentGUI, final PdfDecoderInt decode_pdf,
final PropertiesFile properties, final SwingThumbnailPanel thumbnails) {
Manipulate.execute(ID, args, commonValues, searchFrame,
currentGUI, decode_pdf, properties, thumbnails);
}
}
|