/*
* Copyright (c) 1997-2024 IDRsolutions (https://www.idrsolutions.com)
*/
package org.jpedal.examples.viewer.gui;
import com.idrsolutions.image.JDeli;
import org.jpedal.FileAccess;
import org.jpedal.FileAccessHelper;
import org.jpedal.PdfDecoder;
import org.jpedal.PdfDecoderInt;
import org.jpedal.constants.JPedalSettings;
import org.jpedal.display.Display;
import org.jpedal.display.GUIDisplay;
import org.jpedal.display.PageOffsets;
import org.jpedal.display.swing.MultiDisplay;
import org.jpedal.display.swing.SingleDisplay;
import org.jpedal.examples.viewer.Commands;
import org.jpedal.examples.viewer.RecentDocuments;
import org.jpedal.examples.viewer.Values;
import org.jpedal.examples.viewer.ViewerCommands;
import org.jpedal.examples.viewer.commands.OpenFile;
import org.jpedal.examples.viewer.commands.PageNavigator;
import org.jpedal.examples.viewer.gui.popups.PrintPanel;
import org.jpedal.examples.viewer.gui.swing.ColorListCellRenderer;
import org.jpedal.examples.viewer.gui.swing.FrameCloser;
import org.jpedal.examples.viewer.gui.swing.SearchList;
import org.jpedal.examples.viewer.gui.swing.SwingAnnotationPanel;
import org.jpedal.examples.viewer.gui.swing.SwingAttachmentsPanel;
import org.jpedal.examples.viewer.gui.swing.SwingCombo;
import org.jpedal.examples.viewer.gui.swing.SwingCommandListener;
import org.jpedal.examples.viewer.gui.swing.SwingLayersPanel;
import org.jpedal.examples.viewer.gui.swing.SwingMenuItems;
import org.jpedal.examples.viewer.gui.swing.SwingMouseListener;
import org.jpedal.examples.viewer.gui.swing.SwingMouseUtils;
import org.jpedal.examples.viewer.gui.swing.SwingPageChanger;
import org.jpedal.examples.viewer.gui.swing.SwingPortfolioDetail;
import org.jpedal.examples.viewer.gui.swing.SwingPortfolioTile;
import org.jpedal.examples.viewer.gui.swing.SwingScrollListener;
import org.jpedal.examples.viewer.gui.swing.SwingSearchWindow;
import org.jpedal.examples.viewer.gui.swing.SwingSignaturesPanel;
import org.jpedal.examples.viewer.gui.swing.SwingThumbnailPanel;
import org.jpedal.examples.viewer.paper.PaperSizes;
import org.jpedal.examples.viewer.utils.LimitDecodeTrackerNoSwing;
import org.jpedal.examples.viewer.utils.PropertiesFile;
import org.jpedal.exception.PdfException;
import org.jpedal.external.AnnotationHandler;
import org.jpedal.external.CustomMessageHandler;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.external.ImageNameCollector;
import org.jpedal.external.OffsetOptions;
import org.jpedal.external.Options;
import org.jpedal.external.RenderChangeListener;
import org.jpedal.fonts.tt.TTGlyph;
import org.jpedal.gui.CommandWindow;
import org.jpedal.io.LimitDecodeTracker;
import org.jpedal.io.PageLabels;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.io.StatusBar;
import org.jpedal.linear.LinearThread;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.acroforms.AcroRenderer;
import org.jpedal.objects.acroforms.actions.ActionHandler;
import org.jpedal.objects.acroforms.creation.FormFactory;
import org.jpedal.objects.layers.PdfLayerList;
import org.jpedal.objects.raw.FormObject;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.parser.CommandParser;
import org.jpedal.parser.DecodeStatus;
import org.jpedal.parser.DecoderOptions;
import org.jpedal.parser.text.Tj;
import org.jpedal.render.BaseDisplay;
import org.jpedal.render.DynamicVectorRenderer;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.Messages;
import org.jpedal.utils.StringUtils;
import org.w3c.dom.Node;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.RootPaneContainer;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.AbstractBorder;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.NumberFormatter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.datatransfer.StringSelection;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URL;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <br>Description: Swing GUI functions in Viewer
*/
public class SwingGUI {
public static final int BUTTONBAR = 0;
public static final int NAVBAR = 1;
public static final int PAGES = 2;
public static final String version;
public static final int CURSOR = 1;
/**
* grabbing cursor
*/
public static final int GRAB_CURSOR = 1;
public static final int GRABBING_CURSOR = 2;
public static final int DEFAULT_CURSOR = 3;
public static final int PAN_CURSOR = 4;
public static final int PAN_CURSORL = 5;
public static final int PAN_CURSORTL = 6;
public static final int PAN_CURSORT = 7;
public static final int PAN_CURSORTR = 8;
public static final int PAN_CURSORR = 9;
public static final int PAN_CURSORBR = 10;
public static final int PAN_CURSORB = 11;
public static final int PAN_CURSORBL = 12;
/**
* Constants for glowing border
*/
private static final int glowThickness = 11;
/**
* minimum screen width to ensure menu buttons are visible
*/
private static final int minimumScreenWidth = 700;
public static boolean deletePropertiesOnExit;
public static boolean alwaysShowMouse;
/**
* control if messages appear
*/
public static boolean showMessages = true;
static int expandedSize = 190;
private static int collapsedSize = 30;
/**
* padding so that the pdf is not right at the edge
*/
private static int inset = 25;
/**
* default scaling on the combobox scalingValues
*/
private static int defaultSelection;
private static String windowTitle;
static {
final Properties props = new Properties();
try (InputStream is = SwingGUI.class.getResourceAsStream("/version.num")) {
if (is != null) {
try {
props.load(is);
} catch (final IOException ex) {
LogWriter.writeLog("Exception: " + ex.getMessage());
}
}
} catch (final IOException e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
final String versionSet = props.getProperty("release");
if (versionSet != null) {
version = versionSet;
} else {
version = "@VERSION@";
}
}
private final Color glowOuterColor = new Color(0.0f, 0.0f, 0.0f, 0.0f);
private final Color glowInnerColor = new Color(0.8f, 0.75f, 0.45f, 0.8f);
private final Values commonValues;
private final SwingThumbnailPanel thumbnails;
private final PropertiesFile properties;
private RecentDocuments recent;
/**
* listener on buttons, menus, combboxes to execute options (one instance on all objects)
*/
private SwingCommandListener currentCommandListener;
private Commands currentCommands;
//allow user to control messages in Viewer
private CustomMessageHandler customMessageHandler;
//setup in init so we can pass in some objects
private SwingMenuItems menuItems;
//layers tab
private PdfLayerList layersObject;
private boolean finishedDecoding;
private Font textFont = new Font("Serif", Font.PLAIN, 12);
//flag if generated so we setup once for each file
private boolean bookmarksGenerated;
private SwingSearchWindow searchFrame;
private String pageTitle;
private String bookmarksTitle;
private String signaturesTitle;
private String layersTitle;
private String annotationTitle;
private String attachmentsTitle;
/**
* handle for internal use
*/
private PdfDecoderInt decode_pdf;
/**
* XML structure of bookmarks
*/
private SwingOutline tree;
/**
* scaling values as floats to save conversion
*/
private float[] scalingFloatValues = {1.0f, 1.0f, 1.0f, .25f, .5f, .75f, 1.0f, 1.25f, 1.5f, 2.0f, 2.5f, 5.0f, 7.5f, 10.0f};
/**
* page scaling to use 1=100%
*/
private float scaling = 1;
/**
* store page rotation
*/
private int rotation;
/**
* scaling factors on the page
*/
private SwingCombo rotationBox;
/**
* scaling factors on the page
*/
private SwingCombo scalingBox;
private RefreshLayout viewListener;
private final Buttons swButtons = new Buttons();
//GUICursor object that holds everything to do with Cursor for SwingGUI
private final SwingCursor guiCursor = new SwingCursor();
//all mouse actions
private SwingMouseListener mouseHandler;
private Timer memoryMonitor;
private SwingScrollListener scrollListener;
//This scroll bar allows for page navigation via the scroll bar/wheel when the page
//fits within the dimensions of the viewable area
private JScrollBar thumbscroll;
//Creates the top toolbar
private final JPanel top;
private boolean sideTabBarOpenByDefault;
private String startSelectedTab = "";
//use new GUI layout
private boolean hasListener;
private boolean isSetup;
private int lastTabSelected = -1;
private boolean tabsExpanded;
private PaperSizes paperSizes;
//Multibox for new GUI Layout to contain memory, cursor and loading bars
private final JPanel multibox;
//Track whether both pages are properly displayed
private boolean pageTurnScalingAppropriate = true;
//holds back/forward buttons at bottom of page
private JToolBar navButtons;
//hold the thumbnails for display panes
private final JPanel containerForThumbnails;
// visual display of current cursor co-ords on page
private JLabel coords;
//root element to hold display
private Container frame;
//element to add portfolio display to
private Container portfolioParent;
//displayed on left to hold thumbnails, bookmarks
private JTabbedPane navOptionsPanel;
//split display between PDF and thumbnails/bookmarks
private JSplitPane displayPane;
//Scrollpane for pdf panel
private JScrollPane scrollPane;
//Interactive display object - needs to be added to PdfDecoder
private StatusBar statusBar;
private StatusBar downloadBar;
private JLabel pageCounter1;
private JTextField pageCounter2;
private JLabel pageCounter3;
private SwingSignaturesPanel signaturesTree;
private SwingLayersPanel layersPanel;
private SwingAnnotationPanel annotationsPanel;
private SwingPortfolioDetail detailView;
private SwingPortfolioTile tileView;
private SwingAttachmentsPanel attachmentsPanel;
//stop user forcing open tab before any pages loaded
private boolean tabsNotInitialised = true;
private JToolBar navToolBar;
private JToolBar pagesToolBar;
//Progress bar on nav bar
private final JProgressBar memoryBar;
//Component to display cursor position on page
private final JToolBar cursor;
private PrintPanel printPanel;
private JPanel glassPane;
private boolean searchInMenu;
private JTextField searchText;
private JToggleButton options;
private JPopupMenu menu;
private boolean cursorOverPage;
private final JLayeredPane lpane;
private Map<FormObject, String> objs;
private long start = System.currentTimeMillis();
/**
* stops autoscrolling at screen edge
*/
private boolean allowScrolling = true;
/**
* confirms exit when closing the window
*/
private boolean confirmClose;
private boolean debugMode;
private ImageNameCollector imageNameCollector = new ImageNameCollector() {};
/**
* Create the user interface for the Viewer example.
*
* @param decode_pdf the object that decodes the pdf
* @param commonValues all common values
* @param thumbnails the panel displaying the thumbnails
* @param properties all properties of the viewer
*/
public SwingGUI(final PdfDecoderInt decode_pdf, final Values commonValues, final SwingThumbnailPanel thumbnails, final PropertiesFile properties) {
this.decode_pdf = decode_pdf;
this.commonValues = commonValues;
this.thumbnails = thumbnails;
this.properties = properties;
statusBar = new StatusBar(new Color(235, 154, 0));
downloadBar = new StatusBar(new Color(185, 209, 0));
//Initialise the java components
top = new JPanel();
multibox = new JPanel();
navButtons = new JToolBar();
containerForThumbnails = new JPanel();
coords = new JLabel();
frame = new JFrame();
portfolioParent = ((RootPaneContainer) frame).getContentPane();
navOptionsPanel = new JTabbedPane();
pageCounter2 = new JTextField(4);
pageCounter3 = new JLabel();
memoryBar = new JProgressBar();
cursor = new JToolBar();
navToolBar = new JToolBar();
pagesToolBar = new JToolBar();
signaturesTree = new SwingSignaturesPanel();
layersPanel = new SwingLayersPanel();
scrollPane = new JScrollPane();
tree = new SwingOutline();
lpane = new JLayeredPane() {
@Override
public void doLayout() {
synchronized (getTreeLock()) {
final int w = getWidth();
final int h = getHeight();
for (final Component c : getComponents()) {
c.setBounds(0, 0, w, h);
}
}
}
};
setupDisplay();
}
public static int getPDFDisplayInset() {
return inset;
}
private static void setHHighlightComposite(final String propValue) {
float value = Float.parseFloat(propValue);
if (value > 1) {
value = 1;
}
if (value < 0) {
value = 0;
}
DecoderOptions.highlightComposite = value;
}
private static void getFlattenedTreeNodes(final TreeNode theNode, final List<TreeNode> items) {
// add the item
items.add(theNode);
// recursion
final int count = theNode.getChildCount();
for (int i = 0; i < count; i++) {
getFlattenedTreeNodes(theNode.getChildAt(i), items);
}
}
/**
* setup display
*/
private void setupDisplay() {
if (SwingUtilities.isEventDispatchThread()) {
setDisplayView(Display.SINGLE_PAGE, Display.DISPLAY_CENTERED);
} else {
final Runnable doPaintComponent = () -> setDisplayView(Display.SINGLE_PAGE, Display.DISPLAY_CENTERED);
try {
SwingUtilities.invokeAndWait(doPaintComponent);
} catch (InterruptedException | InvocationTargetException e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
}
//pass in SwingGUI so we can call via callback
decode_pdf.addExternalHandler(this, Options.GUIContainer);
//pass properties into Swing Menu items
menuItems = new SwingMenuItems(properties);
}
/**
* Returns the split pane used in the display area of the viewer.
*
* @return JSplitPane used to hold the page display and the side tab bar
*/
public JSplitPane getDisplayPane() {
return displayPane;
}
/**
* Returns the scroll bar used in single page mode that shows page thumbnails as you scroll
*
* @return JScrollBar used for the thumbnail scroll in single page mode
*/
public JScrollBar getThumbnailScrollBar() {
return thumbscroll;
}
/**
* Control thumbnail scroll bars visibility
*
* @param isVisible boolean value to control visibility
*/
public void setThumbnailScrollBarVisibility(final boolean isVisible) {
thumbscroll.setVisible(isVisible);
}
/**
* Set the position of the scroll bar based on desired page number
*
* @param pageNum int value for the page
*/
public void setThumbnailScrollBarValue(final int pageNum) {
thumbscroll.setValue(pageNum);
}
/**
* Gets the file path for the properties file used in the viewer.
*
* @return String containing the properties file name
*/
public String getPropertiesFileLocation() {
return properties.getConfigFile();
}
/**
* Gets the page number of the given bookmark
*
* @param bookmark String value of the bookmark
* @return String value of the page number
*/
public String getBookmark(final String bookmark) {
return tree.getPage(bookmark);
}
/**
* Set the side tab bar state and set any values required for that state.
*
* @param showVisible true to expand the side tab bar, false to collapse
*/
public void reinitialiseTabs(final boolean showVisible) {
if ("true".equalsIgnoreCase(properties.getValue("ShowSidetabbar"))) {
if (!showVisible && !"true".equalsIgnoreCase(properties.getValue("consistentTabBar"))) {
if (sideTabBarOpenByDefault) {
displayPane.setDividerLocation(expandedSize);
tabsExpanded = true;
} else {
displayPane.setDividerLocation(collapsedSize);
tabsExpanded = false;
navOptionsPanel.setSelectedIndex(-1);
}
}
lastTabSelected = -1;
if (commonValues.isPDF()) {
setupPdfDependantTabs();
}
if (tabsNotInitialised) {
navOptionsPanel.setSelectedIndex(-1);
for (int i = 0; i != navOptionsPanel.getTabCount(); i++) {
if (DecoderOptions.isRunningOnMac) {
if (navOptionsPanel.getTitleAt(i).equals(startSelectedTab)) {
navOptionsPanel.setSelectedIndex(i);
break;
}
} else {
if (navOptionsPanel.getIconAt(i).toString().equals(startSelectedTab)) {
navOptionsPanel.setSelectedIndex(i);
break;
}
}
}
}
}
}
private void setupPdfDependantTabs() {
//add/remove optional tabs
if (!decode_pdf.hasOutline()) {
final int outlineTab = getTabIndex(bookmarksTitle);
if (outlineTab != -1) {
navOptionsPanel.remove(outlineTab);
}
} else if ("true".equalsIgnoreCase(properties.getValue("Bookmarkstab"))) {
final int outlineTab = getTabIndex(bookmarksTitle);
if (outlineTab == -1) {
if (DecoderOptions.isRunningOnMac && UIManager.getLookAndFeel().isNativeLookAndFeel()) {
navOptionsPanel.addTab(bookmarksTitle, tree);
} else {
final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, bookmarksTitle);
navOptionsPanel.addTab(null, textIcon2, tree);
}
}
}
//handle signatures pane
final AcroRenderer currentFormRenderer = decode_pdf.getFormRenderer();
Iterator<FormObject> signatureObjects = null;
if (currentFormRenderer != null) {
signatureObjects = currentFormRenderer.getSignatureObjects();
}
if (signatureObjects != null) {
signaturesTree.reinitialise(decode_pdf, signatureObjects);
checkTabShown(signaturesTitle);
} else {
removeTab(signaturesTitle);
}
//add a control Panel to enable/disable layers
layersObject = (PdfLayerList) decode_pdf.getJPedalObject(PdfDictionary.Layer);
if (layersObject != null && layersObject.getLayersCount() > 0) { //some files have empty Layers objects
checkTabShown(layersTitle);
layersPanel.reinitialise(layersObject, decode_pdf, scrollPane, commonValues.getCurrentPage());
} else {
removeTab(layersTitle);
}
final PdfObjectReader reader = decode_pdf.getIO();
Object[] embeddedFiles = null;
if (reader != null) {
if (reader.getNamesLookup() != null) {
embeddedFiles = reader.getNamesLookup().getEmbeddedFiles();
}
if (attachmentsPanel == null) {
attachmentsPanel = new SwingAttachmentsPanel(this);
}
//Always load values even when null as this method also loads values stored in annotations
if (attachmentsPanel.loadEmbeddedFileData(decode_pdf, embeddedFiles)) {
checkTabShown(attachmentsTitle);
} else {
removeTab(attachmentsTitle);
}
}
if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE && !decode_pdf.isEncrypted()) {
checkTabShown(annotationTitle);
} else {
removeTab(annotationTitle);
}
setBookmarks(false);
}
private int getTabIndex(final String title) {
int tabIndex = -1;
if (DecoderOptions.isRunningOnMac) {
//see if there is an outlines tab
for (int jj = 0; jj < navOptionsPanel.getTabCount(); jj++) {
if (navOptionsPanel.getTitleAt(jj).equals(title)) {
tabIndex = jj;
}
}
} else {
//see if there is an outlines tab
for (int jj = 0; jj < navOptionsPanel.getTabCount(); jj++) {
if (navOptionsPanel.getIconAt(jj).toString().equals(title)) {
tabIndex = jj;
}
}
}
return tabIndex;
}
private void checkTabShown(final String title) {
final int outlineTab = getTabIndex(title);
if (outlineTab == -1) {
if (DecoderOptions.isRunningOnMac && UIManager.getLookAndFeel().isNativeLookAndFeel()) {
if (title.equals(signaturesTitle) && "true".equalsIgnoreCase(properties.getValue("Signaturestab"))) {
navOptionsPanel.addTab(signaturesTitle, signaturesTree);
navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() - 1, signaturesTitle);
} else if (title.equals(layersTitle) && "true".equalsIgnoreCase(properties.getValue("Layerstab"))) {
final JScrollPane layerScrollPane = new JScrollPane();
layerScrollPane.getViewport().add(layersPanel);
layerScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
layerScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
navOptionsPanel.addTab(layersTitle, layerScrollPane);
navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() - 1, layersTitle);
} else if (title.equals(annotationTitle) && "true".equalsIgnoreCase(properties.getValue("AnnotationTab")) && SwingAnnotationPanel.addPanel()) {
navOptionsPanel.addTab(annotationTitle, annotationsPanel.getDisplayPanel());
navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() - 1, annotationTitle);
} else if (title.equals(attachmentsTitle) && "true".equalsIgnoreCase(properties.getValue("AttachmentsTab"))) {
navOptionsPanel.addTab(attachmentsTitle, attachmentsPanel);
navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() - 1, attachmentsTitle);
}
} else {
if (title.equals(signaturesTitle) && "true".equalsIgnoreCase(properties.getValue("Signaturestab"))) { //stop spurious display of Sig tab
final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, signaturesTitle);
navOptionsPanel.addTab(null, textIcon2, signaturesTree);
} else if (title.equals(layersTitle) && "true".equalsIgnoreCase(properties.getValue("Layerstab"))) {
final VTextIcon textIcon = new VTextIcon(navOptionsPanel, layersTitle);
final JScrollPane scrollPane = new JScrollPane();
scrollPane.getViewport().add(layersPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
navOptionsPanel.addTab(null, textIcon, scrollPane);
} else if (title.equals(annotationTitle) && "true".equalsIgnoreCase(properties.getValue("AnnotationTab")) && SwingAnnotationPanel.addPanel()) {
final VTextIcon textIcon = new VTextIcon(navOptionsPanel, annotationTitle);
navOptionsPanel.addTab(null, textIcon, annotationsPanel.getDisplayPanel());
} else if (title.equals(attachmentsTitle) && "true".equalsIgnoreCase(properties.getValue("AttachmentsTab"))) {
final VTextIcon textIcon = new VTextIcon(navOptionsPanel, attachmentsTitle);
navOptionsPanel.addTab(null, textIcon, attachmentsPanel);
}
}
}
}
private void removeTab(final String title) {
final int outlineTab = getTabIndex(title);
if (outlineTab != -1) {
navOptionsPanel.remove(outlineTab);
}
}
/**
* Stop thumbnails from being generated for the side tab bar
*/
public void stopThumbnails() {
if (thumbnails.isShownOnscreen()) {
//if running terminate first
thumbnails.terminateDrawing();
thumbnails.removeAllListeners();
}
}
/**
* Flag the thumbnails tab as requires reinitialisation
*/
public void reinitThumbnails() {
isSetup = false;
}
/**
* Reset the nav bar and collapse side tab bar
*/
public void resetNavBar() {
if (!"true".equalsIgnoreCase(properties.getValue("consistentTabBar"))) {
displayPane.setDividerLocation(collapsedSize);
navOptionsPanel.setSelectedIndex(-1);
tabsNotInitialised = true;
}
//also reset layers
layersPanel.resetLayers();
//disable page view buttons until we know we have multiple pages
swButtons.setPageLayoutButtonsEnabled(false);
}
/*
* Called when new file opened so we set flags here
*/
public void setNoPagesDecoded() {
bookmarksGenerated = false;
resetNavBar();
//Ensure preview from last file doesn't appear
if (scrollListener != null) {
scrollListener.lastImage = null;
}
}
/**
* Gets the thumbnail panel.
*
* @return SwingThumbnailPanel instance
*/
public SwingThumbnailPanel getThumbnailPanel() {
return thumbnails;
}
/**
* Gets the SwingOutline used for the outline panel
*
* @return SwingOutline
*/
public SwingOutline getOutlinePanel() {
return tree;
}
/**
* Gets the current vertical scroll bar. This will be the thumbnail scroll bar
* if it is currently present, otherwise it will be the scrollpanes scroll bar.
*
* @return a JScrollBar representing the scroll bar
*/
public JScrollBar getVerticalScrollBar() {
if (scrollPane.getVerticalScrollBar().isVisible()) {
return scrollPane.getVerticalScrollBar();
} else {
return thumbscroll;
}
}
/**
* Sets the scroll bar policy for the display areas scroll pane
*
* @param pol ScrollPolicy to be applied to the scroll pane
*/
public void setScrollBarPolicy(final ScrollPolicy pol) {
switch (pol) {
case VERTICAL_NEVER:
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
break;
case VERTICAL_AS_NEEDED:
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
break;
case HORIZONTAL_NEVER:
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
break;
case HORIZONTAL_AS_NEEDED:
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
break;
}
}
/**
* Specify a Container for the viewers interface to be added to.
*
* @param rawValue an Object that extends container to add the user interface to.
*/
public void setRootContainer(final Object rawValue) {
if (rawValue == null) {
throw new RuntimeException("Null containers not allowed.");
}
final Container rootContainer = (Container) rawValue;
Container c = rootContainer;
if ((rootContainer instanceof JTabbedPane)) {
final JPanel temp = new JPanel(new BorderLayout());
rootContainer.add(temp);
c = temp;
} else if (rootContainer instanceof JScrollPane) {
final JPanel temp = new JPanel(new BorderLayout());
((JScrollPane) rootContainer).getViewport().add(temp);
c = temp;
} else if (rootContainer instanceof JSplitPane) {
throw new RuntimeException("To add the viewer to a split pane please pass through either JSplitPane.getLeftComponent() or JSplitPane.getRightComponent()");
}
if (rootContainer instanceof JFrame) {
portfolioParent = ((RootPaneContainer) rootContainer).getContentPane();
} else {
c.setLayout(new BorderLayout());
portfolioParent = c;
}
//Load width and height from properties file
int width = Integer.parseInt(properties.getValue("startViewerWidth"));
int height = Integer.parseInt(properties.getValue("startViewerHeight"));
//Used to prevent infinite scroll issue as a preferred size has been set
final Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
if (width < 0) {
width = d.width / 2;
if (width < 700) {
width = 700;
}
properties.setValue("startViewerWidth", String.valueOf(width));
}
if (height < 0) {
height = d.height / 2;
properties.setValue("startViewerHeight", String.valueOf(height));
}
//allow user to alter size
final String customWindowSize = System.getProperty("org.jpedal.startWindowSize");
if (customWindowSize != null) {
final StringTokenizer values = new StringTokenizer(customWindowSize, "x");
if (values.countTokens() != 2) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300");
}
try {
width = Integer.parseInt(values.nextToken().trim());
height = Integer.parseInt(values.nextToken().trim());
} catch (final NumberFormatException ee) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300 " + ee);
}
}
c.setPreferredSize(new Dimension(width, height));
frame = c;
}
public void resetRotationBox() {
final PdfPageData currentPageData = decode_pdf.getPdfPageData();
if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
rotation = currentPageData.getRotation(commonValues.getCurrentPage());
}
if (getSelectedComboIndex(Commands.ROTATION) != (rotation / 90)) {
setSelectedComboIndex(Commands.ROTATION, (rotation / 90));
} else if (!Values.isProcessing()) {
decode_pdf.repaint();
}
}
public PropertiesFile getProperties() {
return properties;
}
/**
* Set Search Bar to be in the Left hand Tabbed pane
*
* @param searchFrame the search window that will be add to the side tab bar
*/
public void searchInTab(final SwingSearchWindow searchFrame) {
this.searchFrame = searchFrame;
this.searchFrame.init(decode_pdf, commonValues);
if (DecoderOptions.isRunningOnMac && UIManager.getLookAndFeel().isNativeLookAndFeel()) {
if (thumbnails.isShownOnscreen()) {
navOptionsPanel.addTab("Search", searchFrame.getContentPane());
}
} else {
final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, "Search");
navOptionsPanel.addTab(null, textIcon2, searchFrame.getContentPane());
}
//Create menu bar text field to trigger side tab bar
final JTextField searchTextLocal = new JTextField();
searchTextLocal.setColumns(searchText.getColumns());
searchTextLocal.setText(searchText.getText());
//Get last listener as all listeners added to the end of the array
searchTextLocal.addKeyListener(searchText.getKeyListeners()[searchText.getKeyListeners().length - 1]);
searchTextLocal.addFocusListener(searchText.getFocusListeners()[searchText.getFocusListeners().length - 1]);
searchTextLocal.addActionListener(e -> {
navOptionsPanel.setSelectedComponent(searchFrame.getContentPane());
if (!tabsExpanded) {
displayPane.setDividerLocation(expandedSize);
tabsExpanded = true;
thumbnails.setIsDisplayedOnscreen(false);
}
searchText.setText(searchTextLocal.getText());
});
searchText.addActionListener(e -> searchTextLocal.setText(searchText.getText()));
swButtons.getTopButtons().add(searchTextLocal);
}
private JToggleButton createMenuBarSearchOptions() {
if (options == null) {
options = new JToggleButton(new ImageIcon(guiCursor.getURLForImage("menuSearchOptions.png")));
menu = new JPopupMenu();
options.setBorder(null);
options.setName("SEARCHOPTIONS");
options.addItemListener(e -> {
if (e.getStateChange() == ItemEvent.SELECTED) {
menu.show(((Component) e.getSource()), 0, ((Component) e.getSource()).getHeight());
}
});
options.setFocusable(false);
options.setToolTipText(Messages.getMessage("PdfViewerSearch.Options"));
final JCheckBoxMenuItem wholeWords = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.WholeWords"));
wholeWords.setToolTipText(Messages.getMessage("PdfViewerSearch.WholeWordsTooltip"));
wholeWords.addActionListener(e -> {
searchFrame.setWholeWords(((AbstractButton) e.getSource()).isSelected());
enableSearchItems(true);
});
final JCheckBoxMenuItem caseSense = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.CaseSense"));
caseSense.setToolTipText(Messages.getMessage("PdfViewerSearch.CaseSenseTooltip"));
caseSense.addActionListener(e -> {
searchFrame.setCaseSensitive(((AbstractButton) e.getSource()).isSelected());
enableSearchItems(true);
});
final JCheckBoxMenuItem multiLine = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.MultiLine"));
multiLine.setToolTipText(Messages.getMessage("PdfViewerSearch.MultiLineTooltip"));
multiLine.addActionListener(e -> {
searchFrame.setMultiLine(((AbstractButton) e.getSource()).isSelected());
enableSearchItems(true);
});
final JCheckBoxMenuItem ignoreSpaces = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.IgnoreSpaces"));
ignoreSpaces.setToolTipText(Messages.getMessage("PdfViewerSearch.IgnoreSpacesTooltip"));
ignoreSpaces.addActionListener(e -> {
searchFrame.setIgnoreSpaces(((AbstractButton) e.getSource()).isSelected());
enableSearchItems(true);
});
menu.add(wholeWords);
menu.add(caseSense);
menu.add(multiLine);
menu.add(ignoreSpaces);
menu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(final PopupMenuEvent e) {
//We do not need to perform an action before making popup visible
}
@Override
public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) {
options.setSelected(false);
}
@Override
public void popupMenuCanceled(final PopupMenuEvent e) {
options.setSelected(false);
}
});
}
return options;
}
/*
* Set Search Bar to be in the Top Button Bar
*/
private void searchInMenu(final SwingSearchWindow searchFrame) {
this.searchFrame = searchFrame;
searchInMenu = true;
searchFrame.find(decode_pdf, commonValues);
swButtons.getTopButtons().add(searchText);
swButtons.getTopButtons().add(createMenuBarSearchOptions());
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerSearch.Previous"), "search_previous.gif", Commands.PREVIOUSRESULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerSearch.Next"), "search_next.gif", Commands.NEXTRESULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.getButton(Commands.NEXTRESULT).setEnabled(false);
swButtons.getButton(Commands.PREVIOUSRESULT).setEnabled(false);
swButtons.getButton(Commands.NEXTRESULT).setVisible(true);
swButtons.getButton(Commands.PREVIOUSRESULT).setVisible(true);
}
/**
* Sets the properties file to be used
*
* @param file String file name for the properties file to be used
*/
public void setPropertiesFileLocation(final String file) {
properties.loadProperties(file);
}
/**
* Gets the Commands object used by the user interface
*
* @return Commands object for executing commands
*/
public Commands getCommand() {
return currentCommands;
}
/**
* Gets the annotation tabs panel if one is present
*
* @return an implementation of SwingAnnotationPanel
*/
public SwingAnnotationPanel getAnnotationPanel() {
return annotationsPanel;
}
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
public void init(final Commands currentCommands) {
//single listener to execute all commands
currentCommandListener = new SwingCommandListener(currentCommands);
//setup custom message and switch off error messages if used
customMessageHandler = (CustomMessageHandler) (decode_pdf.getExternalHandler(Options.CustomMessageOutput));
if (customMessageHandler != null) {
DecoderOptions.showErrorMessages = false;
showMessages = false;
}
this.currentCommands = currentCommands;
initProperties();
annotationsPanel = new SwingAnnotationPanel(this);
/*
* arrange insets
*/
decode_pdf.setInset(inset, inset);
setViewerTitle();
setViewerIcon();
setDefaultPdfDecoderParameters();
//Add Background color to the panel to help break up view.
setupCenterPanelBackground();
//setup combo boxes.
setupComboBoxes();
if (LogWriter.isRunningFromIDE) {
nameElements();
}
//add the pdf display to show page.
setupPDFDisplayPane();
//add the pdf display left and right panes.
setupBorderPanes();
//Initialise the Swing Buttons
swButtons.init(true);
//create a menu bar and add to display
createTopMenuBar();
//set colours on display boxes and add listener to page number
setupBottomToolBarItems();
//create other tool bars and add to display
createOtherToolBars();
initButtonsAndMenu();
//navigation toolbar for moving between pages
createNavbar();
//add cursor location
initCoordBox();
if (searchFrame != null && searchFrame.getViewStyle() == SwingSearchWindow.SEARCH_MENU_BAR) {
searchInMenu(searchFrame);
}
//status object on toolbar showing 0 -100 % completion
initStatus();
//Ensure all gui sections are displayed correctly
//Issues found when removing some sections
frame.invalidate();
frame.validate();
frame.repaint();
//Load properties
GUIModifier.load(properties, this);
initViewerWindow();
redrawDocumentOnResize();
setupPDFBorder();
//Set side tab bar state at start up
if (sideTabBarOpenByDefault) {
displayPane.setDividerLocation(expandedSize);
tabsExpanded = true;
} else {
displayPane.setDividerLocation(collapsedSize);
tabsExpanded = false;
navOptionsPanel.setSelectedIndex(-1);
}
mouseHandler = new SwingMouseListener((PdfDecoder) decode_pdf, this, commonValues, currentCommands);
mouseHandler.setupMouse();
final long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
//Add universal listener to catch coords updating regardless of form component
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
//Required to prevent recursive calling of listener
boolean listenerCalled;
@Override
public void eventDispatched(final AWTEvent e) {
if (decode_pdf != null && !listenerCalled && e.getID() == MouseEvent.MOUSE_MOVED) {
listenerCalled = true;
Point mousePosition = ((Component) decode_pdf).getMousePosition();
if ((annotationsPanel != null && SwingAnnotationPanel.addPanel()) && glassPane != null) {
mousePosition = glassPane.getMousePosition();
}
if (mousePosition != null) {
mouseHandler.allowMouseCoordsUpdate();
((Component) decode_pdf).dispatchEvent(new MouseEvent(((Component) decode_pdf),
e.getID(),
System.currentTimeMillis(),
0,
mousePosition.x,
mousePosition.y,
0,
false));
}
listenerCalled = false;
}
}
}, eventMask);
if (LogWriter.isRunningFromIDE && !debugMode) {
final LimitDecodeTracker decodeLimiter = new LimitDecodeTracker(menuItems, (PdfDecoder) decode_pdf);
decode_pdf.addExternalHandler(decodeLimiter, Options.ErrorTracker);
}
}
private void setDefaultPdfDecoderParameters() {
final boolean separateCoverOn = "true".equalsIgnoreCase(properties.getValue("separateCoverOn"));
decode_pdf.getPages().setBoolean(Display.BoolValue.SEPARATE_COVER, separateCoverOn);
final boolean showFormFieldHighlights = "true".equalsIgnoreCase(properties.getValue("highlightFormFields"));
final int formFieldHighlightColor = Integer.parseInt(properties.getValue("formFieldsHighlightColor"));
final boolean useOffScreenRendering = "true".equalsIgnoreCase(properties.getValue("useOffScreenRendering"));
final boolean fullOffScreenRendering = "true".equalsIgnoreCase(properties.getValue("fullOffScreenRendering"));
final Map<Integer, Object> map = new HashMap<>();
map.put(JPedalSettings.HIGHLIGHT_FORM_FIELDS, showFormFieldHighlights);
map.put(JPedalSettings.HIGHLIGHT_FORM_FIELDS_COLOR, formFieldHighlightColor);
map.put(JPedalSettings.OFF_SCREEN_RENDERING, useOffScreenRendering);
map.put(JPedalSettings.FULL_OFF_SCREEN_RENDERING, fullOffScreenRendering);
try {
decode_pdf.modifyNonstaticJPedalParameters(map);
} catch (final PdfException e) {
LogWriter.writeLog("Error setting values from properties " + e);
}
}
private void initViewerWindow() {
//Load width and height from properties file
int width = Integer.parseInt(properties.getValue("startViewerWidth"));
int height = Integer.parseInt(properties.getValue("startViewerHeight"));
//Used to prevent infinite scroll issue as a preferred size has been set
final Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
if (width < 0) {
width = d.width / 2;
if (width < minimumScreenWidth) {
width = minimumScreenWidth;
}
properties.setValue("startViewerWidth", String.valueOf(width));
}
if (height < 0) {
height = d.height / 2;
properties.setValue("startViewerHeight", String.valueOf(height));
}
//allow user to alter size
final String customWindowSize = System.getProperty("org.jpedal.startWindowSize");
if (customWindowSize != null) {
final StringTokenizer values = new StringTokenizer(customWindowSize, "x");
if (values.countTokens() != 2) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300");
}
try {
width = Integer.parseInt(values.nextToken().trim());
height = Integer.parseInt(values.nextToken().trim());
} catch (final NumberFormatException ee) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300 " + ee);
}
}
createMainViewerWindow(width, height);
}
private void initButtonsAndMenu() {
//Menu bar for using the majority of functions
menuItems.createMainMenu(true, currentCommandListener, currentCommands, swButtons);
//sets up all the toolbar items
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.openFile"), "open.gif", Commands.OPENFILE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.saveFile"), "save.gif", Commands.SAVE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.print"), "print.gif", Commands.PRINT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
if (searchFrame != null && (searchFrame.getViewStyle() == SwingSearchWindow.SEARCH_EXTERNAL_WINDOW)) {
searchFrame.setViewStyle(SwingSearchWindow.SEARCH_EXTERNAL_WINDOW);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.search"), "find.gif", Commands.FIND, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
}
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.properties"), "properties.gif", Commands.DOCINFO, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
//snapshot screen function
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.snapshot"), "snapshot.gif", Commands.SNAPSHOT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.minimise"), "minimise.gif", Commands.ZOOMOUT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.zoom"), "zoom.gif", Commands.ZOOMIN, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
final JSeparator sep = new JSeparator(SwingConstants.VERTICAL);
sep.setPreferredSize(new Dimension(5, 32));
swButtons.getTopButtons().add(sep);
//combo boxes on toolbar
addCombo(Messages.getMessage("PdfViewerToolbarTooltip.zoomin"), Commands.SCALING);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.rotateLeft"), "rotateLeft.gif", Commands.ROTATELEFT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.rotateRight"), "rotateRight.gif", Commands.ROTATERIGHT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
addCombo(Messages.getMessage("PdfViewerToolbarTooltip.rotation"), Commands.ROTATION);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.mouseMode"), "mouse_select.png", Commands.MOUSEMODE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
final JSeparator sep2 = new JSeparator(SwingConstants.VERTICAL);
sep2.setPreferredSize(new Dimension(5, 32));
swButtons.getTopButtons().add(sep2);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.help"), "help.png", Commands.HELP, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.openSystemDefault"), "openSystem.png", Commands.OPENINSYSTEMDEFAULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
}
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
private void initProperties() {
String propValue = properties.getValue("pageInsets");
if (!propValue.isEmpty()) {
inset = Integer.parseInt(propValue);
}
propValue = properties.getValue("changeTextAndLineart");
if (!propValue.isEmpty()
&& "true".equalsIgnoreCase(propValue)) {
currentCommands.executeCommand(ViewerCommands.CHANGELINEART, new Object[]{Boolean.parseBoolean(propValue)});
}
propValue = properties.getValue("windowTitle");
if (!propValue.isEmpty()) {
windowTitle = propValue;
} else {
windowTitle = Messages.getMessage("PdfViewer.titlebar") + ' ' + version;
}
propValue = properties.getValue("vbgColor");
if (!propValue.isEmpty()) {
currentCommands.executeCommand(ViewerCommands.SETPAGECOLOR, new Object[]{Integer.parseInt(propValue)});
}
propValue = properties.getValue("replaceDocumentTextColors");
if (!propValue.isEmpty()
&& "true".equalsIgnoreCase(propValue)) {
propValue = properties.getValue("vfgColor");
if (!propValue.isEmpty()) {
currentCommands.executeCommand(ViewerCommands.SETTEXTCOLOR, new Object[]{Integer.parseInt(propValue)});
}
}
propValue = properties.getValue("TextColorThreshold");
if (!propValue.isEmpty()) {
currentCommands.executeCommand(ViewerCommands.SETREPLACEMENTCOLORTHRESHOLD, new Object[]{Integer.parseInt(propValue)});
}
propValue = properties.getValue("enhanceFractionalLines");
if (!propValue.isEmpty()) {
currentCommands.executeCommand(ViewerCommands.SETENHANCEFRACTIONALLINES, new Object[]{Boolean.parseBoolean(propValue)});
}
propValue = properties.getValue("hideLineWeights");
if (!propValue.isEmpty()) {
currentCommands.executeCommand(ViewerCommands.SETHIDELINEWEIGHTS, new Object[]{Boolean.parseBoolean(propValue)});
}
//Set autoScroll default and add to properties file
propValue = properties.getValue("autoScroll");
if (!propValue.isEmpty()) {
allowScrolling = Boolean.parseBoolean(propValue);
}
//set confirmClose
propValue = properties.getValue("confirmClose");
if (!propValue.isEmpty()) {
confirmClose = "true".equals(propValue);
}
//Dpi is taken into effect when zoom is called
propValue = properties.getValue("resolution");
if (!propValue.isEmpty()) {
setDpi(Integer.parseInt(propValue));
}
//Ensure valid value if not recognised
propValue = properties.getValue("startView");
if (!propValue.isEmpty()) {
int pageMode = Integer.parseInt(propValue);
if (pageMode < Display.SINGLE_PAGE || pageMode > Display.PAGEFLOW) {
pageMode = Display.SINGLE_PAGE;
}
//Default Page Layout
decode_pdf.setPageMode(pageMode);
}
final String val = properties.getValue("highlightBoxColor"); //empty string to old users
if (!val.isEmpty()) {
DecoderOptions.highlightColor = new Color(Integer.parseInt(val));
}
propValue = properties.getValue("useSmoothImage");
if (!propValue.isEmpty()) {
final HashMap<Integer, Object> map = new HashMap<>();
map.put(JPedalSettings.SMOOTH_IMAGES, Boolean.valueOf(propValue));
try {
decode_pdf.modifyNonstaticJPedalParameters(map);
} catch (final PdfException e) {
LogWriter.writeLog(e);
}
}
propValue = properties.getValue("highlightTextColor");
if (!propValue.isEmpty()) {
DecoderOptions.backgroundColor = new Color(Integer.parseInt(propValue));
}
propValue = properties.getValue("showMouseSelectionBox");
if (!propValue.isEmpty()) {
DecoderOptions.showMouseBox = Boolean.parseBoolean(propValue);
}
propValue = properties.getValue("enhancedViewerMode");
if (!propValue.isEmpty()) {
decode_pdf.useNewGraphicsMode(Boolean.parseBoolean(propValue));
}
propValue = properties.getValue("highlightComposite");
if (!propValue.isEmpty()) {
setHHighlightComposite(propValue);
}
//Set border config value and repaint
propValue = properties.getValue("borderType");
if (!propValue.isEmpty()) {
decode_pdf.getPages().setBorderPresent(Integer.parseInt(propValue) == 1);
}
//Allow cursor to change
propValue = properties.getValue("allowCursorToChange");
if (!propValue.isEmpty()) {
GUIDisplay.allowChangeCursor = "true".equalsIgnoreCase(propValue);
}
propValue = properties.getValue("invertHighlights");
if (!propValue.isEmpty()) {
BaseDisplay.invertHighlight = Boolean.parseBoolean(propValue);
}
propValue = properties.getValue("enhancedFacingMode");
if (!propValue.isEmpty()) {
GUIDisplay.default_turnoverOn = Boolean.parseBoolean(propValue);
}
//Set whether to use hinting
propValue = properties.getValue("useHinting");
final String propValue2 = System.getProperty("org.jpedal.useTTFontHinting");
//check JVM flag first
if (propValue2 != null) {
//check if properties file conflicts
if (!propValue.isEmpty() && !propValue2.equalsIgnoreCase(propValue)) {
JOptionPane.showMessageDialog(null, Messages.getMessage("PdfCustomGui.hintingFlagFileConflict"));
}
TTGlyph.useHinting = "true".equalsIgnoreCase(propValue2);
//check properties file
} else {
TTGlyph.useHinting = !propValue.isEmpty() && "true".equalsIgnoreCase(propValue);
}
//Set icon location
propValue = properties.getValue("iconLocation");
if (!propValue.isEmpty()) {
guiCursor.setIconLocation(propValue);
}
}
private void nameElements() {
menuItems.getCurrentMenu().setName("menuBar");
frame.setName("frame");
pageCounter2.setName("pageCounter");
rotationBox.setName("rotationBox");
scalingBox.setName("scalingBox");
}
/**
* method being called from within init to create other tool bars to add to
* display
*/
private void createOtherToolBars() {
//setup top main menu toolbar and create options
top.add(menuItems.getCurrentMenu(), BorderLayout.NORTH);
//This is where we add the Buttons for the top ToolBar
top.add(swButtons.getTopButtons(), BorderLayout.CENTER);
//This is where we add the Buttons for the bottom ToolBar
if (frame instanceof JFrame) {
((RootPaneContainer) frame).getContentPane().add(navButtons, BorderLayout.SOUTH);
} else {
frame.add(navButtons, BorderLayout.SOUTH);
}
//This is where we add the display pane to the center of the viewer
if (frame instanceof JFrame) {
((RootPaneContainer) frame).getContentPane().add(displayPane, BorderLayout.CENTER);
} else {
frame.add(displayPane, BorderLayout.CENTER);
}
}
private void handleTabbedPanes() {
if (tabsNotInitialised) {
return;
}
//expand size if not already at size
final int tabSelected = navOptionsPanel.getSelectedIndex();
if (tabSelected == -1) {
return;
}
if (!tabsExpanded) {
//workout selected tab
final String tabName;
if (DecoderOptions.isRunningOnMac) {
tabName = navOptionsPanel.getTitleAt(tabSelected);
} else {
tabName = navOptionsPanel.getIconAt(tabSelected).toString();
}
thumbnails.setIsDisplayedOnscreen(tabName.equals(pageTitle));
if (tabName.equals(annotationTitle)) {
if (decode_pdf.isEncrypted()) {
showMessageDialog((Messages.getMessage("PdfViewerMessage.NewAnnotInEncryptedFile")), Messages.getMessage("PdfViewerGeneral.Warning"), JOptionPane.WARNING_MESSAGE);
}
annotationsPanel.populateList(decode_pdf);
}
displayPane.setDividerLocation(expandedSize);
tabsExpanded = true;
} else if (lastTabSelected == tabSelected) {
displayPane.setDividerLocation(collapsedSize);
tabsExpanded = false;
thumbnails.setIsDisplayedOnscreen(false);
navOptionsPanel.setSelectedIndex(-1);
}
lastTabSelected = tabSelected;
}
/**
* Not part of API - used internally
* <p>
* Set the state and value for the multi box at the bottom left of the user interface.
*
* @param flags an int[] used to control multi box display
*/
public void setMultibox(final int[] flags) {
//debug code for formclicktests
if (alwaysShowMouse) {
multibox.removeAll();
multibox.add(coords, BorderLayout.CENTER);
multibox.repaint();
return;
}
//deal with flags
if (flags.length > 1 && flags[0] == CURSOR) {
//if no change, return
if (cursorOverPage != (flags[1] == 1)) {
cursorOverPage = flags[1] == 1;
} else {
return;
}
}
//LOAD_PROGRESS:
if (statusBar.isEnabled() && statusBar.isVisible() && !statusBar.isDone()) {
multibox.removeAll();
statusBar.getStatusObject().setSize(multibox.getSize());
multibox.add(statusBar.getStatusObject(), BorderLayout.CENTER);
multibox.repaint();
return;
}
//CURSOR:
if (cursor.isEnabled() && cursor.isVisible() && cursorOverPage && decode_pdf.isOpen()) {
multibox.removeAll();
multibox.add(coords, BorderLayout.CENTER);
multibox.repaint();
return;
}
//DOWNLOAD_PROGRESS:
if (downloadBar.isEnabled() && downloadBar.isVisible() && !downloadBar.isDone() && (decode_pdf.isLoadingLinearizedPDF() || !decode_pdf.isOpen())) {
multibox.removeAll();
downloadBar.getStatusObject().setSize(multibox.getSize());
multibox.add(downloadBar.getStatusObject(), BorderLayout.CENTER);
multibox.repaint();
return;
}
//MEMORY:
if (memoryBar.isEnabled() && memoryBar.isVisible()) {
multibox.removeAll();
memoryBar.setSize(multibox.getSize());
memoryBar.setForeground(new Color(125, 145, 255));
multibox.add(memoryBar, BorderLayout.CENTER);
multibox.repaint();
}
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setTitle(final String title) {
if (frame instanceof JFrame) {
((Frame) frame).setTitle(title);
}
}
public void resetComboBoxes(final boolean value) {
scalingBox.setEnabled(value);
rotationBox.setEnabled(value);
}
public SwingCombo getCombo(final int ID) {
switch (ID) {
case Commands.SCALING:
return scalingBox;
case Commands.ROTATION:
return rotationBox;
}
return null;
}
/**
* All scaling and rotation should go through this.
*/
public void scaleAndRotate() {
if (decode_pdf != null) {
if (decode_pdf.getDisplayView() == Display.PAGEFLOW) {
decode_pdf.setPageParameters(scaling, commonValues.getCurrentPage(), rotation);
return;
}
//ignore if called too early
if (!decode_pdf.isOpen() && OpenFile.isPDf) {
return;
}
}
// [AWI]: Get the values of all of the border insets around the scrollpane
Insets borderInsets = new Insets(0, 0, 0, 0);
if (scrollPane.getBorder() != null && scrollPane.getBorder().getBorderInsets(scrollPane) != null) {
borderInsets = scrollPane.getBorder().getBorderInsets(scrollPane);
}
float width = scrollPane.getWidth() - inset - inset - borderInsets.left - borderInsets.right;
final float height = scrollPane.getHeight() - inset - inset - borderInsets.top - borderInsets.bottom;
if (decode_pdf != null) {
int index = getSelectedComboIndex(Commands.SCALING);
if (decode_pdf.getDisplayView() == Display.PAGEFLOW) {
//Ensure we only display in window mode
setSelectedComboIndex(Commands.SCALING, 0);
index = 0;
//Disable scaling option
scalingBox.setEnabled(false);
} else if (decode_pdf.getDisplayView() != Display.PAGEFLOW) {
//No long pageFlow. enable scaling option
scalingBox.setEnabled(true);
}
if (index == -1) {
final float zoom = getScalingFromString((String) getSelectedComboItem(Commands.SCALING));
//if nothing off either attempt, use window value
if (zoom == -1) {
//its not set so use To window value
index = defaultSelection;
setSelectedComboIndex(Commands.SCALING, index);
} else {
scaling = decode_pdf.getDPIFactory().adjustScaling(zoom / 100);
setSelectedComboItem(Commands.SCALING, String.valueOf(zoom));
}
}
int page = commonValues.getCurrentPage();
//Multipage tiff should be treated as a single page
if (commonValues.isMultiTiff()) {
page = 1;
}
//always check in facing mode with turnover on
if (index != -1 || decode_pdf.getDisplayView() == Display.SINGLE_PAGE || (decode_pdf.getDisplayView() == Display.FACING && decode_pdf.getPages().getBoolean(Display.BoolValue.TURNOVER_ON))) {
final Dimension contentSize = getContentDimensions(page);
if (displayPane != null) {
width -= displayPane.getDividerSize();
}
setupScalingValue(index, width, height, contentSize.width, contentSize.height);
}
//allow for clicking on it before page opened
decode_pdf.setPageParameters(scaling, page, rotation);
//Ensure the page is displayed in the correct rotation
setRotation();
}
if (LogWriter.isRunningFromIDE) {
System.out.println("Memory usage after zoom=" + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1_000);
}
//Update annotation selection position if required
annotationsPanel.getAnnotationListener().updateSelectionPosition();
}
private Dimension getContentDimensions(final int page) {
final Dimension dimensions = new Dimension();
final PdfPageData pageData = decode_pdf.getPdfPageData();
final int raw_rotation;
if (decode_pdf.getDisplayView() == Display.FACING) {
raw_rotation = pageData.getRotation(page);
} else {
raw_rotation = 0;
}
final boolean isRotated = (rotation + raw_rotation) % 180 == 90;
final PageOffsets offsets = (PageOffsets) decode_pdf.getExternalHandler(Options.CurrentOffset);
switch (decode_pdf.getDisplayView()) {
case Display.CONTINUOUS_FACING:
handleContinuousModes(dimensions, isRotated, offsets, offsets.getMaxH() * 2, offsets.getMaxW() * 2);
break;
case Display.CONTINUOUS:
handleContinuousModes(dimensions, isRotated, offsets, offsets.getMaxH(), offsets.getMaxW());
break;
case Display.FACING:
handleFacing(page, dimensions, pageData, isRotated, decode_pdf, commonValues);
break;
default:
if (isRotated) {
dimensions.width = pageData.getCropBoxHeight(page);
dimensions.height = pageData.getCropBoxWidth(page);
} else {
dimensions.width = pageData.getCropBoxWidth(page);
dimensions.height = pageData.getCropBoxHeight(page);
}
}
//Check if image with no size data stored and get values direct from image
if (dimensions.width == 0 && dimensions.height == 0 && commonValues.getBufferedImg() != null) {
if (isRotated) {
dimensions.width = commonValues.getBufferedImg().getHeight();
dimensions.height = commonValues.getBufferedImg().getWidth();
} else {
dimensions.width = commonValues.getBufferedImg().getWidth();
dimensions.height = commonValues.getBufferedImg().getHeight();
}
}
return dimensions;
}
private static void handleFacing(final int page, final Dimension dimensions, final PdfPageData pageData,
final boolean isRotated, final PdfDecoderInt decode_pdf, final Values commonValues) {
int leftPage;
if (decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER)) {
leftPage = (page / 2) * 2;
if (commonValues.getPageCount() == 2) {
leftPage = 1;
}
} else {
leftPage = (page);
if ((leftPage & 1) == 0) {
leftPage--;
}
}
if (leftPage == 0) {
leftPage++;
}
if (isRotated) {
dimensions.width = pageData.getCropBoxHeight(leftPage);
//if first or last page double the width, otherwise add other page width
if (leftPage + 1 > commonValues.getPageCount() || leftPage == 1) {
dimensions.width *= 2;
} else {
dimensions.width += pageData.getCropBoxHeight(leftPage + 1);
}
dimensions.height = pageData.getCropBoxWidth(leftPage);
if (leftPage + 1 <= commonValues.getPageCount() && dimensions.height < pageData.getCropBoxWidth(leftPage + 1)) {
dimensions.height = pageData.getCropBoxWidth(leftPage + 1);
}
} else {
dimensions.width = pageData.getCropBoxWidth(leftPage);
//if first or last page double the width, otherwise add other page width
if (leftPage + 1 > commonValues.getPageCount()) {
dimensions.width *= 2;
} else {
dimensions.width += pageData.getCropBoxWidth(leftPage + 1);
}
dimensions.height = pageData.getCropBoxHeight(leftPage);
if (leftPage + 1 <= commonValues.getPageCount() && dimensions.height < pageData.getCropBoxHeight(leftPage + 1)) {
dimensions.height = pageData.getCropBoxHeight(leftPage + 1);
}
}
}
private static void handleContinuousModes(final Dimension dimensions, final boolean isRotated,
final PageOffsets offsets, final int i, final int i2) {
if (isRotated) {
dimensions.width = i;
dimensions.height = offsets.getMaxW();
} else {
dimensions.width = i2;
dimensions.height = offsets.getMaxH();
}
}
private static float getScalingFromString(String numberValue) {
float zoom = -1;
if ((numberValue != null) && (!numberValue.isEmpty())) {
//Remove the % that may be present when setting value manually
if (numberValue.endsWith("%")) {
numberValue = numberValue.substring(0, numberValue.length() - 1);
}
try {
zoom = Float.parseFloat(numberValue);
} catch (final NumberFormatException e) {
LogWriter.writeLog("Exception in getting zoom " + e);
//its got characters in it so get first valid number string
final int length = numberValue.length();
int ii = 0;
while (ii < length) {
final char c = numberValue.charAt(ii);
if ((c >= '0' && c <= '9') || c == '.') {
ii++;
} else {
break;
}
}
if (ii > 0) {
numberValue = numberValue.substring(0, ii);
}
//try again if we reset above
try {
zoom = Float.parseFloat(numberValue);
} catch (final NumberFormatException e1) {
LogWriter.writeLog("Exception in getting zoom " + e1);
zoom = -1;
}
}
if (zoom > 1_000) {
zoom = 1_000;
}
}
return zoom;
}
private void setupScalingValue(final int index, float viewWidth, float viewHeight, final float contentWidth, final float contentHeight) {
// [AWI]: Get the default width of scrollbars from the UI Manager
int scrollbarWidth = 0;
final Object scrollbarWidthObj = UIManager.get("ScrollBar.width");
if (scrollbarWidthObj instanceof Integer) {
scrollbarWidth = ((Integer) scrollbarWidthObj);
if (scrollbarWidth < 0) {
scrollbarWidth = 0;
}
}
float x_factor, y_factor, window_factor = 1.0f;
// [AWI]: Iterate over the scaling algorithm to try and take the scrollbar size into account.
// This logic was added to address an issue with 'Fit Width' and 'Fit Height' calculations where the
// scrollbar appeared as a result of the scaling, but the scrollbar was not taken into account in the
// scaling algorithm. When this occurred, both scrollbars could appear, even though only one should.
//
// The loopCount is configured such that the scaling routine should be run at least once, but not more
// than enough to make room for the scrollbar, to prevent an infinite loop.
float scaledWidth, scaledHeight;
int loopCount = 0;
while (loopCount++ <= (scrollbarWidth)) {
x_factor = viewWidth / contentWidth;
y_factor = viewHeight / contentHeight;
window_factor = Math.min(x_factor, y_factor);
if (index != -1) {
if (index < 3) { //handle scroll to width/height/window
switch (index) {
case 0:
scaling = window_factor;
break;
case 1:
scaling = y_factor;
break;
case 2:
scaling = x_factor;
break;
}
// [AWI]: Determine if the horizontal scrollbar will appear when set to 'Fit Height'
// or if the vertical scrollbar will appear when set to 'Fit Width' and if so, add the
// scrollbar size into the scaling algorithm and recalculate once.
scaledWidth = scaling * contentWidth;
scaledHeight = scaling * contentHeight;
if (index == 1 && scaledWidth > viewWidth) { // height
viewHeight--;
} else if (index == 2 && scaledHeight > viewHeight) { // width
viewWidth--;
} else {
// Break out to prevent multiple passes since scrollbars should not be displayed
break;
}
} else {
scaling = decode_pdf.getDPIFactory().adjustScaling(scalingFloatValues[index]);
// Break out to prevent multiple passes since scrollbars should not be displayed
break;
}
}
}
if (decode_pdf.getDisplayView() == Display.FACING) { // Enable turnover if both pages properly displayed
pageTurnScalingAppropriate = scaling <= window_factor;
}
if (thumbscroll != null) {
if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE && scaling <= window_factor) {
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
thumbscroll.setVisible(commonValues.getFileType() == Values.FileType.PDF);
} else {
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
thumbscroll.setVisible(false);
}
}
}
/**
* Set scaling to nearest of the viewer default values.
*
* @param newScaling The scaling value to snap to viewer default values
*/
public void snapScalingToDefaults(float newScaling) {
newScaling = decode_pdf.getDPIFactory().adjustScaling(newScaling / 100);
float width = scrollPane.getViewport().getWidth() - inset - inset;
final float height = scrollPane.getViewport().getHeight() - inset - inset;
final Dimension contentSize = getContentDimensions(commonValues.getCurrentPage());
if (displayPane != null) {
width -= displayPane.getDividerSize();
}
float x_factor;
float y_factor;
final float window_factor;
x_factor = width / contentSize.width;
y_factor = height / contentSize.height;
if (x_factor < y_factor) {
window_factor = x_factor;
x_factor = -1;
} else {
window_factor = y_factor;
y_factor = -1;
}
if (getSelectedComboIndex(Commands.SCALING) != 0
&& ((newScaling < window_factor * 1.1 && newScaling > window_factor * 0.91)
|| ((window_factor > scaling && window_factor < newScaling) || (window_factor < scaling && window_factor > newScaling)))) {
setSelectedComboIndex(Commands.SCALING, 0);
scaling = window_factor;
} else if (y_factor != -1
&& getSelectedComboIndex(Commands.SCALING) != 1
&& ((newScaling < y_factor * 1.1 && newScaling > y_factor * 0.91)
|| ((y_factor > scaling && y_factor < newScaling) || (y_factor < scaling && y_factor > newScaling)))) {
setSelectedComboIndex(Commands.SCALING, 1);
scaling = y_factor;
} else if (x_factor != -1
&& getSelectedComboIndex(Commands.SCALING) != 2
&& ((newScaling < x_factor * 1.1 && newScaling > x_factor * 0.91)
|| ((x_factor > scaling && x_factor < newScaling) || (x_factor < scaling && x_factor > newScaling)))) {
setSelectedComboIndex(Commands.SCALING, 2);
scaling = x_factor;
} else {
setSelectedComboItem(Commands.SCALING, String.valueOf((int) decode_pdf.getDPIFactory().removeScaling(newScaling * 100)));
scaling = newScaling;
}
}
public void rotate() {
rotation = Integer.parseInt((String) getSelectedComboItem(Commands.ROTATION));
scaleAndRotate();
((JComponent) decode_pdf).updateUI();
}
/**
* Scrolls the view to the specified page.
*
* @param page Page to scroll to.
*/
private void scrollToPage(final int page) {
commonValues.setCurrentPage(page);
if (commonValues.getCurrentPage() > 0) {
int yCord = 0;
if (decode_pdf.getDisplayView() != Display.SINGLE_PAGE) {
yCord = decode_pdf.getPages().getYCordForPage(page);
}
if ((decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING || decode_pdf.getDisplayView() == Display.FACING)
&& page == 1) {
scrollPane.getHorizontalScrollBar().setValue((int) (decode_pdf.getPdfPageData().getCropBoxWidth(commonValues.getCurrentPage()) * scaling));
} else {
scrollPane.getHorizontalScrollBar().setValue(0);
}
scrollPane.getVerticalScrollBar().setValue(yCord);
}
if (decode_pdf.getPageCount() > 1) {
swButtons.setPageLayoutButtonsEnabled(true);
}
}
/**
* Set the thumbnail panel ready for display.
*/
private void setupThumbnailPanel() {
if (isSetup) {
return;
}
isSetup = true;
if (thumbnails.isShownOnscreen()) {
final int pages = decode_pdf.getPageCount();
//setup and add to display
thumbnails.setupThumbnails(pages, textFont, decode_pdf.getPdfPageData());
//add listener so clicking on button changes to page - has to be in Viewer so it can update it
final Object[] buttons = thumbnails.getButtons();
for (int i = 0; i < pages; i++) {
((AbstractButton) buttons[i]).addActionListener(new SwingPageChanger(this, commonValues, i));
}
//add global listener
thumbnails.addComponentListener();
}
}
/**
* Set the bookmarks for the outline panel
*
* @param alwaysGenerate true we will generate the bookmarks, false we only generate bookmarks if not already generated
*/
public void setBookmarks(final boolean alwaysGenerate) {
//Ignore if done already
if ((bookmarksGenerated && !alwaysGenerate) || decode_pdf.isLoadingLinearizedPDF()) {
return;
}
bookmarksGenerated = true;
final org.w3c.dom.Document doc = decode_pdf.getOutlineAsXML();
Node rootNode = null;
if (doc != null) {
rootNode = doc.getFirstChild();
}
if (rootNode != null) {
tree.reset(rootNode);
/*
* Use a mouse listener instead of a TreeSelectionListener for 2 reasons
* 1. Tree selection only works on new selections, Mouse clicks work on
* every click of the mouse.
* 2. Tree nodes are highlighted before the mouse event, the mouse event
* can check the node that was highlighted by the tree and trigger it
* allowing highlighted bookmarks to be triggered again.
* We can also check if the mouse is within the node so it doesn't trigger
* if clicked in an empty area.
*/
tree.getTree().addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent e) {
final DefaultMutableTreeNode node = tree.getLastSelectedPathComponent();
final int[] selected = tree.getTree().getSelectionRows();
if (selected != null && selected.length != 0) {
final Rectangle r = tree.getTree().getRowBounds(selected[0]);
if (node == null || !r.contains(e.getX(), e.getY())) {
return;
}
}
triggerBookmark(node);
}
});
/*
* Navigate bookmarks using arrow keys,
* left and right go to parent / child nodes,
* enter key will trigger the currently selected node
*/
tree.getTree().addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(final KeyEvent e) {
if (e.getKeyCode() == '\n') {
final DefaultMutableTreeNode node = tree.getLastSelectedPathComponent();
if (node != null) {
triggerBookmark(node);
}
}
}
});
} else {
tree.reset(null);
}
}
private void triggerBookmark(final DefaultMutableTreeNode node) {
final JTree jtree = tree.getTree();
final DefaultTreeModel treeModel = (DefaultTreeModel) jtree.getModel();
final java.util.List<TreeNode> flattenedTree = new ArrayList<>();
//flatten out the tree so we can find the index of the selected node
getFlattenedTreeNodes((TreeNode) treeModel.getRoot(), flattenedTree);
flattenedTree.remove(0); // remove the root node as we don't account for this
final int index = flattenedTree.indexOf(node);
final String ref = tree.convertNodeIDToRef(index);
final PdfObject Aobj = decode_pdf.getOutlineData().getAobj(ref);
//handle in our handler code
if (Aobj != null) {
if (SwingUtilities.isEventDispatchThread()) {
decode_pdf.getFormRenderer().getActionHandler().gotoDest(Aobj, ActionHandler.MOUSECLICKED, PdfDictionary.Dest);
} else {
try {
SwingUtilities.invokeAndWait(() -> decode_pdf.getFormRenderer().getActionHandler().gotoDest(Aobj, ActionHandler.MOUSECLICKED, PdfDictionary.Dest));
} catch (InterruptedException | InvocationTargetException e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
}
}
}
private void initStatus() {
decode_pdf.setStatusBarObject(statusBar);
//and initialise the display
setMultibox(new int[]{});
}
public void setCoordText(final String string) {
coords.setText(string);
}
private void initCoordBox() {
coords.setOpaque(true);
coords.setBorder(BorderFactory.createEtchedBorder());
coords.setPreferredSize(multibox.getPreferredSize());
//Need to ensure the coords appear correctly in facing mode
//incase coords have not been displayed before entering facing mode
coords.setSize(multibox.getPreferredSize());
coords.setText(" X: " + " Y: " + ' ' + ' ');
}
public void setPageNumber() {
if (SwingUtilities.isEventDispatchThread()) {
setPageNumberWorker();
if (isSetup) {
//Page changed so save this page as last viewed
setThumbnails();
}
} else {
final Runnable r = () -> {
setPageNumberWorker();
if (isSetup) {
//Page changed so save this page as last viewed
setThumbnails();
}
};
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException | InvocationTargetException e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
}
}
private void setPageNumberWorker() {
if (pageCounter2 == null) {
return;
}
if (!decode_pdf.isOpen() && !commonValues.isMultiTiff()) {
pageCounter2.setText("0");
pageCounter3.setText(Messages.getMessage("PdfViewerOfLabel.text") + " 0");
} else {
if (thumbscroll != null) {
thumbscroll.setMaximum(decode_pdf.getPageCount());
thumbscroll.setValue(commonValues.getCurrentPage() - 1);
}
final int currentPage = commonValues.getCurrentPage();
if (decode_pdf.getDisplayView() == Display.FACING || decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING) {
if (decode_pdf.getPageCount() == 2) {
pageCounter2.setText(getPageLabel(1) + '/' + getPageLabel(2));
} else if (decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER)) {
final int base = currentPage & -2;
if (base != decode_pdf.getPageCount() && base != 0) {
pageCounter2.setText(getPageLabel(base) + '/' + getPageLabel(base + 1));
} else {
pageCounter2.setText(getPageLabel(currentPage));
}
} else {
final int base = currentPage - (1 - (currentPage & 1));
if (base != decode_pdf.getPageCount()) {
pageCounter2.setText(getPageLabel(base) + '/' + getPageLabel(base + 1));
} else {
pageCounter2.setText(getPageLabel(currentPage));
}
}
} else {
pageCounter2.setText(getPageLabel(currentPage));
}
if (pageLabelDiffers(currentPage)) {
pageCounter3.setText("(" + currentPage + ' ' + Messages.getMessage("PdfViewerOfLabel.text") + ' ' + commonValues.getPageCount() + ')'); //$NON-NLS-1$
} else {
pageCounter3.setText(Messages.getMessage("PdfViewerOfLabel.text") + ' ' + commonValues.getPageCount()); //$NON-NLS-1$
}
swButtons.hideRedundentNavButtons(this);
}
}
/**
* note - to plugin put all on single line so addButton values over-ridden
*/
private void createNavbar() {
if (memoryMonitor == null) { //ensure only 1 instance
memoryMonitor = new Timer(500, event -> {
final int free = (int) (Runtime.getRuntime().freeMemory() / (1_024 * 1_024));
final int total = (int) (Runtime.getRuntime().totalMemory() / (1_024 * 1_024));
//this broke the image saving when it was run every time
if (finishedDecoding) {
finishedDecoding = false;
}
memoryBar.setMaximum(total);
memoryBar.setValue(total - free);
memoryBar.setStringPainted(true);
memoryBar.setString((total - free) + "M of " + total + 'M');
});
memoryMonitor.start();
}
multibox.setLayout(new BorderLayout());
navButtons.add(multibox, BorderLayout.WEST);
navButtons.add(Box.createHorizontalGlue());
navToolBar.add(Box.createHorizontalGlue());
swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.RewindToStart"), "start.gif", Commands.FIRSTPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Rewind10"), "fback.gif", Commands.FBACKPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Rewind1"), "back.gif", Commands.BACKPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
pageCounter1 = new JLabel(Messages.getMessage("PdfViewerPageLabel.text"));
pageCounter1.setOpaque(false);
navToolBar.add(pageCounter1);
navToolBar.add(pageCounter2);
navToolBar.add(pageCounter3);
swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Forward1"), "forward.gif", Commands.FORWARDPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Forward10"), "fforward.gif", Commands.FFORWARDPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.ForwardLast"), "end.gif", Commands.LASTPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
navToolBar.add(Box.createHorizontalGlue());
if (debugMode) {
addLimitDecodeSlider();
}
swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.SinglePage"), "single.gif", Commands.SINGLE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.Continuous"), "continuous.gif", Commands.CONTINUOUS, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.ContinousFacing"), "continuous_facing.gif", Commands.CONTINUOUS_FACING, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.Facing"), "facing.gif", Commands.FACING, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.PageFlow"), "pageflow.gif", Commands.PAGEFLOW, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
final Dimension size;
navButtons.add(pagesToolBar, BorderLayout.EAST);
size = pagesToolBar.getPreferredSize();
multibox.setPreferredSize(size);
navButtons.add(navToolBar, BorderLayout.CENTER);
}
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
private void addLimitDecodeSlider() {
final JToolBar decoderPanel = new JToolBar();
decoderPanel.setFloatable(false);
decoderPanel.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridy = 0;
final JSlider slider = new JSlider();
slider.setMinimum(0);
slider.setMinorTickSpacing(1);
slider.setMinorTickSpacing(10);
slider.setValue(0);
c.gridx = 0;
c.weightx = 0;
final NumberFormat format = NumberFormat.getInstance();
final NumberFormatter formatter = new NumberFormatter(format);
formatter.setValueClass(Integer.class);
formatter.setMinimum(0);
formatter.setAllowsInvalid(true);
formatter.setCommitsOnValidEdit(false);
final JFormattedTextField field = new JFormattedTextField(formatter);
final CommandWindow commandWindow = new CommandWindow();
CommandParser.commandWindow = commandWindow;
Tj.commandWindow = commandWindow;
final DefaultListModel<String> listModel = new DefaultListModel<>();
commandWindow.setListModel(listModel);
final HashSet<String> commands = new HashSet<>();
commandWindow.setHashSet(commands);
final JList<String> list = new JList<>(listModel);
final JScrollPane scrollPane = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
final JScrollBar v = scrollPane.getVerticalScrollBar();
final TreeSet<String> breaks =
new TreeSet<>(Comparator.comparingInt(cmd -> Integer.parseInt(cmd.substring(0, cmd.indexOf(':')))));
list.setCellRenderer(new ColorListCellRenderer(commands, breaks, 300));
final LimitDecodeTrackerNoSwing errorTracker =
new LimitDecodeTrackerNoSwing((PdfDecoder) decode_pdf, formatter, field, slider, breaks, list);
final KeyAdapter keyAdapter = new KeyAdapter() {
@Override
public void keyReleased(final KeyEvent e) {
final int value = (Integer) field.getValue();
if (e != null && (e.getKeyChar() == '\n' || e.getKeyChar() == '\r')) {
field.setValue(value);
}
slider.setValue(value);
}
};
field.addKeyListener(keyAdapter);
slider.addChangeListener(e -> {
if (slider.getValueIsAdjusting()) {
return; // Redecoding each time the slider moves is very slow
}
final int value = slider.getValue();
field.setValue(value);
errorTracker.repaint(value);
v.setValue(v.getMaximum());
});
decode_pdf.addExternalHandler(errorTracker, Options.ErrorTracker);
c.gridx = 1;
swButtons.addButtonToToolBarWithConstraints("Start", "start.gif", -1, menuItems, this, e -> {
field.setValue(0);
keyAdapter.keyReleased(null);
}, decoderPanel, c);
c.gridx = 2;
swButtons.addButtonToToolBarWithConstraints("Retreat by 1", "back.gif", -1, menuItems, this, e -> {
if ((Integer) field.getValue() <= 0) {
field.setValue(0);
} else {
field.setValue(((Integer) field.getValue()) - 1);
}
keyAdapter.keyReleased(null);
}, decoderPanel, c);
c.gridx = 3;
c.weightx = 1;
decoderPanel.add(field, c);
c.weightx = 0;
c.gridx = 4;
swButtons.addButtonToToolBarWithConstraints("Advance by 1", "forward.gif", -1, menuItems, this, e -> {
if ((int) field.getValue() >= (Integer) formatter.getMaximum()) {
field.setValue(formatter.getMaximum());
} else {
field.setValue(((Integer) field.getValue()) + 1);
}
keyAdapter.keyReleased(null);
}, decoderPanel, c);
c.gridx = 5;
swButtons.addButtonToToolBarWithConstraints("End", "end.gif", -1, menuItems, this, e -> {
field.setValue(formatter.getMaximum());
keyAdapter.keyReleased(null);
}, decoderPanel, c);
c.gridx = 6;
c.fill = GridBagConstraints.VERTICAL;
final JSeparator separator = new JSeparator(SwingConstants.VERTICAL);
decoderPanel.add(separator, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 7;
swButtons.addButtonToToolBarWithConstraints("Next breakpoint", "resume.gif", -1, menuItems, this, e -> {
// If we are at the end, the resume button restarts the decoding
if ((int) field.getValue() == (Integer) formatter.getMaximum()) {
try {
final String firstBreak = breaks.first();
field.setValue(Integer.parseInt(firstBreak.substring(0, firstBreak.indexOf(':'))));
keyAdapter.keyReleased(null);
return;
} catch (final NoSuchElementException ignored) {
//NOSONAR
}
}
// If we are not at the end, attempt to find the next breakpoint
String nextBreakpoint = null;
int nextBreakpointCommand = -1;
if (!breaks.isEmpty()) {
for (final String breakPoint : breaks) {
nextBreakpointCommand = Integer.parseInt(breakPoint.substring(0, breakPoint.indexOf(':')));
if (nextBreakpointCommand > (Integer) field.getValue()) {
nextBreakpoint = breakPoint;
break;
}
}
}
if (nextBreakpoint == null) {
field.setValue(formatter.getMaximum());
} else {
field.setValue(nextBreakpointCommand);
}
keyAdapter.keyReleased(null);
}, decoderPanel, c);
c.gridx = 8;
swButtons.addButtonToToolBarWithConstraints("Clear breakpoints", "clearb.gif", -1, menuItems, this, e -> {
breaks.clear();
list.repaint();
}, decoderPanel, c);
final ListSelectionListener listSelectionListener = e -> {
if (list.getValueIsAdjusting()) {
return;
}
final String command = list.getSelectedValue();
if (commands.contains(command)) { // Only allow commands to be breakpoints
if (breaks.contains(command)) {
breaks.remove(command);
} else {
breaks.add(command);
}
}
list.clearSelection();
};
final MouseAdapter listMouseListener = new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent e) {
showMenu(e);
}
@Override
public void mouseReleased(final MouseEvent e) {
showMenu(e);
}
private void showMenu(final MouseEvent e) {
if (!e.isPopupTrigger()) {
return;
}
final int clicked = list.locationToIndex(e.getPoint());
if (clicked != -1 && list.getCellBounds(clicked, clicked).contains(e.getPoint())) {
final JPopupMenu menu = new JPopupMenu();
final JMenuItem breakItem = new JMenuItem("Set breakpoint");
breakItem.addActionListener(e1 -> {
final String command = listModel.get(clicked);
if (commands.contains(command)) { // Only allow commands to be breakpoints
if (breaks.contains(command)) {
breaks.remove(command);
} else {
breaks.add(command);
}
list.repaint();
}
});
menu.add(breakItem);
final String command = listModel.get(clicked);
final Pattern doPattern = Pattern.compile("^\\d+?:\\s+?DO$", Pattern.CASE_INSENSITIVE);
final Matcher doMatcher = doPattern.matcher(command);
if (doMatcher.matches()) {
final JMenuItem imageItem = new JMenuItem("View Image");
imageItem.addActionListener(e1 -> {
final String imageCacheName = imageNameCollector.getCacheName(listModel.get(clicked - 1).substring(1));
if (imageCacheName == null) {
LogWriter.writeLog("[Warning] Cannot find image name in collector");
return;
}
final JDialog imageDialog = new JDialog((Frame) null, doMatcher.group(), false);
imageDialog.add(new JLabel(new ImageIcon(decode_pdf.getObjectStore().loadStoredImage(imageCacheName))));
imageDialog.pack();
imageDialog.setLocationRelativeTo(frame);
imageDialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
imageDialog.setVisible(true);
});
menu.add(imageItem);
} else {
final Pattern idPattern = Pattern.compile("^(\\d+?):\\s+?ID$", Pattern.CASE_INSENSITIVE);
final Matcher idMatcher = idPattern.matcher(command);
if (idMatcher.matches()) {
final JMenuItem imageItem = new JMenuItem("View Inline Image");
imageItem.addActionListener(e1 -> {
final String imageCacheName = imageNameCollector.getCacheNameFromIDToken(Integer.parseInt(idMatcher.group(1)));
if (imageCacheName == null) {
LogWriter.writeLog("[Warning] Cannot find image name in collector");
return;
}
final JDialog imageDialog = new JDialog((Frame) null, idMatcher.group(), false);
imageDialog.add(new JLabel(new ImageIcon(decode_pdf.getObjectStore().loadStoredImage(imageCacheName))));
imageDialog.pack();
imageDialog.setLocationRelativeTo(frame);
imageDialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
imageDialog.setVisible(true);
});
menu.add(imageItem);
}
}
menu.add(new JSeparator(SwingConstants.HORIZONTAL));
final JMenuItem copyItem = new JMenuItem("Copy Text");
copyItem.addActionListener(e1 -> {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new StringSelection(listModel.get(clicked)), null);
});
menu.add(copyItem);
menu.show(list, e.getX(), e.getY());
}
}
};
list.addListSelectionListener(listSelectionListener);
list.addMouseListener(listMouseListener);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
final GridBagConstraints gridBagConstraints = new GridBagConstraints();
final JPanel panel = new JPanel(new GridBagLayout());
panel.setPreferredSize(new Dimension(400, 400));
gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.weightx = 0;
gridBagConstraints.weighty = 0;
gridBagConstraints.anchor = GridBagConstraints.NORTH;
panel.add(slider, gridBagConstraints);
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.weightx = 1;
gridBagConstraints.weighty = 1;
gridBagConstraints.anchor = GridBagConstraints.CENTER;
panel.add(scrollPane, gridBagConstraints);
gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.weightx = 0;
gridBagConstraints.weighty = 0;
gridBagConstraints.anchor = GridBagConstraints.SOUTH;
panel.add(decoderPanel, gridBagConstraints);
((RootPaneContainer) frame).getContentPane().add(panel, BorderLayout.EAST);
}
/**
* Set the interfaces page counter to the page number
* and alter any other interface options to match.
*
* @param page page number as an int
*/
public void setPage(int page) {
if (decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING
&& (page & 1) == 1 && page != 1) {
page--;
}
if (decode_pdf.getDisplayView() == Display.FACING) {
final boolean isSeparacteCover = decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER);
if (isSeparacteCover ? (page & 1) == 1 && page != 1 : (page & 1) == 0) {
page--;
}
}
commonValues.setCurrentPage(page);
setPageNumber();
}
/**
* Method to set the viewers rotation from external sources.
*
* @param rot The rotation to use in the Viewer
*/
public void setRotationFromExternal(final int rot) {
rotation = rot;
rotationBox.setSelectedIndex(rotation / 90);
if (!Values.isProcessing()) {
decode_pdf.repaint();
}
}
/**
* Method to set the viewers scaling from external sources.
*
* @param scale The scaling to use in the Viewer as an enum
*/
public void setScalingFromExternal(final Object[] scale) {
String selectedScale = "";
if (scale.length == 1) {
final String scaleValue = scale[0].toString();
if (scaleValue != null) {
selectedScale = StringUtils.isNumber(scaleValue) ? scaleValue + '%' : scaleValue;
} else {
throw new IllegalArgumentException("Missing second parameter: No custom value set");
}
} else if (scale.length == 2) {
selectedScale = scale[1].toString();
}
scalingBox.setSelectedItem(selectedScale);
}
public Container getFrame() {
return frame;
}
public void showMessageDialog(final String message1) {
final boolean showMessage = customMessageHandler == null || customMessageHandler.showMessage(message1);
//check user has not setup message and if we still show message
if (showMessage) {
javax.swing.SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(frame, message1));
}
}
public void showMessageDialog(final Object message, final String title, final int type) {
final boolean showMessage = customMessageHandler == null || customMessageHandler.showMessage(message);
//check user has not setup message and if we still show message
if (showMessage) {
javax.swing.SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(frame, message, title, type));
}
}
public String showInputDialog(final Object message, final String title, final int type) {
String returnMessage = null;
//check user has not setup message and if we still show message
if (customMessageHandler != null) {
returnMessage = customMessageHandler.requestInput(new Object[]{message, title, title});
}
if (returnMessage == null) {
return JOptionPane.showInputDialog(frame, message, title, type);
} else {
return returnMessage;
}
}
public String showInputDialog(final String message) {
String returnMessage = null;
//check user has not setup message and if we still show message
if (customMessageHandler != null) {
returnMessage = customMessageHandler.requestInput(new String[]{message});
}
if (returnMessage == null) {
return JOptionPane.showInputDialog(frame, message);
} else {
return returnMessage;
}
}
public int showConfirmDialog(final String message, final String message2, final int option) {
int returnMessage = -1;
//check user has not setup message and if we still show message
if (customMessageHandler != null) {
returnMessage = customMessageHandler.requestConfirm(new Object[]{message, message2, String.valueOf(option)});
}
if (returnMessage == -1) {
return JOptionPane.showConfirmDialog(frame, message, message2, option);
} else {
return returnMessage;
}
}
public int showOverwriteDialog(final String file, final boolean yesToAllPresent) {
final int n;
int returnMessage = -1;
//check user has not setup message and if we still show message
if (customMessageHandler != null) {
returnMessage = customMessageHandler.requestConfirm(new Object[]{file, String.valueOf(yesToAllPresent)});
}
if (returnMessage != -1) {
return returnMessage;
}
if (yesToAllPresent) {
final Object[] buttonRowObjects = {
Messages.getMessage("PdfViewerConfirmButton.Yes"),
Messages.getMessage("PdfViewerConfirmButton.YesToAll"),
Messages.getMessage("PdfViewerConfirmButton.No"),
Messages.getMessage("PdfViewerConfirmButton.Cancel")
};
n = JOptionPane.showOptionDialog(frame,
file + '\n' + Messages.getMessage("PdfViewerMessage.FileAlreadyExists")
+ '\n' + Messages.getMessage("PdfViewerMessage.ConfirmResave"),
Messages.getMessage("PdfViewerMessage.Overwrite"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
buttonRowObjects,
buttonRowObjects[0]);
} else {
n = JOptionPane.showOptionDialog(frame,
file + '\n' + Messages.getMessage("PdfViewerMessage.FileAlreadyExists")
+ '\n' + Messages.getMessage("PdfViewerMessage.ConfirmResave"),
Messages.getMessage("PdfViewerMessage.Overwrite"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null, null, null);
}
return n;
}
public void showMessageDialog(final Object info) {
final boolean showMessage = customMessageHandler == null || customMessageHandler.showMessage(info);
//check user has not setup message and if we still show message
if (showMessage) {
javax.swing.SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(frame, info));
}
}
public void showFirstTimePopup() {
//allow user to disable
final boolean showMessage = customMessageHandler == null || customMessageHandler.showMessage("first time popup");
if (!showMessage) {
return;
}
try {
final JPanel a = new JPanel();
a.setLayout(new BoxLayout(a, BoxLayout.Y_AXIS));
final MouseAdapter supportListener = new MouseAdapter() {
@Override
public void mouseEntered(final MouseEvent e) {
if (GUIDisplay.allowChangeCursor) {
a.setCursor(new Cursor(Cursor.HAND_CURSOR));
}
}
@Override
public void mouseExited(final MouseEvent e) {
if (GUIDisplay.allowChangeCursor) {
a.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
@Override
public void mouseClicked(final MouseEvent e) {
try {
java.awt.Desktop.getDesktop().browse(new URI((Messages.getMessage("PdfViewer.SupportLink.Link"))));
} catch (final Exception e1) {
showMessageDialog(e1.getMessage() + ' ' + Messages.getMessage("PdfViewer.ErrorWebsite"));
}
}
};
final JLabel img = new JLabel(new ImageIcon(getClass().getResource("/org/jpedal/examples/viewer/res/supportScreenshot.png")));
img.setBorder(BorderFactory.createRaisedBevelBorder());
img.setAlignmentX(JLabel.CENTER_ALIGNMENT);
img.addMouseListener(supportListener);
a.add(img);
final JLabel supportLink = new JLabel("<html><center><u>" + Messages.getMessage("PdfViewer.SupportLink.Text1") + ' ' + Messages.getMessage("PdfViewer.SupportLink.Text2") + "</u></html>");
supportLink.setMaximumSize(new Dimension(245, 60));
supportLink.setForeground(Color.BLUE);
supportLink.addMouseListener(supportListener);
supportLink.setAlignmentX(JLabel.CENTER_ALIGNMENT);
a.add(supportLink);
a.add(Box.createRigidArea(new Dimension(10, 10)));
JOptionPane.showMessageDialog(
frame,
a,
Messages.getMessage("PdfViewerTitle.RunningFirstTime"),
JOptionPane.PLAIN_MESSAGE);
} catch (final Exception | Error e) {
System.err.println(Messages.getMessage("PdfViewerFirstRunDialog.Error") + ' ' + e);
}
}
public int showConfirmDialog(final Object message, final String title, final int optionType, final int messageType) {
int returnMessage = -1;
//check user has not setup message and if we still show message
if (customMessageHandler != null) {
returnMessage = customMessageHandler.requestConfirm(new Object[]{message, title, String.valueOf(optionType), String.valueOf(messageType)});
}
if (returnMessage == -1) {
return JOptionPane.showConfirmDialog(frame, message, title, optionType, messageType);
} else {
return returnMessage;
}
}
public void setDownloadProgress(final String message, final int percentage) {
downloadBar.setProgress(message, percentage);
setMultibox(new int[]{});
}
public void updateStatusMessage(final String message) {
statusBar.updateStatus(message, 0);
}
public void resetStatusMessage(final String message) {
statusBar.resetStatus(message);
}
public void setStatusProgress(final int size) {
statusBar.setProgress(size);
setMultibox(new int[]{});
}
/**
* Gets the current divider location for the split pane
*
* @return int values representing the current divider location
*/
public int getSplitDividerLocation() {
return displayPane.getDividerLocation();
}
/**
* Get the print dialog.
*
* @param printersList String array of all available printers
* @param defaultPrinter String representing the default printer
* @return a print dialog.
*/
public PrintPanel printDialog(final String[] printersList, final String defaultPrinter) {
final JDialog printDialog = new JDialog((Frame) null, Messages.getMessage("PdfViewerLabel.Printer"), true);
printDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
//get default resolution
String propValue = properties.getValue("defaultDPI");
int defaultDPI = -1;
if (propValue != null && !propValue.isEmpty()) {
try {
propValue = propValue.replaceAll("[^0-9]", "");
defaultDPI = Integer.parseInt(propValue);
} catch (final NumberFormatException e) {
LogWriter.writeLog("Caught an Exception " + e);
}
}
if (printPanel == null) {
printPanel = new PrintPanel(printersList, defaultPrinter, getPaperSizes(), defaultDPI, commonValues.getCurrentPage(), decode_pdf);
} else {
printPanel.resetDefaults(printersList, defaultPrinter, commonValues.getPageCount(), commonValues.getCurrentPage());
}
printDialog.getContentPane().add(printPanel);
printDialog.setSize(670, 415);
printDialog.setResizable(false);
printDialog.setLocationRelativeTo(frame);
printDialog.setName("printDialog");
printDialog.setVisible(true);
printDialog.remove(printPanel);
return printPanel;
}
/**
* Gets the paper sizes for use by the print dialog
*
* @return a PaperSizes object holding all paper sizes
*/
public PaperSizes getPaperSizes() {
if (paperSizes == null) {
paperSizes = new PaperSizes(properties.getValue("defaultPagesize"));
}
return paperSizes;
}
private void setThumbnails() {
final org.jpedal.utils.SwingWorker worker = new org.jpedal.utils.SwingWorker() {
@Override
public Object construct() {
if (thumbnails.isShownOnscreen()) {
setupThumbnailPanel();
thumbnails.generateOtherVisibleThumbnails(commonValues.getCurrentPage());
}
return null;
}
};
worker.start();
}
/**
* Set the search text field to be used for the menu bar search input
*
* @param searchText A JTextField to be used for search input
*/
public void setSearchText(final Object searchText) {
this.searchText = (JTextField) searchText;
}
/**
* Set the search list to be used to hold search results in menu bar search mode
*
* @param results an implementation of SearchList
*/
public void setResults(final SearchList results) {
if (searchInMenu && results.getResultCount() == 0) {
showMessageDialog(Messages.getMessage("PdfViewerFileMenuFind.noResultText") + " \"" + results.getSearchTerm() + '"', Messages.getMessage("PdfViewerFileMenuFind.noResultTitle"), JOptionPane.INFORMATION_MESSAGE);
}
}
/**
* Get the JTabbedPane, as an Object, used for the side tab bar
*
* @return JTabbedPane used for the side tab bar
*/
public JTabbedPane getSideTabBar() {
return navOptionsPanel;
}
private void enableSearchItems(final boolean enabled) {
if (searchInMenu) { //Menu Bar search
searchText.setEnabled(enabled);
options.setEnabled(enabled);
swButtons.getButton(Commands.NEXTRESULT).setEnabled(false);
swButtons.getButton(Commands.PREVIOUSRESULT).setEnabled(false);
} else if (swButtons.getButton(Commands.FIND) != null) { //External Window search
swButtons.getButton(Commands.FIND).setEnabled(enabled);
}
}
/**
* Removes the search window from view with option to clear search results
*
*/
private void removeSearchWindow() {
searchFrame.removeSearchWindow(false);
}
/**
* Alter property using properties files keys and values to alter the user interface
*
* @param value String representation of the property key
* @param set true to turn on option, false to turn off
*/
public void alterProperty(final String value, final boolean set) {
GUIModifier.alterProperty(value, set, this);
}
/**
* Method to dispose of objects used by the interface before closing.
*/
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
public void dispose() {
for (final AWTEventListener listener : Toolkit.getDefaultToolkit().getAWTEventListeners()) {
Toolkit.getDefaultToolkit().removeAWTEventListener(listener);
}
for (final ComponentListener listener : frame.getComponentListeners()) {
frame.removeComponentListener(listener);
}
if (options != null) {
for (final ItemListener listener : options.getItemListeners()) {
options.removeItemListener(listener);
}
}
if (menu != null) {
for (final PopupMenuListener listener : menu.getPopupMenuListeners()) {
menu.removePopupMenuListener(listener);
}
menu.removeAll();
}
thumbnails.removeAllListeners();
thumbnails.dispose();
if (scrollListener != null) {
scrollListener.dispose();
}
mouseHandler.dispose();
if (navButtons != null) {
navButtons.removeAll();
}
menuItems.dispose();
if (coords != null) {
coords.removeAll();
}
if (navOptionsPanel != null) {
disposeNavOptions(navOptionsPanel);
}
if (thumbscroll != null) {
disposeThumbnailScroll(thumbscroll);
}
if (scrollPane != null) {
disposeScrollPane(scrollPane);
}
if (signaturesTree != null) {
signaturesTree.setCellRenderer(null);
signaturesTree.removeAll();
}
if (layersPanel != null) {
layersPanel.removeAll();
}
if (annotationsPanel != null) {
annotationsPanel.dispose();
}
searchFrame.dispose();
if (navToolBar != null) {
disposeNavToolBar(navToolBar);
}
if (pagesToolBar != null) {
disposePageToolBar(pagesToolBar);
}
//release memory at end
if (memoryMonitor != null) {
disposeMemoryMonitor();
}
//Ensure Timer is closed as does not use daemon thread
if (viewListener != null) {
viewListener.dispose();
}
//Below line causes a NullPointerException
removeSearchWindow();
swButtons.dispose();
//display pane cleanup
if (displayPane != null) {
disposeDisplayPane();
}
if (attachmentsPanel != null) {
attachmentsPanel.dispose();
attachmentsPanel = null;
}
final JTree disposeTree = tree.getTree();
if (disposeTree != null) {
disposeTree(disposeTree);
}
removePageListener();
removeGUIListeners((Component) decode_pdf);
if (glassPane != null) {
removeGUIListeners(glassPane);
glassPane.removeAll();
}
disposeFrame();
if (lpane != null) {
for (final PropertyChangeListener listener : lpane.getPropertyChangeListeners()) {
lpane.removePropertyChangeListener(listener);
}
for (final ComponentListener listener : lpane.getComponentListeners()) {
lpane.removeComponentListener(listener);
}
lpane.removeAll();
}
if (containerForThumbnails != null) {
for (final PropertyChangeListener listener : containerForThumbnails.getPropertyChangeListeners()) {
containerForThumbnails.removePropertyChangeListener(listener);
}
containerForThumbnails.removeAll();
}
if (frame != null) {
frame.removeAll();
}
decode_pdf.closePdfFile();
decode_pdf.dispose();
((Container) decode_pdf).removeAll();
setGlobalVariablesToNull();
tree = null;
scalingFloatValues = null;
rotationBox = null;
scalingBox = null;
}
private void setGlobalVariablesToNull() {
options = null;
menu = null;
scrollListener = null;
mouseHandler = null;
pageTitle = null;
bookmarksTitle = null;
signaturesTitle = null;
layersTitle = null;
annotationTitle = null;
attachmentsTitle = null;
currentCommandListener = null;
navButtons = null;
coords = null;
navOptionsPanel = null;
thumbscroll = null;
scrollPane = null;
textFont = null;
statusBar = null;
downloadBar = null;
pageCounter2 = null;
pageCounter3 = null;
signaturesTree = null;
layersPanel = null;
annotationsPanel = null;
searchFrame = null;
navToolBar = null;
pagesToolBar = null;
layersObject = null;
viewListener = null;
glassPane = null;
frame = null;
portfolioParent = null;
decode_pdf = null;
}
private static void disposePageToolBar(final JToolBar toolBar) {
for (final MouseListener listener : toolBar.getMouseListeners()) {
toolBar.removeMouseListener(listener);
}
for (final MouseMotionListener listener : toolBar.getMouseMotionListeners()) {
toolBar.removeMouseMotionListener(listener);
}
toolBar.removeAll();
}
private static void disposeNavToolBar(final JToolBar navBar) {
final Component[] comps = navBar.getComponents();
for (final Component comp : comps) {
for (final PropertyChangeListener listener : comp.getPropertyChangeListeners()) {
comp.removePropertyChangeListener(listener);
}
for (final ComponentListener listener : comp.getComponentListeners()) {
comp.removeComponentListener(listener);
}
}
navBar.removeAll();
}
private static void disposeScrollPane(final JScrollPane scrollPane) {
for (final PropertyChangeListener listener : scrollPane.getPropertyChangeListeners()) {
scrollPane.removePropertyChangeListener(listener);
}
for (final MouseWheelListener listener : scrollPane.getMouseWheelListeners()) {
scrollPane.removeMouseWheelListener(listener);
}
for (final MouseMotionListener listener : scrollPane.getMouseMotionListeners()) {
scrollPane.removeMouseMotionListener(listener);
}
for (final FocusListener listener : scrollPane.getFocusListeners()) {
scrollPane.removeFocusListener(listener);
}
scrollPane.removeAll();
}
private static void disposeNavOptions(final JTabbedPane navOptions) {
for (final MouseListener listener : navOptions.getMouseListeners()) {
navOptions.removeMouseListener(listener);
}
for (final ChangeListener listener : navOptions.getChangeListeners()) {
navOptions.removeChangeListener(listener);
}
navOptions.removeAll();
}
private static void disposeThumbnailScroll(final JScrollBar thumbnailScroll) {
for (final MouseListener listener : thumbnailScroll.getMouseListeners()) {
thumbnailScroll.removeMouseListener(listener);
}
for (final PropertyChangeListener listener : thumbnailScroll.getPropertyChangeListeners()) {
thumbnailScroll.removePropertyChangeListener(listener);
}
thumbnailScroll.removeAll();
}
private void disposeMemoryMonitor() {
memoryMonitor.stop();
final ActionListener[] al = memoryMonitor.getActionListeners();
for (int i = 0; i != al.length; i++) {
memoryMonitor.removeActionListener(al[i]);
}
}
private void disposeFrame() {
if (frame instanceof JFrame) {
final JFrame disposeFrame = (JFrame) frame;
for (final ComponentListener listener : disposeFrame.getComponentListeners()) {
disposeFrame.removeComponentListener(listener);
}
} else {
final Component disposeComp = frame;
for (final ComponentListener listener : disposeComp.getComponentListeners()) {
disposeComp.removeComponentListener(listener);
}
}
}
private static void removeGUIListeners(final Component comp) {
for (final KeyListener listener : comp.getKeyListeners()) {
comp.removeKeyListener(listener);
}
for (final MouseListener listener : comp.getMouseListeners()) {
comp.removeMouseListener(listener);
}
for (final MouseWheelListener listener : comp.getMouseWheelListeners()) {
comp.removeMouseWheelListener(listener);
}
for (final MouseMotionListener listener : comp.getMouseMotionListeners()) {
comp.removeMouseMotionListener(listener);
}
}
private static void disposeTree(final JTree disposeTree) {
for (final MouseListener listener : disposeTree.getMouseListeners()) {
disposeTree.removeMouseListener(listener);
}
for (final KeyListener listener : disposeTree.getKeyListeners()) {
disposeTree.removeKeyListener(listener);
}
disposeTree.removeAll();
}
private void disposeDisplayPane() {
for (final PropertyChangeListener listener : displayPane.getPropertyChangeListeners()) {
displayPane.removePropertyChangeListener(listener);
}
for (final MouseListener listener : displayPane.getMouseListeners()) {
displayPane.removeMouseListener(listener);
}
for (final ComponentListener listener : displayPane.getComponentListeners()) {
displayPane.removeComponentListener(listener);
}
displayPane.removeAll();
}
/**
* Not part of API - used internally
*
* @return true if it is page turn scaling is appropriate
*/
public boolean getPageTurnScalingAppropriate() {
return pageTurnScalingAppropriate;
}
/**
* Not part of API - used internally
*
* @return the gui cursor object
*/
public SwingCursor getGUICursor() {
return guiCursor;
}
/**
* Checks if title matches the title of any of the side tab bar tabs
*
* @param title String title to check for.
* @return String title of tab found.
*/
public String getTitles(final String title) {
if (title.equals(pageTitle)) {
return pageTitle;
} else if (title.equals(bookmarksTitle)) {
return bookmarksTitle;
} else if (title.equals(signaturesTitle)) {
return signaturesTitle;
} else if (title.equals(layersTitle)) {
return layersTitle;
} else if (title.equals(annotationTitle)) {
return annotationTitle;
} else if (title.equals(attachmentsTitle)) {
return attachmentsTitle;
}
return null;
}
/**
* Get the GUIButtons object that holds all buttons used by the user interface
*
* @return GUIButtons implementation used by the user interface
*/
public Buttons getButtons() {
return swButtons;
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setViewerIcon() {
if (frame instanceof JFrame) {
//Check if file location provided
final URL path = guiCursor.getURLForImage("icon.png");
if (path != null) {
try {
final BufferedImage fontIcon = JDeli.read(path.openStream());
((Window) frame).setIconImage(fontIcon);
} catch (final Exception e) {
LogWriter.writeLog("Exception attempting to set icon " + e);
}
}
}
}
/**
* Get the SwingMenuItems object that holds all the menu items used by the user interface.
*
* @return SwingMenuItems implementation used by the user interface
*/
public SwingMenuItems getMenuItems() {
return menuItems;
}
/**
* Key method that calls decodePage from GUI.java
*/
public void decodePage() {
if (SwingAnnotationPanel.addPanel()) {
annotationsPanel.getAnnotationListener().setFormMode(SwingAnnotationPanel.FORMMODE.CREATION);
}
//Ensure thumbnail scroll bar is updated when page changed
if (thumbscroll != null) {
setThumbnailScrollBarValue(commonValues.getCurrentPage() - 1);
}
decodeGUIPage();
}
/**
* Get the PdfDecoder object used to display the PDF in the user interface
*
* @return PdfDecoder object used for display
*/
public PdfDecoder getPdfDecoder() {
return ((PdfDecoder) decode_pdf);
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void addComboListenerAndLabel(final SwingCombo combo) {
//add listener
combo.addActionListener(currentCommandListener);
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void addGUIComboBoxes(final SwingCombo combo) {
swButtons.getTopButtons().add(combo);
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setupCenterPanelBackground() {
String propValue = properties.getValue("replacePdfDisplayBackground");
Color background = new Color(190, 190, 190);
if (!propValue.isEmpty()
&& "true".equalsIgnoreCase(propValue)) {
propValue = properties.getValue("pdfDisplayBackground");
if (!propValue.isEmpty()) {
currentCommands.executeCommand(ViewerCommands.SETDISPLAYBACKGROUND, new Object[]{Integer.parseInt(propValue)});
}
background = new Color(Integer.parseInt(propValue));
} else {
if (decode_pdf.getDecoderOptions().getDisplayBackgroundColor() != null) {
background = decode_pdf.getDecoderOptions().getDisplayBackgroundColor();
} else if (decode_pdf.useNewGraphicsMode()) {
background = new Color(55, 55, 65);
}
}
((Component) decode_pdf).setBackground(background);
frame.setBackground(background);
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setupComboBoxes() {
final String[] rotationValues = {"0", "90", "180", "270"};
final String[] scalingValues = {Messages.getMessage("PdfViewerScaleWindow.text"), Messages.getMessage("PdfViewerScaleHeight.text"),
Messages.getMessage("PdfViewerScaleWidth.text"),
"25%", "50%", "75%", "100%", "125%", "150%", "200%", "250%", "500%", "750%", "1000%"};
//set new default if appropriate
String choosenScaling = System.getProperty("org.jpedal.defaultViewerScaling");
//Only use value from properties is VM arguement not set
if (choosenScaling == null) {
choosenScaling = properties.getValue("startScaling");
}
if (choosenScaling != null) {
final int total = scalingValues.length;
for (int aa = 0; aa < total; aa++) {
if (scalingValues[aa].equals(choosenScaling)) {
defaultSelection = aa;
aa = total;
}
}
}
scalingBox = new SwingCombo(scalingValues);
scalingBox.setEditable(true);
scalingBox.setSelectedIndex(defaultSelection); //set default before we add a listener
//if you enable, remember to change rotation and quality Comboboxes
rotationBox = new SwingCombo(rotationValues);
rotationBox.setSelectedIndex(0); //set default before we add a listener
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setupKeyboardControl() {
((Component) decode_pdf).addKeyListener(new KeyAdapter() {
int count;
int pageChange;
java.util.Timer t2;
@Override
public void keyPressed(final KeyEvent e) {
final JScrollBar scroll = scrollPane.getVerticalScrollBar();
final int keyPressed = e.getKeyCode();
if (keyPressed == KeyEvent.VK_LEFT || keyPressed == KeyEvent.VK_RIGHT) {
//Only use left and right arrows to change pages if page is smaller than display area
if (scrollPane.getWidth() > ((Component) decode_pdf).getWidth()) {
if (keyPressed == KeyEvent.VK_LEFT) { //change page
pageChange--;
} else { //change page
pageChange++;
}
}
} else if ((keyPressed == KeyEvent.VK_UP || keyPressed == KeyEvent.VK_DOWN) && (count == 0)) {
if (keyPressed == KeyEvent.VK_UP
&& scroll.getValue() == scroll.getMinimum()
&& commonValues.getCurrentPage() > 1) {
//change page
pageChange--;
} else if (keyPressed == KeyEvent.VK_DOWN
&& (scroll.getValue() == scroll.getMaximum() - scroll.getHeight() || scroll.getHeight() == 0)
&& commonValues.getCurrentPage() < decode_pdf.getPageCount()) {
//change page
pageChange++;
}
}
count++;
if (pageChange != 0) {
if (t2 != null) {
t2.cancel();
}
final TimerTask t = new TimerTask() {
@Override
public void run() {
int p = (commonValues.getCurrentPage() + pageChange);
if (p < 1) {
p = 1;
} else if (p > decode_pdf.getPageCount()) {
p = decode_pdf.getPageCount();
}
if (p != commonValues.getCurrentPage()) {
final String page = String.valueOf(p);
SwingUtilities.invokeLater(() -> {
currentCommands.executeCommand(ViewerCommands.GOTO, new Object[]{page});
if (scroll.getValue() == scroll.getMinimum()
&& commonValues.getCurrentPage() > 1) {
scroll.setValue(scroll.getMaximum());
} else if ((scroll.getValue() == scroll.getMaximum() - scroll.getHeight() || scroll.getHeight() == 0)
&& commonValues.getCurrentPage() < decode_pdf.getPageCount()) {
scroll.setValue(scroll.getMinimum());
}
});
}
pageChange = 0;
//Add cancel for the timer at the end of this task.
//This should ensure the timer is not kept active
if (t2 != null) {
t2.cancel();
}
}
};
//restart - if its not stopped it will trigger page update
t2 = new java.util.Timer();
t2.schedule(t, 500);
}
}
@Override
public void keyReleased(final KeyEvent e) {
count = 0;
}
});
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setupPDFDisplayPane() {
if (SwingAnnotationPanel.addPanel()) {
glassPane = new JPanel();
glassPane.setLayout(null);
glassPane.setOpaque(false);
lpane.add(scrollPane, 0, 0);
lpane.add(glassPane, 1, 1);
}
thumbscroll = new JScrollBar(JScrollBar.VERTICAL, 0, 1, 0, 1);
thumbscroll.setName("ThumbnailScroll");
if (scrollListener == null) {
scrollListener = new SwingScrollListener(this, "true".equalsIgnoreCase(properties.getValue("previewOnSingleScroll")));
}
thumbscroll.addAdjustmentListener(scrollListener);
thumbscroll.addMouseListener(scrollListener);
containerForThumbnails.setLayout(new BorderLayout());
containerForThumbnails.add(thumbscroll, BorderLayout.EAST);
scrollPane.getViewport().add(((Component) decode_pdf));
if (SwingAnnotationPanel.addPanel()) {
containerForThumbnails.add(lpane, BorderLayout.CENTER);
} else {
containerForThumbnails.add(scrollPane, BorderLayout.CENTER);
}
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.getVerticalScrollBar().setUnitIncrement(80);
scrollPane.getHorizontalScrollBar().setUnitIncrement(80);
//Keyboard control of next/previous page
setupKeyboardControl();
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
private void setupBorderPanes() {
//Create a left-right split pane with tabs and add to main display
navOptionsPanel.setTabPlacement(JTabbedPane.LEFT);
navOptionsPanel.setOpaque(true);
//Use start size as min width to keep divider from covering tabs
navOptionsPanel.setMinimumSize(new Dimension(collapsedSize, 100));
navOptionsPanel.setName("NavPanel");
navOptionsPanel.setFocusable(false);
setupSidebarTitles();
displayPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, navOptionsPanel, containerForThumbnails);
displayPane.setOneTouchExpandable(false);
//update scaling when divider moved
displayPane.addPropertyChangeListener("dividerLocation", e -> {
//hack to get it to use current values instead of old values
scrollPane.getViewport().setSize((scrollPane.getViewport().getWidth() + (Integer) e.getOldValue() - (Integer) e.getNewValue()),
scrollPane.getViewport().getHeight());
//Keep track of the current divider position
final int dividerPos = (Integer) e.getNewValue();
if (tabsExpanded && (dividerPos > collapsedSize)) {
expandedSize = dividerPos;
}
scaleAndRotate();
});
if (DecoderOptions.isRunningOnMac && UIManager.getLookAndFeel().isNativeLookAndFeel()) {
navOptionsPanel.addTab(pageTitle, thumbnails);
navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() - 1, pageTitle);
if (thumbnails.isShownOnscreen()) {
navOptionsPanel.addTab(bookmarksTitle, tree);
navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() - 1, bookmarksTitle);
}
} else {
//Remove borders from thumbnail and bookmark tab in windows as looks better
tree.setBorder(null);
thumbnails.setBorder(null);
if (thumbnails.isShownOnscreen()) {
final VTextIcon textIcon1 = new VTextIcon(navOptionsPanel, pageTitle);
navOptionsPanel.addTab(null, textIcon1, thumbnails);
}
final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, bookmarksTitle);
navOptionsPanel.addTab(null, textIcon2, tree);
}
String propValue = properties.getValue("startSideTabOpen");
if (!propValue.isEmpty()) {
sideTabBarOpenByDefault = "true".equalsIgnoreCase(propValue);
}
propValue = properties.getValue("startSelectedSideTab");
if (!propValue.isEmpty()) {
startSelectedTab = propValue;
}
if (!hasListener) {
hasListener = true;
navOptionsPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(final MouseEvent mouseEvent) {
handleTabbedPanes();
}
});
}
}
/**
* Sets up the position and visual style of the items on the bottom toolbar
* (page navigation buttons etc).
*/
private void setupBottomToolBarItems() {
pageCounter2.setEditable(true);
pageCounter2.setToolTipText(Messages.getMessage("PdfViewerTooltip.goto"));
pageCounter2.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(1, 1, 1, 1),
pageCounter2.getBorder()));
pageCounter2.setColumns(2);
pageCounter2.setMaximumSize(pageCounter2.getPreferredSize());
pageCounter2.addActionListener(arg0 -> {
String value = pageCounter2.getText().trim();
//Check if mapped and if so set the actual page number
//This is updated later to the correct page label
final PdfObjectReader reader = decode_pdf.getIO();
if (reader != null) {
final PageLabels pageLabels = reader.getPageLabels();
if (pageLabels != null && pageLabels.containsValue(value)) {
final Set<Map.Entry<Integer, String>> entries = pageLabels.entrySet();
for (final Map.Entry<Integer, String> e : entries) {
if (e.getValue().equals(value)) {
value = e.getKey().toString();
break;
}
}
}
}
currentCommands.executeCommand(ViewerCommands.GOTO, new Object[]{value});
});
pageCounter2.setHorizontalAlignment(JTextField.CENTER);
setPageNumber();
pageCounter3 = new JLabel(Messages.getMessage("PdfViewerOfLabel.text") + ' ');
pageCounter3.setOpaque(false);
navToolBar.setLayout(new BoxLayout(navToolBar, BoxLayout.LINE_AXIS));
navToolBar.setFloatable(false);
pagesToolBar.setFloatable(false);
navButtons.setBorder(BorderFactory.createEmptyBorder());
navButtons.setLayout(new BorderLayout());
navButtons.setFloatable(false);
navButtons.setPreferredSize(new Dimension(5, 24));
}
/**
* Creates a glowing border around the PDFDisplayPane.
*/
private void setupPDFBorder() {
//add a border
if (decode_pdf.useNewGraphicsMode()) {
decode_pdf.setPDFBorder(new AbstractBorder() {
@Override
public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
final Graphics2D g2 = (Graphics2D) g;
final int cornerDepth = (glowThickness / 2) + 1;
//left
g2.setPaint(new GradientPaint(x, 0, glowOuterColor, x + glowThickness, 0, glowInnerColor));
g2.fillRect(x, y + glowThickness, glowThickness, height - (glowThickness * 2));
//bottom left corner
g2.setPaint(new GradientPaint(x - cornerDepth + glowThickness, y + height + cornerDepth - glowThickness, glowOuterColor, x + glowThickness, y + height - glowThickness, glowInnerColor));
g2.fillRect(x, y + height - glowThickness, glowThickness, glowThickness);
//below
g2.setPaint(new GradientPaint(0, y + height, glowOuterColor, 0, y + height - glowThickness, glowInnerColor));
g2.fillRect(x + glowThickness, y + height - glowThickness, width - (glowThickness * 2), glowThickness);
//bottom right corner
g2.setPaint(new GradientPaint(x + width + cornerDepth - glowThickness, y + height + cornerDepth - glowThickness, glowOuterColor, x + width - glowThickness, y + height - glowThickness, glowInnerColor));
g2.fillRect(x + width - glowThickness, y + height - glowThickness, glowThickness, glowThickness);
//right
g2.setPaint(new GradientPaint(x + width, 0, glowOuterColor, x + width - glowThickness, 0, glowInnerColor));
g2.fillRect(x + width - glowThickness, y + glowThickness, glowThickness, height - (glowThickness * 2));
//top right corner
g2.setPaint(new GradientPaint(x + width - glowThickness + cornerDepth, y + glowThickness - cornerDepth, glowOuterColor, x + width - glowThickness, y + glowThickness, glowInnerColor));
g2.fillRect(x + width - glowThickness, y, glowThickness, glowThickness);
//above
g2.setPaint(new GradientPaint(0, y, glowOuterColor, 0, y + glowThickness, glowInnerColor));
g2.fillRect(x + glowThickness, y, width - (glowThickness * 2), glowThickness);
//top left corner
g2.setPaint(new GradientPaint(x - cornerDepth + glowThickness, y - cornerDepth + glowThickness, glowOuterColor, x + glowThickness, y + glowThickness, glowInnerColor));
g2.fillRect(x, y, glowThickness, glowThickness);
//draw black over top
g2.setPaint(Color.black);
g2.drawRect(x + glowThickness, y + glowThickness, width - (glowThickness * 2), height - (glowThickness * 2));
}
@Override
public Insets getBorderInsets(final Component c, final Insets insets) {
insets.set(glowThickness, glowThickness, glowThickness, glowThickness);
return insets;
}
});
} else {
decode_pdf.setPDFBorder(BorderFactory.createLineBorder(Color.black, 1));
}
}
/**
* Creates the top two menu bars, the file loading and viewer properties one
* and the PDF toolbar, the one which controls printing, searching etc.
*/
private void createTopMenuBar() {
top.setLayout(new BorderLayout());
if (frame instanceof JFrame) {
((RootPaneContainer) frame).getContentPane().add(top, BorderLayout.NORTH);
} else {
frame.add(top, BorderLayout.NORTH);
}
}
/**
* Ensure Document is redrawn when frame is resized and scaling set to
* width, height or window.
*/
private void redrawDocumentOnResize() {
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(final ComponentEvent e) {
if (((Component) decode_pdf).getParent() != null
&& (getSelectedComboIndex(Commands.SCALING) < 3 || decode_pdf.getDisplayView() == Display.FACING)) { //always rezoom in facing mode for turnover
scaleAndRotate();
}
}
});
}
/**
* Creates the Main Display Window for all of the Swing Content.
*
* @param width is of type int
* @param height is of type int
*/
private void createMainViewerWindow(final int width, final int height) {
if (frame instanceof JFrame) {
frame.setSize(width, height);
((Window) frame).setLocationRelativeTo(null); //centre on screen
((JFrame) frame).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
((Window) frame).addWindowListener(new FrameCloser(currentCommands, this, decode_pdf, thumbnails, commonValues, properties));
frame.setVisible(true);
}
}
/**
* Returns the RecentDocuments used to hand the recent document list
*
* @return RecentDocuments used by the user interface
*/
public RecentDocuments getRecentDocument() {
if (recent == null) {
recent = new RecentDocuments(PropertiesFile.getNoRecentDocumentsToDisplay());
}
return recent;
}
/**
* Create the RecentDocuments for the user interface
*/
public void setRecentDocument() {
recent = new RecentDocuments(PropertiesFile.getNoRecentDocumentsToDisplay());
}
/**
* Open a file in the Viewer
*
* @param fileToOpen String filename for the file to be opened
*/
public void openFile(final String fileToOpen) {
if (fileToOpen != null) {
OpenFile.open(fileToOpen, commonValues, searchFrame, this, decode_pdf, properties, thumbnails);
}
}
/**
* Open a file in the Viewer
*
* @param fileName String filename for the file to be opened
*/
public void open(final String fileName) {
OpenFile.open(fileName, commonValues, searchFrame, this, decode_pdf, properties, thumbnails);
}
/**
* Enable and make visible different parts of the page counter of all of it
*
* @param value PageCounter value for the different page counter elements
* @param enabled true to enable the counter section, false to disable.
* @param visibility true to make visible the counter section, false to disable.
*/
public void enablePageCounter(final PageCounter value, final boolean enabled, final boolean visibility) {
switch (value) {
case PAGECOUNTER1:
pageCounter1.setVisible(visibility);
pageCounter1.setEnabled(enabled);
break;
case PAGECOUNTER2:
pageCounter2.setVisible(visibility);
pageCounter2.setEnabled(enabled);
break;
case PAGECOUNTER3:
pageCounter3.setVisible(visibility);
pageCounter3.setEnabled(enabled);
break;
case ALL:
pageCounter1.setVisible(visibility);
pageCounter1.setEnabled(enabled);
pageCounter2.setVisible(visibility);
pageCounter2.setEnabled(enabled);
pageCounter3.setVisible(visibility);
pageCounter3.setEnabled(enabled);
break;
default:
System.out.println("No Value detected, please choose from Enum PageCounter in GUI.java");
break;
}
}
/**
* Set the text content for a section of the page counter.
*
* @param value PageCounter value for the different page counter elements
* @param text String value to be place in the page counter
*/
public void setPageCounterText(final PageCounter value, final String text) {
switch (value) {
case PAGECOUNTER1:
pageCounter1.setText(text);
break;
case PAGECOUNTER2:
pageCounter2.setText(text);
break;
case PAGECOUNTER3:
pageCounter3.setText(text);
break;
default:
System.out.println("No Value detected, please choose from Enum PageCounter in GUI.java");
break;
}
}
/**
* Get the page counter segments
*
* @param value PageCounter value for the different page counter elements
* @return an Object containing the section of the page counter
*/
public Object getPageCounter(final PageCounter value) {
switch (value) {
case PAGECOUNTER1:
return pageCounter1;
case PAGECOUNTER2:
return pageCounter2;
case PAGECOUNTER3:
return pageCounter3;
default:
System.out.println("No Value detected, please choose from Enum PageCounter in GUI.java");
return 0;
}
}
/**
* Update the page counter input size to accommodate the contents
*/
public void updateTextBoxSize() {
//Set textbox size
int col = (String.valueOf(commonValues.getPageCount())).length();
if (decode_pdf.getIO().getPageLabels() != null) {
final Collection<String> values = decode_pdf.getIO().getPageLabels().values();
for (final String value : values) {
final int length = value.length();
if (col < length) {
col = length;
}
}
}
if (decode_pdf.getDisplayView() == Display.FACING || decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING) {
col *= 2;
}
if (col < 2) {
col = 2;
}
pageCounter2.setColumns(col);
pageCounter2.setMaximumSize(pageCounter2.getPreferredSize());
navToolBar.invalidate();
navToolBar.doLayout();
}
/**
* Enable and or set visibility for the cursor display for multi box
*
* @param enabled true to enable, false to disable
* @param visible true to make visible, false to make invisible
*/
public void enableCursor(final boolean enabled, final boolean visible) {
cursor.setEnabled(enabled);
cursor.setVisible(visible);
}
/**
* Enable and or set visibility for the memory bar display for multi box
*
* @param enabled true to enable, false to disable
* @param visible true to make visible, false to make invisible
*/
public void enableMemoryBar(final boolean enabled, final boolean visible) {
multibox.setEnabled(enabled);
multibox.setVisible(visible);
}
/**
* Enable and or set visibility for the navigation bar
*
* @param enabled true to enable, false to disable
* @param visible true to make visible, false to make invisible
*/
public void enableNavigationBar(final boolean enabled, final boolean visible) {
navButtons.setEnabled(enabled);
navButtons.setVisible(visible);
}
/**
* Enable and or set visibility for the download display for multi box
*
* @param enabled true to enable, false to disable
* @param visible true to make visible, false to make invisible
*/
public void enableDownloadBar(final boolean enabled, final boolean visible) {
downloadBar.setEnabled(enabled);
downloadBar.setVisible(visible);
}
/**
* Get the current count of tabs on the side tab bar
*
* @return int value representing the number of tabs currently visible
*/
public int getSidebarTabCount() {
return navOptionsPanel.getTabCount();
}
/**
* Get the title of the tab at the given position
*
* @param pos The position of the tab on the tabbed pane
* @return String title of the given tab or an empty String is tab not present.
*/
public String getSidebarTabTitleAt(final int pos) {
if (navOptionsPanel.getIconAt(pos) != null) {
return navOptionsPanel.getIconAt(pos).toString();
} else {
return "";
}
}
/**
* Remove the tab at the specified position from the side tab bar
*
* @param pos Tab index to removed.
*/
public void removeSidebarTabAt(final int pos) {
navOptionsPanel.remove(pos);
}
/**
* Get the divider location for the viewer
*
* @return double representation of the divider location
*/
private double getDividerLocation() {
return displayPane.getDividerLocation();
}
/**
* calculates the scalingToFit required to make the given area visible
*
* @param left float value representing the smallest value on the x axis
* @param right float value representing the largest value on the x axis
* @param top float value representing the largest value on the y axis
* @param bottom float value representing the smallest value on the y axis
* @return float value representing the scalingToFit value
*/
public float scaleToVisible(final float left, final float right, final float top, final float bottom) {
float width = scrollPane.getViewport().getWidth() - inset - inset;
final float height = scrollPane.getViewport().getHeight() - inset - inset;
if (displayPane != null) {
width -= displayPane.getDividerSize();
}
final float widthScaling = (right - left) / width;
final float heightScaling = (top - bottom) / height;
if (widthScaling > heightScaling) {
return decode_pdf.getDPIFactory().adjustScaling(widthScaling);
} else {
return decode_pdf.getDPIFactory().adjustScaling(heightScaling);
}
}
/**
* Get the thickness of the glow border
*
* @return thickness of glow as an int
*/
public static int getDropShadowDepth() {
return glowThickness;
}
/**
* Set up the split pane divider for use
*
* @param size size of the divider
* @param visibility true to set left side of divider visible and enabled, false to set disabled and invisible
*/
public void setupSplitPaneDivider(final int size, final boolean visibility) {
displayPane.setDividerSize(size);
displayPane.getLeftComponent().setEnabled(visibility);
displayPane.getLeftComponent().setVisible(visibility);
}
/**
* Get the start / collapsed position of the split pane divider
*
* @return divider position as a double
*/
private static double getStartSize() {
return collapsedSize;
}
/**
* Set the start / collapsed position of the split pane divider
*
* @param size position as an int
*/
public static void setStartSize(final int size) {
collapsedSize = size;
}
/**
* Get the page container for the PDF display area
*
* @return JScrollPane containing the PdfDecoder
*/
public JScrollPane getPageContainer() {
return scrollPane;
}
/**
* Enable and or set visibility for the status bar for multi box
*
* @param enabled true to enable, false to disable
* @param visible true to make visible, false to make invisible
*/
public void enableStatusBar(final boolean enabled, final boolean visible) {
statusBar.setEnabled(enabled);
statusBar.setVisible(visible);
}
/**
* Converts mouse / components coords to pdf page coords
*
* @param x :: The x coordinate of the cursors location in display area coordinates
* @param y :: The y coordinate of the cursors location in display area coordinates
* @param page :: The page we are currently on
* @return Point object of the cursor location in page coordinates
*/
public Point convertComponentCoordsToPageCoords(final int x, final int y, final int page) {
return SwingMouseUtils.getCoordsOnPage(x, y, page, decode_pdf, this, commonValues);
}
/**
* Set the display view options to be used to display the PDF.
*
* @param displayView int value for display view from Display
* @param orientation int value for display orientation from Display
*/
public void setDisplayView(final int displayView, final int orientation) {
final int lastDisplayView = decode_pdf.getDisplayView();
if (decode_pdf.isOpen() && lastDisplayView != displayView) {
final PdfObject collectionObj = decode_pdf.getIO().getPDFObject(PdfDictionary.Collection);
if (displayView == Display.PORTFOLIO_DETAIL || displayView == Display.PORTFOLIO_TILE) {
if (collectionObj == null) {
//Incorrect mode for file type so cancel display view change
showMessageDialog(Messages.getMessage("PdfPortfolio.nonPortfolioIncorrectDisplay"));
return;
} else {
switch (displayView) {
case Display.PORTFOLIO_DETAIL:
setupDetailPortfolioView();
break;
case Display.PORTFOLIO_TILE:
setupTilePortfolioView();
break;
}
}
} else {
//Only set up pdf view if we were in a portfolio mode
if ((lastDisplayView == Display.PORTFOLIO_DETAIL || lastDisplayView == Display.PORTFOLIO_TILE)) {
setupPdfView();
}
}
}
//Check for null as can be called before UI is set up
if (annotationsPanel != null && SwingAnnotationPanel.addPanel()) {
annotationsPanel.getAnnotationListener().setFormMode(SwingAnnotationPanel.FORMMODE.CREATION);
}
// remove listener if setup
if (viewListener != null) {
((Component) decode_pdf).removeComponentListener(viewListener);
viewListener.dispose();
viewListener = null;
}
final boolean hasChanged = setDisplayView2(displayView, orientation);
//move to correct page
final int pageNumber = decode_pdf.getPageNumber();
if (pageNumber > 0 && hasChanged) {
try {
decode_pdf.setPageParameters(scaling, pageNumber, decode_pdf.getDisplayRotation());
((Component) decode_pdf).invalidate();
((JComponent) decode_pdf).updateUI();
decode_pdf.decodePage(pageNumber);
//Hide annotations tab if not needed
if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
checkTabShown(annotationTitle);
} else {
removeTab(annotationTitle);
}
} catch (final Exception e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
}
//Only all search in certain modes
enableSearchItems(displayView == Display.SINGLE_PAGE
|| displayView == Display.CONTINUOUS
|| displayView == Display.CONTINUOUS_FACING);
// add listener if one not already there
if (viewListener == null) {
viewListener = new RefreshLayout(decode_pdf);
((Component) decode_pdf).addComponentListener(viewListener);
}
}
public boolean allowScrolling() {
return allowScrolling;
}
public boolean confirmClose() {
return confirmClose;
}
public void toogleAutoScrolling() {
allowScrolling = !allowScrolling;
}
public int getRotation() {
return rotation;
}
public float getScaling() {
return scaling;
}
/**
* Get the values used by the GUI
*
* @return Values object to hold various details for the viewer
*/
public Values getValues() {
return commonValues;
}
private void addCombo(final String tooltip, final int ID) {
SwingCombo combo = null;
switch (ID) {
case Commands.SCALING:
combo = scalingBox;
break;
case Commands.ROTATION:
combo = rotationBox;
break;
}
if (combo != null) {
combo.setID(ID);
if (!tooltip.isEmpty()) {
combo.setToolTipText(tooltip);
addGUIComboBoxes(combo);
addComboListenerAndLabel(combo);
}
}
}
/**
* get Map containing Form Objects setup for Unique Annotations
*
* @return Map
*/
public Map<FormObject, String> getHotspots() {
return Collections.unmodifiableMap(objs);
}
/**
* example code which sets up an individual icon for each annotation to display - only use
* if you require each annotation to have its own icon<p>
* To use this you ideally need to parse the annotations first -there is a method allowing you to
* extract just the annotations from the data.
*/
private void createUniqueAnnotationIcons() {
//and place to store so we can test later
//flush list if needed
if (objs == null) {
objs = new HashMap<>();
} else {
objs.clear();
}
//create Annots - you can replace with your own implementation using setExternalHandler()
((AnnotationHandler) decode_pdf.getExternalHandler(Options.UniqueAnnotationHandler)).handleAnnotations(decode_pdf, objs, commonValues.getCurrentPage());
}
/**
* Set the dpi value used to adjust scaling
*
* @param dpi int value to represent the dpi
*/
private void setDpi(final int dpi) {
decode_pdf.getDPIFactory().setDpi(dpi);
}
/**
* Get the thickness of the glow border
*
* @return int value of the glow border thickness
*/
@SuppressWarnings("MethodMayBeStatic")
public int getGlowThickness() {
return glowThickness;
}
/**
* Get the outer colour of the glow border
*
* @return Color used for the outer section of the glow border
*/
public Color getGlowOuterColor() {
return glowOuterColor;
}
/**
* Get the inner colour of the glow border
*
* @return Color used for the inner section of the glow border
*/
public Color getGlowInnerColor() {
return glowInnerColor;
}
/**
* Set the search frame to be used as part of the user interface
*
* @param searchFrame SwingSearchWindow object to be used as the search window
*/
public void setSearchFrame(final SwingSearchWindow searchFrame) {
this.searchFrame = searchFrame;
}
private void setRotation() {
if (rotation > 360) {
rotation -= 360;
}
if (getSelectedComboIndex(Commands.ROTATION) != (rotation / 90)) {
setSelectedComboIndex(Commands.ROTATION, (rotation / 90));
}
}
/**
* Get selected index for the specified combo-box
*
* @param ID int value specifying a combo-box
* @return int value of the selected index in the given combo-box or -1 if ID is not valid
*/
public int getSelectedComboIndex(final int ID) {
switch (ID) {
case Commands.SCALING:
return scalingBox.getSelectedIndex();
case Commands.ROTATION:
return rotationBox.getSelectedIndex();
default:
return -1;
}
}
/**
* Set selected index for the specified combo-box
*
* @param ID int value specifying a combo-box
* @param index int value of the index to select
*/
public void setSelectedComboIndex(final int ID, final int index) {
switch (ID) {
case Commands.SCALING:
scalingBox.setSelectedIndex(index);
break;
case Commands.ROTATION:
rotationBox.setSelectedIndex(index);
break;
}
}
/**
* Get selected item for the specified combo-box
*
* @param ID int value specifying a combo-box
* @return Object representing the selected item or null if ID is not recognised
*/
public Object getSelectedComboItem(final int ID) {
switch (ID) {
case Commands.SCALING:
return scalingBox.getSelectedItem();
case Commands.ROTATION:
return rotationBox.getSelectedItem();
default:
return null;
}
}
/**
* Set selected item for the specified combo-box
*
* @param ID int value specifying a combo-box
* @param index String value of the item to select
*/
public void setSelectedComboItem(final int ID, String index) {
switch (ID) {
case Commands.SCALING:
//When using any of the fit scalings, adding a % will break it
//Only add if scaling is a number
if (StringUtils.isNumber(index)) {
index += '%';
}
scalingBox.setSelectedItem(index);
break;
case Commands.ROTATION:
rotationBox.setSelectedItem(index);
break;
}
}
private void prepareForDecode() {
//Remove Image extraction outlines when page is changed
decode_pdf.getPages().setHighlightedImage(null);
resetRotationBox();
/* if running terminate first */
if (thumbnails.isShownOnscreen()) {
thumbnails.terminateDrawing();
}
if (thumbnails.isShownOnscreen()) {
setupThumbnailPanel();
final LinearThread linearizedBackgroundRenderer = (LinearThread) decode_pdf.getJPedalObject(PdfDictionary.LinearizedReader);
if (linearizedBackgroundRenderer != null && !linearizedBackgroundRenderer.isAlive()) {
thumbnails.drawThumbnails();
}
}
if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
setPageCounterText(PageCounter.PAGECOUNTER2, getPageLabel(commonValues.getCurrentPage()));
if (pageLabelDiffers(commonValues.getCurrentPage())) {
setPageCounterText(PageCounter.PAGECOUNTER3, "(" + commonValues.getCurrentPage() + ' ' + Messages.getMessage("PdfViewerOfLabel.text") + ' ' + commonValues.getPageCount() + ')');
} else {
setPageCounterText(PageCounter.PAGECOUNTER3, Messages.getMessage("PdfViewerOfLabel.text") + ' ' + commonValues.getPageCount());
}
}
updateTextBoxSize();
//allow user to now open tabs
tabsNotInitialised = false;
//ensure text and color extracted. If you do not need color, take out line for faster decode
decode_pdf.setExtractionMode(PdfDecoderInt.TEXT + PdfDecoderInt.TEXTCOLOR);
//remove any search highlight
decode_pdf.getTextLines().clearHighlights();
}
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
private void performDecoding() {
Values.setProcessing(true);
setCursor(2);
if (LogWriter.isRunningFromIDE) {
start = System.currentTimeMillis();
}
try {
statusBar.updateStatus("Decoding Page", 0);
/*
* decode the page
*/
try {
decode_pdf.decodePage(commonValues.getCurrentPage());
final Object errorTracker = decode_pdf.getExternalHandler(Options.ErrorTracker);
if (debugMode && errorTracker instanceof LimitDecodeTrackerNoSwing) {
((LimitDecodeTrackerNoSwing) errorTracker).onPageChange();
}
//wait to ensure decoded
decode_pdf.waitForDecodingToFinish();
//value set from JVM flag org.jpedal.maxShapeCount=maxNumber
if (decode_pdf.getPageDecodeStatus(DecodeStatus.TooManyShapes)) {
final String status = "Too many shapes on page";
showMessageDialog(status);
}
if (!decode_pdf.getPageDecodeStatus(DecodeStatus.ImagesProcessed)) {
final String status = (Messages.getMessage("PdfViewer.ImageDisplayError") +
Messages.getMessage("PdfViewer.ImageDisplayError1") +
Messages.getMessage("PdfViewer.ImageDisplayError2") +
Messages.getMessage("PdfViewer.ImageDisplayError3") +
Messages.getMessage("PdfViewer.ImageDisplayError4") +
Messages.getMessage("PdfViewer.ImageDisplayError5") +
Messages.getMessage("PdfViewer.ImageDisplayError6") +
Messages.getMessage("PdfViewer.ImageDisplayError7"));
showMessageDialog(status);
}
/*
* Tell user if hinting is probably required
*/
if (decode_pdf.getPageDecodeStatus(DecodeStatus.TTHintingRequired)) {
final String status = Messages.getMessage("PdfCustomGui.ttHintingRequired");
showMessageDialog(status);
}
if (decode_pdf.getPageDecodeStatus(DecodeStatus.NonEmbeddedCIDFonts)) {
final String status = ("This page contains non-embedded CID fonts \n" +
decode_pdf.getPageDecodeStatusReport(DecodeStatus.NonEmbeddedCIDFonts) +
"\nwhich may need mapping to display correctly.\n" +
"See https://support.idrsolutions.com/jpedal/api-documents/pdf-fonts-how-they-work-and-how-they-can-be-displayed-in");
showMessageDialog(status);
}
//create custom annot icons
if (decode_pdf.getExternalHandler(Options.UniqueAnnotationHandler) != null) {
/*
* ANNOTATIONS code to create unique icons
*
* this code allows you to create a unique set on icons for any type of annotations, with
* an icons for every annotation, not just types.
*/
final FormFactory formfactory = decode_pdf.getFormRenderer().getFormFactory();
//swing needs it to be done with invokeLater
if (formfactory.getType() == FormFactory.SWING) {
final Runnable doPaintComponent2 = this::createUniqueAnnotationIcons;
SwingUtilities.invokeLater(doPaintComponent2);
} else {
createUniqueAnnotationIcons();
}
}
statusBar.updateStatus("Displaying Page", 0);
} catch (final Exception e) {
System.err.println(Messages.getMessage("PdfViewerError.Exception") + ' ' + e +
' ' + Messages.getMessage("PdfViewerError.DecodePage"));
LogWriter.writeLog(e);
Values.setProcessing(false);
}
//tell user if we had a memory error on decodePage
if (DecoderOptions.showErrorMessages) {
String status = decode_pdf.getPageDecodeReport();
if (status.contains("java.lang.OutOfMemoryError")) {
status = (Messages.getMessage("PdfViewer.OutOfMemoryDisplayError") +
Messages.getMessage("PdfViewer.OutOfMemoryDisplayError1") +
Messages.getMessage("PdfViewer.OutOfMemoryDisplayError2") +
Messages.getMessage("PdfViewer.OutOfMemoryDisplayError3") +
Messages.getMessage("PdfViewer.OutOfMemoryDisplayError4") +
Messages.getMessage("PdfViewer.OutOfMemoryDisplayError5"));
showMessageDialog(status);
}
}
Values.setProcessing(false);
setViewerTitle(); //restore title
if (LogWriter.isRunningFromIDE) {
/*
* show time and memory usage
*/
System.out
.println(((Runtime.getRuntime().totalMemory() - Runtime
.getRuntime().freeMemory()) / 1_000)
+ "K");
System.out.println((((float) Math.abs(((System
.currentTimeMillis() - start) / 100))) / 10)
+ "s");
}
if (decode_pdf.getPageCount() > 0 && thumbnails.isShownOnscreen() && decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
thumbnails.generateOtherVisibleThumbnails(commonValues.getCurrentPage());
}
} catch (final Exception e) {
LogWriter.writeLog(e);
Values.setProcessing(false); // Remove processing flag so that the viewer can be exited.
setViewerTitle(); //restore title
}
}
/**
* called by nav functions to decode next page (in GUI code as needs to
* manipulate large part of GUI)
*/
private void decodeGUIPage() {
//Prepare GUI for decoding
prepareForDecode();
//kick-off thread to create pages
switch (decode_pdf.getDisplayView()) {
case Display.FACING:
scaleAndRotate();
scrollToPage(commonValues.getCurrentPage());
decode_pdf.getPages().decodeOtherPages(commonValues.getCurrentPage());
return;
case Display.CONTINUOUS:
case Display.CONTINUOUS_FACING:
//resize (ensure at least certain size)
//must be here as otherwise will not redraw if new page opened
//in multipage mode
scaleAndRotate();
scrollToPage(commonValues.getCurrentPage());
return;
case Display.PAGEFLOW:
return;
default:
break;
}
//stop user changing scaling while decode in progress
resetComboBoxes(false);
swButtons.setPageLayoutButtonsEnabled(false);
//Decoding happens here
performDecoding();
//Update multibox
statusBar.setProgress(100);
setMultibox(new int[]{});
//reanable user changing scaling
resetComboBoxes(true);
if (decode_pdf.getPageCount() > 1) {
swButtons.setPageLayoutButtonsEnabled(true);
}
if (frame != null) {
reinitialiseTabs(getDividerLocation() > getStartSize());
}
finishedDecoding = true;
//Ensure page is at the correct scaling and rotation for display
scaleAndRotate();
setCursor(1);
}
public void setViewerTitle() {
String title;
if (commonValues.getSelectedFile() == null) {
title = (windowTitle + ' ');
} else {
title = (windowTitle + ' ' + commonValues.getSelectedFile());
}
final PdfObject linearObj = (PdfObject) decode_pdf.getJPedalObject(PdfDictionary.Linearized);
if (linearObj != null) {
final LinearThread linearizedBackgroundReaderer = (LinearThread) decode_pdf.getJPedalObject(PdfDictionary.LinearizedReader);
if (linearizedBackgroundReaderer != null && linearizedBackgroundReaderer.isAlive()) {
title += " (still loading)";
} else {
title += " (Linearized)";
}
}
if (commonValues.isFormsChanged()) {
title = "* " + title;
}
if (FileAccessHelper.bb > 0) {
title = "(" + FileAccessHelper.bb + " days left) " + title;
}
setTitle(title);
}
private void setupSidebarTitles() {
pageTitle = Messages.getMessage("PdfViewerJPanel.thumbnails");
bookmarksTitle = Messages.getMessage("PdfViewerJPanel.bookmarks");
layersTitle = Messages.getMessage("PdfViewerJPanel.layers");
signaturesTitle = Messages.getMessage("PdfViewerJPanel.signatures");
annotationTitle = Messages.getMessage("PdfViewerJPanel.annotations");
attachmentsTitle = Messages.getMessage("PdfViewerJPanel.attachments");
}
/**
* Get the label of the given page. PDFs can specify a label for a page
* (such as using Roman numerals), the method will return the page label if
* one exists, otherwise it will return the default of the page number.
*
* @param pageNumber int value to present the page number
* @return String value representing the page label for the page.
*/
public String getPageLabel(final int pageNumber) {
if (commonValues.isPDF()) { //Only check labels if pdf
final String value = decode_pdf.getIO().convertPageNumberToLabel(pageNumber);
if (value != null) {
return value;
}
}
return String.valueOf(pageNumber);
}
/**
* Get if the page label for a given page differs from the default page numbers
*
* @param pageNumber int value representing the page number
* @return true if the page label differs, false otherwise
*/
private boolean pageLabelDiffers(final int pageNumber) {
final PdfObjectReader reader = decode_pdf.getIO();
if (reader != null) {
final String value = reader.convertPageNumberToLabel(pageNumber);
if (value != null) {
return !value.equals(String.valueOf(pageNumber));
}
}
return false;
}
public void hideVersionNumber() {
windowTitle = "JPedal PDF workflow tools";
setViewerTitle();
}
public void showVersionNumber() {
windowTitle = Messages.getMessage("PdfViewer.titlebar") + ' ' + version;
setViewerTitle();
}
/**
* Generic ENUMS for setting Swing values.
*/
public enum ScrollPolicy {
VERTICAL_AS_NEEDED, HORIZONTAL_AS_NEEDED, VERTICAL_NEVER, HORIZONTAL_NEVER
}
public enum PageCounter {
PAGECOUNTER1, PAGECOUNTER2, PAGECOUNTER3, ALL
}
/**
* class to repaint multiple views
*/
private class RefreshLayout extends ComponentAdapter {
final PdfDecoderInt decode_pdf;
final PageMoveTracker tracker = new PageMoveTracker();
int delay = 500;
RefreshLayout(final PdfDecoderInt pdf) {
decode_pdf = pdf;
final String value = properties.getValue("pageMoveDelay");
if (value != null && !value.isEmpty()) {
delay = Integer.parseInt(value);
}
}
@Override
public void componentMoved(final ComponentEvent e) {
tracker.startTimer(decode_pdf.getPages(), decode_pdf.getPageNumber(), (FileAccess) decode_pdf.getExternalHandler(Options.FileAccess), delay);
}
@Override
public void componentResized(final ComponentEvent e) {
final int displayView = decode_pdf.getDisplayView();
final PdfPageData pageData = decode_pdf.getPdfPageData();
final int page = decode_pdf.getPageNumber();
if (displayView != Display.SINGLE_PAGE && displayView != Display.PAGEFLOW) {
final Rectangle r = decode_pdf.getVisibleRect();
if (!(pageData.getScaledCropBoxWidth(page) > r.width
|| pageData.getScaledCropBoxHeight(page) > r.height)) {
scrollToPage(page);
}
tracker.startTimer(decode_pdf.getPages(), decode_pdf.getPageNumber(), (FileAccess) decode_pdf.getExternalHandler(Options.FileAccess), delay);
}
}
//fix submitted by Niklas Matthies
void dispose() {
tracker.dispose();
}
}
/**
* Remove the ComponentListener from the PdfDecoder and flush cached pages
*/
public void removePageListener() {
// remove listener if not removed by close
if (viewListener != null) {
//flush any cached pages
decode_pdf.getPages().flushPageCaches();
((Component) decode_pdf).removeComponentListener(viewListener);
viewListener.dispose();
viewListener = null;
}
}
/**
* Trigger page turn in magazine mode. Not to be used in other display modes.
*
* @param decode_pdf PdfDecoder holder the PDF
* @param commonValues Values object holding PDF values
* @param updatedTotal New page total after page turn
* @param rightTurn true if turning page right, false if turning left
*/
public void triggerPageTurnAnimation(final PdfDecoderInt decode_pdf, final Values commonValues, final int updatedTotal, final boolean rightTurn) {
float pageW = decode_pdf.getPdfPageData().getCropBoxWidth(1);
float pageH = decode_pdf.getPdfPageData().getCropBoxHeight(1);
if (decode_pdf.getPdfPageData().getRotation(1) % 180 == 90) {
final float temp = pageW;
pageW = pageH;
pageH = temp;
}
final Point corner = new Point();
corner.x = (int) (decode_pdf.getVisibleRect().getWidth() / 2);
if (rightTurn) {
corner.x -= pageW;
} else {
corner.x += pageW;
}
corner.y = (int) (decode_pdf.getInsetH() + pageH);
final Point cursor = new Point();
cursor.x = (int) ((decode_pdf.getVisibleRect().getWidth() / 2) + pageW);
if (rightTurn) {
cursor.x += pageW;
} else {
cursor.x -= pageW;
}
cursor.y = (int) (decode_pdf.getInsetH() + pageH);
final SwingGUI currentGUI = this;
final Thread animation = new Thread(() -> {
// Fall animation
int velocity = 1;
//ensure cursor is not outside expected range
if (rightTurn ? cursor.x <= corner.x : cursor.x >= corner.x) {
cursor.x = corner.x - 1;
}
//Calculate distance required
final double distX = (corner.x - cursor.x);
//Loop through animation
while (rightTurn ? cursor.getX() >= corner.getX() : cursor.getX() <= corner.getX()) {
//amount to move this time
double xMove = velocity * distX * 0.001;
//make sure always moves at least 1 pixel in each direction
if ((rightTurn && xMove > -1)) {
xMove = -1;
} else {
if ((!rightTurn && xMove < 1)) {
xMove = 1;
}
}
cursor.setLocation(cursor.getX() + xMove, cursor.getY());
if (rightTurn) {
decode_pdf.setUserOffsets((int) cursor.getX(), (int) cursor.getY(), OffsetOptions.INTERNAL_DRAG_CURSOR_BOTTOM_RIGHT);
} else {
decode_pdf.setUserOffsets((int) cursor.getX(), (int) cursor.getY(), OffsetOptions.INTERNAL_DRAG_CURSOR_BOTTOM_LEFT);
}
//Double speed til moving 32/frame
if (velocity < 32) {
velocity *= 2;
}
//sleep til next frame
try {
Thread.sleep(50);
} catch (final InterruptedException e) {
LogWriter.writeLog(e);
}
}
//change page
commonValues.setCurrentPage(updatedTotal);
setPageNumber();
decode_pdf.setPageParameters(scaling, commonValues.getCurrentPage());
decodePage();
//unlock corner drag
PageNavigator.setPageTurnAnimating(false, currentGUI);
//hide turnover
decode_pdf.setUserOffsets(0, 0, OffsetOptions.INTERNAL_DRAG_BLANK);
});
animation.setDaemon(true);
//lock corner drag
PageNavigator.setPageTurnAnimating(true, this);
animation.start();
}
private void setCursor(final int type) {
if (type == 1) {
((Component) decode_pdf).setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
} else if (type == 2) {
((Component) decode_pdf).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
}
/**
* Not part of API - used internally
* set view mode used in panel and redraw in new mode
* SINGLE_PAGE,CONTINUOUS,FACING,CONTINUOUS_FACING delay is the time in
* milli-seconds which scrolling can stop before background page drawing
* starts Multipage views not in OS releases
*/
private boolean setDisplayView2(final int displayView, final int orientation) {
final DecoderOptions options = decode_pdf.getDecoderOptions();
Display pages = decode_pdf.getPages();
final FileAccess fileAccess = (FileAccess) decode_pdf.getExternalHandler(Options.FileAccess);
final int pageNumber = decode_pdf.getPageNumber();
final ExternalHandlers externalHandlers = decode_pdf.getExternalHandler();
final PdfDecoder comp = (PdfDecoder) decode_pdf;
final int lastDisplayView = decode_pdf.getDisplayView();
options.setPageAlignment(orientation);
if (pages != null) {
pages.stopGeneratingPage();
}
final boolean hasChanged = displayView != lastDisplayView;
options.setDisplayView(displayView);
if (lastDisplayView != displayView && lastDisplayView == Display.PAGEFLOW && pages != null) {
pages.dispose();
}
final Object customSwingHandle = externalHandlers.getExternalHandler(Options.MultiPageUpdate);
//Set the default value, may be replaced for pageflow as not needed
if (decode_pdf.getFormRenderer() != null) {
decode_pdf.getFormRenderer().getCompData().setRootDisplayComponent(decode_pdf);
}
switch (displayView) {
case Display.SINGLE_PAGE:
if (pages == null || hasChanged) {
final DynamicVectorRenderer currentDisplay = decode_pdf.getDynamicRenderer();
pages = new SingleDisplay(pageNumber, currentDisplay, comp, options); //abacus-del
}
break;
case Display.PAGEFLOW:
if (pages instanceof org.jpedal.display.swing.PageFlowDisplay) { //adode-del abacus-del
return hasChanged; //adode-del abacus-del
} //adode-del abacus-del
//Remove root display to prevent annotations being added behind page flow display
//Without this pageflow display will not resize with the viewer.
if (decode_pdf.getFormRenderer() != null) {
decode_pdf.getFormRenderer().getCompData().setRootDisplayComponent(null);
}
if (lastDisplayView != Display.SINGLE_PAGE) {
setDisplayView(Display.SINGLE_PAGE, 0);
setDisplayView(Display.PAGEFLOW, 0);
return hasChanged;
}
((JScrollPane) comp.getParent().getParent()).setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
((JScrollPane) comp.getParent().getParent()).setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
pages = new org.jpedal.display.swing.PageFlowDisplay((SwingGUI) customSwingHandle, decode_pdf); //adode-del abacus-del
break;
default:
pages = new MultiDisplay(pageNumber, null, displayView, comp, options, fileAccess); //adode-del abacus-del
//pass in value if needed
final RenderChangeListener customRenderChangeListener = (RenderChangeListener) externalHandlers.getExternalHandler(Options.RenderChangeListener);
if (customRenderChangeListener != null) {
pages.setObjectValue(Options.RenderChangeListener, customRenderChangeListener);
}
break;
}
//enable pageFlow mode and setup slightly different display configuration
if (lastDisplayView == Display.PAGEFLOW) {
comp.removeAll();
//forms needs null layout manager
comp.setLayout(null);
((JScrollPane) comp.getParent().getParent()).setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
((JScrollPane) comp.getParent().getParent()).setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
final javax.swing.Timer t = new javax.swing.Timer(1_000, e -> comp.repaint());
t.setRepeats(false);
t.start();
}
//setup once per page getting all page sizes and working out settings for views
if (fileAccess.getOffset() == null) {
fileAccess.setOffset(new PageOffsets(decode_pdf.getPageCount(), decode_pdf.getPdfPageData()));
}
pages.setup(options.useHardwareAcceleration(), fileAccess.getOffset());
final DynamicVectorRenderer currentDisplay = decode_pdf.getDynamicRenderer();
pages.init(scaling, decode_pdf.getDisplayRotation(), decode_pdf.getPageNumber(), currentDisplay, true);
pages.setPageRotation(decode_pdf.getDisplayRotation()); //force update //adode-del
pages.forceRedraw();
pages.refreshDisplay();
comp.pages = pages;
return hasChanged;
}
/**
* Get the glass panes used to allow annotations draw in the viewer for
* adding to the PDF.
*
* @return a JPanel to act as a glass pane.
*/
public JPanel getGlassPane() {
return glassPane;
}
private void setupTilePortfolioView() {
if (tileView == null) {
tileView = new SwingPortfolioTile(this);
}
tileView.loadCollectionValues(decode_pdf);
if (detailView != null) {
portfolioParent.remove(detailView);
}
if (tileView != null) {
portfolioParent.remove(tileView);
}
portfolioParent.remove(displayPane);
portfolioParent.add(tileView, BorderLayout.CENTER);
menuItems.getMenuItem(Commands.PORTFOLIO_TILES).setSelected(true);
menuItems.getMenuItem(Commands.PORTFOLIO_DETAIL).setSelected(false);
portfolioParent.repaint();
frame.validate();
}
private void setupDetailPortfolioView() {
if (detailView == null) {
detailView = new SwingPortfolioDetail(this);
}
detailView.loadCollectionValues(decode_pdf);
if (detailView != null) {
portfolioParent.remove(detailView);
}
if (tileView != null) {
portfolioParent.remove(tileView);
}
portfolioParent.remove(displayPane);
portfolioParent.add(detailView, BorderLayout.CENTER);
menuItems.getMenuItem(Commands.PORTFOLIO_TILES).setSelected(false);
menuItems.getMenuItem(Commands.PORTFOLIO_DETAIL).setSelected(true);
portfolioParent.repaint();
frame.validate();
}
private void setupPdfView() {
if (detailView != null) {
portfolioParent.remove(detailView);
}
if (tileView != null) {
portfolioParent.remove(tileView);
}
portfolioParent.remove(displayPane);
portfolioParent.add(displayPane, BorderLayout.CENTER);
portfolioParent.validate();
//Ensure display pane is displayed correctly
displayPane.repaint();
scaleAndRotate();
}
@SuppressWarnings({"OverlyLongMethod", "java:S138"})
public void setupGUIElementsForFiletype(final Values.FileType type) {
//Set Visibility of items (also check properties)
swButtons.getButton(Commands.ROTATELEFT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("RotateLeftbutton")));
swButtons.getButton(Commands.ROTATERIGHT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("RotateRightbutton")));
swButtons.getButton(Commands.ZOOMIN).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("ZoomInbutton")));
swButtons.getButton(Commands.ZOOMOUT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("ZoomOutbutton")));
swButtons.getButton(Commands.MOUSEMODE).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("MouseModeButton")));
swButtons.getButton(Commands.FIRSTPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Firstbottom")));
swButtons.getButton(Commands.FBACKPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Back10bottom")));
swButtons.getButton(Commands.BACKPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Backbottom")));
swButtons.getButton(Commands.FORWARDPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Forwardbottom")));
swButtons.getButton(Commands.FFORWARDPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Forward10bottom")));
swButtons.getButton(Commands.LASTPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Lastbottom")));
swButtons.getButton(Commands.SINGLE).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Singlebottom")));
swButtons.getButton(Commands.CONTINUOUS).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Continuousbottom")));
swButtons.getButton(Commands.FACING).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Facingbottom")));
swButtons.getButton(Commands.CONTINUOUS_FACING).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Continuousfacingbottom")));
swButtons.getButton(Commands.PAGEFLOW).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("PageFlowbottom")));
swButtons.getButton(Commands.PRINT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("Printbutton")));
swButtons.getButton(Commands.SNAPSHOT).setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Snapshotbutton")));
multibox.setVisible(type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Memorybottom")));
navButtons.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("ShowNavigationbar")));
//Handle Combo boxes
getCombo(Commands.SCALING).setVisibility((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("Scalingdisplay")));
getCombo(Commands.ROTATION).setVisibility((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("Rotationdisplay")));
final boolean showPageCounter = "true".equalsIgnoreCase(properties.getValue("Gotobottom"));
pageCounter1.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff())) && showPageCounter);
pageCounter2.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff())) && showPageCounter);
pageCounter3.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff())) && showPageCounter);
final boolean showMenubarSearch = "2".equalsIgnoreCase(properties.getValue("searchWindowType"));
swButtons.getButton(Commands.NEXTRESULT).setVisible(type == Values.FileType.PDF && showMenubarSearch);
swButtons.getButton(Commands.PREVIOUSRESULT).setVisible(type == Values.FileType.PDF && showMenubarSearch);
searchText.setVisible(type == Values.FileType.PDF);
if (options != null) {
options.setVisible(type == Values.FileType.PDF && showMenubarSearch);
}
navOptionsPanel.setVisible((type == Values.FileType.PDF)
&& "true".equalsIgnoreCase(properties.getValue("ShowSidetabbar")));
//No property for this value as always needed
menuItems.setMenuItemVisibility(Commands.PORTFOLIOMENU, type == Values.FileType.PORTFOLIO);
//Set enabled for items
menuItems.setMenuItemVisibility(Commands.SAVE, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Save")));
menuItems.setMenuItemVisibility(Commands.SAVEFORM, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Resaveasforms")));
menuItems.setMenuItemVisibility(Commands.DOCINFO, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Documentproperties")));
menuItems.setMenuItemVisibility(Commands.FIND, (type == Values.FileType.PDF)
&& "true".equalsIgnoreCase(properties.getValue("Find")));
menuItems.setMenuItemVisibility(Commands.PRINT, (type == Values.FileType.PDF)
&& "true".equalsIgnoreCase(properties.getValue("Print")));
menuItems.setMenuItemVisibility(Commands.SEPARATECOVER, (type == Values.FileType.PDF)
&& "true".equalsIgnoreCase(properties.getValue("separateCover")));
menuItems.setMenuItemVisibility(Commands.PANMODE, (type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("panMode")));
menuItems.setMenuItemVisibility(Commands.TEXTSELECT, (type == Values.FileType.PDF)
&& "true".equalsIgnoreCase(properties.getValue("textSelect")));
menuItems.setMenuItemVisibility(Commands.FULLSCREEN, (type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("Fullscreen")));
menuItems.setMenuItemVisibility(Commands.FIRSTPAGE, (type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Firstpage")));
menuItems.setMenuItemVisibility(Commands.BACKPAGE, (type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Backpage")));
menuItems.setMenuItemVisibility(Commands.GOTO, (type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Goto")));
menuItems.setMenuItemVisibility(Commands.FORWARDPAGE, (type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Forwardpage")));
menuItems.setMenuItemVisibility(Commands.LASTPAGE, (type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
&& "true".equalsIgnoreCase(properties.getValue("Lastpage")));
menuItems.setMenuItemVisibility(Commands.EDITMENU, (type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("EditMenu")));
menuItems.setMenuItemVisibility(Commands.PAGELAYOUTMENU, (type == Values.FileType.PDF || type == Values.FileType.IMAGES)
&& "true".equalsIgnoreCase(properties.getValue("PagelayoutMenu")));
menuItems.setMenuItemVisibility(Commands.COPY, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Copy")));
menuItems.setMenuItemVisibility(Commands.SELECTALL, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Selectall")));
menuItems.setMenuItemVisibility(Commands.DESELECTALL, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Deselectall")));
menuItems.setMenuItemVisibility(Commands.IMAGES, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Images")));
menuItems.setMenuItemVisibility(Commands.TEXT, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Text")));
menuItems.setMenuItemVisibility(Commands.CONTENTMENU, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("ContentMenu")));
menuItems.setMenuItemVisibility(Commands.BITMAP, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("Bitmap")));
menuItems.setMenuItemVisibility(Commands.EXPORTMENU, type == Values.FileType.PDF
&& "true".equalsIgnoreCase(properties.getValue("ExportMenu")));
menuItems.setMenuItemVisibility(Commands.XREF, type == Values.FileType.PDF
&& debugMode);
menuItems.setMenuItemVisibility(Commands.OBJECTS, type == Values.FileType.PDF
&& debugMode);
menuItems.setMenuItemVisibility(Commands.PORTFOLIOMENU, type == Values.FileType.PORTFOLIO);
if (type == Values.FileType.IMAGES) {
currentCommands.executeCommand(ViewerCommands.PANMODE, null);
} else {
currentCommands.executeCommand(ViewerCommands.TEXTSELECT, null);
}
//Check for double separaters and remove as needed
swButtons.checkButtonSeparators();
menuItems.checkMenuItemSeparators();
frame.revalidate();
}
public void setDebugMode(final boolean enableDebugMode) {
debugMode = enableDebugMode;
menuItems.setDebugMode(enableDebugMode);
imageNameCollector = new ImageNameCollector() {
final HashMap<String, String> names = new HashMap<>();
@Override
public void put(final String imageName, final String cacheName) {
names.put(decode_pdf.getPageNumber() + "-" + imageName, cacheName);
}
@Override
public String getCacheName(final String imageName) {
return names.get(decode_pdf.getPageNumber() + "-" + imageName);
}
@Override
public String getCacheNameFromIDToken(final int tokenNumber) {
final String prefix = decode_pdf.getPageNumber() + "-";
final String suffix = "-IN-" + tokenNumber;
for (final String name : names.keySet()) {
if (name.startsWith(prefix) && name.endsWith(suffix)) {
return names.get(name);
}
}
return null;
}
@Override
public boolean cacheAllToDisk() {
return true;
}
};
decode_pdf.setImageNameCollector(imageNameCollector);
}
}
|