/*
* Copyright (c) 1997-2024 IDRsolutions (https://www.idrsolutions.com)
*/
package org.jpedal.examples.viewer;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLightLaf;
import org.jpedal.PdfDecoder;
import org.jpedal.PdfDecoderInt;
import org.jpedal.examples.viewer.commands.OpenFile;
import org.jpedal.examples.viewer.gui.SwingGUI;
import org.jpedal.examples.viewer.gui.swing.SearchList;
import org.jpedal.examples.viewer.gui.swing.SwingSearchWindow;
import org.jpedal.examples.viewer.gui.swing.SwingThumbnailPanel;
import org.jpedal.examples.viewer.objects.SwingClientExternalHandler;
import org.jpedal.examples.viewer.utils.PropertiesFile;
import org.jpedal.exception.PdfException;
import org.jpedal.external.Options;
import org.jpedal.fonts.FontMappings;
import org.jpedal.grouping.PdfGroupingAlgorithms;
import org.jpedal.objects.acroforms.actions.ActionHandler;
import org.jpedal.objects.acroforms.actions.DefaultActionHandler;
import org.jpedal.objects.raw.OutlineObject;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.parser.DecoderOptions;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.Messages;
import org.w3c.dom.Node;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Arrays;
import java.util.ResourceBundle;
/**
* <h2><b>PDF Viewer</b></h2>
*
* <p><b>Run directly from jar with java -cp jpedal.jar org/jpedal/examples/viewer/Viewer</b></p>
*
* <p>There are plenty of tutorials on how to configure the Viewer on our website
* <a href="https://support.idrsolutions.com/jpedal/tutorials/viewer/">Support Section.</a></p>
*
* <p>If you want to implement your own there are tutorials at :
* <a href="https://support.idrsolutions.com/jpedal/tutorials/optional/">Customizing the Viewer</a></p>
* <p>We recommend you look at the full viewer as it is totally configurable and does everything for you.</p>
*
*
* <p>Fully featured GUI viewer and demonstration of JPedal's capabilities.</p>
*
* <p>This class provides the framework for the Viewer and calls other classes which provide the following
* functions:-</p>
* <ul>
* <li>Values commonValues - repository for general settings.</li>
* <li>PdfDecoder decode_pdf - PDF library and panel.</li>
* <li>SwingThumbnailPanel thumbnails - provides a thumbnail pane down the left side of page - thumbnails can be clicked on to goto page.</li>
* <li>PropertiesFile properties - saved values stored between sessions.</li>
* <li>SwingGUI currentGUI - all Swing GUI functions.</li>
* <li>SwingSearchWindow searchFrame (not GPL) - search Window to search pages and goto references on any page.</li>
* <li>SwingCommands currentCommands - parses and executes all options.</li>
* </ul>
*/
public class Viewer {
static {
FlatDarkLaf.installLafInfo();
FlatDarculaLaf.installLafInfo();
FlatIntelliJLaf.installLafInfo();
FlatLightLaf.installLafInfo();
}
//repository for general settings
private Values commonValues = new Values();
//PDF library and panel
PdfDecoderInt decode_pdf;
//encapsulates all thumbnail functionality - just ignore if not required
private SwingThumbnailPanel thumbnails;
//values saved on file between sessions
private PropertiesFile properties = new PropertiesFile();
//general GUI functions
SwingGUI currentGUI;
//search window and functionality
private SwingSearchWindow searchFrame;
//command functions
private Commands currentCommands;
//warn user if viewer not setup fully
private boolean isSetup;
//tell software to exit on close - default is true
public static boolean exitOnClose = true;
//Throw runtime exception when user tries to open document after close() has been called
public static boolean closeCalled;
/**
* setup and run client
*/
public Viewer() {
final String prefFile = System.getProperty("org.jpedal.Viewer.Prefs");
if (prefFile != null) {
properties.loadProperties(prefFile);
} else {
properties.loadProperties();
}
init();
//enable error messages which are OFF by default
DecoderOptions.showErrorMessages = true;
}
/**
* setup and run client passing in parameter that points to the preferences file we should use. preferences file
*
* @param rootContainer Is a swing component that the viewer is displayed inside
* @param preferencesPath The path of the preferences file
*/
public Viewer(final javax.accessibility.Accessible rootContainer, final String preferencesPath) {
if (preferencesPath != null && !preferencesPath.isEmpty()) {
try {
properties.loadProperties(preferencesPath);
} catch (final Exception e) {
System.err.println("Specified Preferrences file not found at " + preferencesPath + ". If this file is within a jar ensure filename has jar: at the begining.\n\nLoading default properties. " + e);
properties.loadProperties();
}
} else {
properties.loadProperties();
}
init();
//enable error messages which are OFF by default
DecoderOptions.showErrorMessages = true;
setRootContainer(rootContainer);
}
/**
* setup and run client passing in paramter that points to the preferences file we should use.
*
* @param prefs Full path to xml file containing preferences
*/
public Viewer(final String prefs) {
try {
properties.loadProperties(prefs);
} catch (final Exception e) {
System.err.println("Specified Preferrences file not found at " + prefs + ". If this file is within a jar ensure filename has jar: at the begining.\n\nLoading default properties. " + e);
properties.loadProperties();
}
init();
//enable error messages which are OFF by default
DecoderOptions.showErrorMessages = true;
}
/**
* setup and run client
*
* @param enableDebugMode Run the client in debug mode
*/
@SuppressWarnings("SameParameterValue")
private Viewer(final boolean enableDebugMode) {
if (enableDebugMode) {
//Disable most menu options
properties.loadDebugProperties();
} else {
final String prefFile = System.getProperty("org.jpedal.Viewer.Prefs");
if (prefFile != null) {
properties.loadProperties(prefFile);
} else {
properties.loadProperties();
}
}
init();
//Allow debug menu items to appear
currentGUI.setDebugMode(enableDebugMode);
//enable error messages which are OFF by default
DecoderOptions.showErrorMessages = true;
}
private void init() {
// Make sure this is called before initialising the components
String lafOption = System.getProperty("org.jpedal.userControlledLAF");
//checking that the using is using the correctly spelled version of the flag
final String altLafOption = System.getProperty("org.jpedal.userControledLAF");
if (altLafOption != null && !altLafOption.isEmpty()) {
lafOption = altLafOption;
}
if (lafOption != null && !lafOption.isEmpty()) {
if (!"true".equalsIgnoreCase(lafOption)) {
if ("false".equalsIgnoreCase(lafOption)) {
setLookAndFeel();
} else {
try {
UIManager.setLookAndFeel(lafOption);
} catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException ex) {
currentGUI.showMessageDialog("Exception " + ex + " could not be found. LookAndFeel not set.");
}
}
}
} else {
final String laf = properties.getValue("viewerLookAndFeel");
if (!laf.isEmpty()) {
if ("SystemDefault".equals(laf) || !Arrays.toString(UIManager.getInstalledLookAndFeels()).contains(laf)) {
setLookAndFeel();
} else {
try {
UIManager.setLookAndFeel(laf);
} catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException ex) {
LogWriter.writeLog("Exception " + ex + " setting look and feel to viewerLookAndFeel value");
}
}
}
}
//switch on if not set by user
if (System.getProperty("org.jpedal.viewerLargeImageCaching") == null) {
System.setProperty("org.jpedal.viewerLargeImageCaching", "true");
}
decode_pdf = new PdfDecoder(true);
thumbnails = new SwingThumbnailPanel(decode_pdf);
currentGUI = new SwingGUI(decode_pdf, commonValues, thumbnails, properties);
decode_pdf.addExternalHandler(new DefaultActionHandler(currentGUI), Options.FormsActionHandler);
decode_pdf.addExternalHandler(new SwingClientExternalHandler(), Options.AdditionalHandler);
searchFrame = new SwingSearchWindow(currentGUI);
currentCommands = new Commands(commonValues, currentGUI, decode_pdf,
thumbnails, properties, searchFrame);
}
/**
* set the look and feel for the GUI components to be the default for the system it is running on
*/
private static void setLookAndFeel() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (final ClassNotFoundException | IllegalAccessException | InstantiationException
| UnsupportedLookAndFeelException e) {
LogWriter.writeLog("Exception " + e + " setting look and feel");
}
}
/**
* Get the search results from a search performing in the Viewer. This is how users searching from a Viewer object
* can retrieve results if they wish to use them outside of the Viewer.
*
* @return SearchList object containing the current search results list
*/
@SuppressWarnings("unused")
public SearchList getSearchResults() {
return currentCommands.getSearchList();
}
/**
* main method to run the software as standalone application
*
* @param args Program arguments passed into the Viewer.
*/
@SuppressWarnings("unused")
public static void main(final String[] args) {
final Viewer current = new Viewer();
current.setupViewer();
current.handleArguments(args);
}
/**
* run the viewer in debug mode
*
* @param args Program arguments passed into the Viewer
*/
public static void debug(final String[] args) {
final Viewer current = new Viewer(true);
current.setupViewer();
current.handleArguments(args);
}
/**
* open the file passed in by user on startup (do not call directly) USED by our tests
*
* @return the current gui
*/
public SwingGUI getSwingGUI() {
return currentGUI;
}
/**
* @param defaultFile Allow user to open PDF file to display
*/
public void openDefaultFile(final String defaultFile) {
//reset flag
if (thumbnails.isShownOnscreen()) {
thumbnails.resetToDefault();
}
commonValues.maxViewY = 0; // Ensure reset for any viewport
// Open any default file and selected page
if (defaultFile != null) {
final File testExists = new File(defaultFile);
boolean isURL = false;
if (defaultFile.startsWith("http:") || defaultFile.startsWith("jar:") || defaultFile.startsWith("file:")) {
LogWriter.writeLog("Opening http connection");
isURL = true;
}
if ((!isURL) && (!testExists.exists())) {
currentGUI.showMessageDialog(defaultFile + '\n' + Messages.getMessage("PdfViewerdoesNotExist.message"));
} else if ((!isURL) && (testExists.isDirectory())) {
currentGUI.showMessageDialog(defaultFile + '\n' + Messages.getMessage("PdfViewerFileIsDirectory.message"));
} else {
commonValues.setFileSize(testExists.length() >> 10);
commonValues.setSelectedFile(defaultFile);
currentGUI.setViewerTitle();
//see if user set Page
final String page = System.getProperty("org.jpedal.page");
final String bookmark = System.getProperty("org.jpedal.bookmark");
if (page != null && !isURL) {
try {
int pageNum = Integer.parseInt(page);
if (pageNum < 1) {
pageNum = -1;
System.err.println(page + " must be 1 or larger. Opening on page 1");
LogWriter.writeLog(page + " must be 1 or larger. Opening on page 1");
}
if (pageNum != -1) {
openFile(testExists, pageNum);
}
} catch (final NumberFormatException e) {
System.err.println(page + "is not a valid number for a page number. Opening on page 1 " + e);
LogWriter.writeLog(page + "is not a valid number for a page number. Opening on page 1");
}
} else if (bookmark != null) {
openFile(testExists, bookmark);
} else {
currentGUI.openFile(defaultFile);
}
}
}
}
/**
* @param defaultFile Allow user to open PDF file to display
*/
private void openDefaultFileAtPage(final String defaultFile, final int page) {
//reset flag
if (thumbnails.isShownOnscreen()) {
thumbnails.resetToDefault();
}
commonValues.maxViewY = 0; // Ensure reset for any viewport
//open any default file and selected page
if (defaultFile != null) {
final File testExists = new File(defaultFile);
boolean isURL = false;
if (defaultFile.startsWith("http:") || defaultFile.startsWith("jar:")) {
LogWriter.writeLog("Opening http connection");
isURL = true;
}
if ((!isURL) && (!testExists.exists())) {
currentGUI.showMessageDialog(defaultFile + '\n' + Messages.getMessage("PdfViewerdoesNotExist.message"));
} else if ((!isURL) && (testExists.isDirectory())) {
currentGUI.showMessageDialog(defaultFile + '\n' + Messages.getMessage("PdfViewerFileIsDirectory.message"));
} else {
commonValues.setSelectedFile(defaultFile);
commonValues.setFileSize(testExists.length() >> 10);
currentGUI.setViewerTitle();
openFile(testExists, page);
}
}
}
public PdfDecoderInt getPdfDecoder() {
return decode_pdf;
}
public void setRootContainer(final Object rootContainer) {
currentGUI.setRootContainer(rootContainer);
}
/**
* Should be called before setupViewer
*
* @param props path to the properties file to load
*/
public void loadProperties(final String props) {
properties.loadProperties(props);
}
/**
* initialise and run client (default as Application in own Frame)
*/
public void setupViewer() {
//also allow messages to be suppressed with JVM option
final String flag = System.getProperty("org.jpedal.suppressViewerPopups");
boolean suppressViewerPopups = false;
if ("true".equalsIgnoreCase(flag)) {
suppressViewerPopups = true;
}
//set search window position here to ensure that gui has correct value
final String searchType = properties.getValue("searchWindowType");
if (searchType != null && !searchType.isEmpty()) {
final int type = Integer.parseInt(searchType);
searchFrame.setViewStyle(type);
} else {
searchFrame.setViewStyle(SwingSearchWindow.SEARCH_MENU_BAR);
}
searchFrame.setUpdateListDuringSearch("true".equals(properties.getValue("updateResultsDuringSearch")));
//Set search frame here
currentGUI.setSearchFrame(searchFrame);
//switch on thumbnails if flag set
final String setThumbnail = System.getProperty("org.jpedal.thumbnail");
if (setThumbnail != null) {
if ("true".equals(setThumbnail)) {
thumbnails.setThumbnailsEnabled(true);
} else if ("false".equals(setThumbnail)) {
thumbnails.setThumbnailsEnabled(false);
}
} else { //default
thumbnails.setThumbnailsEnabled(true);
}
final String customBundle = System.getProperty("org.jpedal.bundleLocation");
final ResourceBundle bundle;
if (customBundle != null) {
final String fileName = customBundle.replaceAll("\\.", "/") + '_' + java.util.Locale.getDefault().getLanguage() + ".properties";
final URL resource = Messages.class.getResource(fileName);
if (resource != null) {
bundle = ResourceBundle.getBundle(customBundle);
} else {
java.util.Locale.setDefault(new java.util.Locale("en", "EN"));
currentGUI.showMessageDialog("No locale file " + fileName + " has been defined for this Locale - using English as Default" +
"\n Format is path, using '.' as break ie org.jpedal.international.messages");
bundle = null;
}
} else {
bundle = null;
}
init(bundle);
//gui setup, create gui, load properties
currentGUI.init(currentCommands);
if (searchFrame.getViewStyle() == SwingSearchWindow.SEARCH_TABBED_PANE) {
currentGUI.searchInTab(searchFrame);
}
String propValue = properties.getValue("showfirsttimepopup");
final boolean showFirstTimePopup = !suppressViewerPopups && !propValue.isEmpty() && "true".equals(propValue);
if (showFirstTimePopup) {
currentGUI.showFirstTimePopup();
properties.setValue("showfirsttimepopup", "false");
}
propValue = properties.getValue("displaytipsonstartup");
if (!suppressViewerPopups && !propValue.isEmpty() && "true".equals(propValue)) {
currentCommands.executeCommand(ViewerCommands.TIP, null);
}
//flag so we can warn user if they call executeCommand without it setup
isSetup = true;
}
/**
* setup the viewer
*/
private void init(final ResourceBundle bundle) {
//load correct set of messages
if (bundle == null) {
//load locale file
try {
Messages.setBundle(ResourceBundle.getBundle("org.jpedal.international.messages"));
} catch (final Exception e) {
LogWriter.writeLog(e);
LogWriter.writeLog("Exception " + e + " loading resource bundle.\n" +
"Also check you have a file in org.jpedal.international.messages to support Locale=" + java.util.Locale.getDefault());
}
} else {
try {
Messages.setBundle(bundle);
} catch (final Exception ee) {
LogWriter.writeLog("Exception with bundle " + bundle);
LogWriter.writeLog(ee);
}
}
//pass through GUI for use in multipages and Javascript
decode_pdf.addExternalHandler(currentGUI, Options.MultiPageUpdate);
//make sure widths in data CRITICAL if we want to split lines correctly!!
DecoderOptions.embedWidthData = true;
//set to extract all
//COMMENT OUT THIS LINE IF USING JUST THE VIEWER
decode_pdf.setExtractionMode(0, 1); //values extraction mode,dpi of images, dpi of page as a factor of 72
//mappings for non-embedded fonts to use
FontMappings.setFontReplacements();
}
/**
* Have the viewer handle program arguments
*
* @param args :: Program arguments passed into the Viewer.
*/
void handleArguments(final String[] args) {
//Ensure default open is on event thread, otherwise the display is updated as values are changing
if (SwingUtilities.isEventDispatchThread()) {
if (args.length > 0) {
openDefaultFile(args[0]);
} else if (("true".equalsIgnoreCase(properties.getValue("openLastDocument")))
&& (properties.getRecentDocuments() != null
&& properties.getRecentDocuments().length > 1)) {
int lastPageViewed = Integer.parseInt(properties.getValue("lastDocumentPage"));
if (lastPageViewed < 0) {
lastPageViewed = 1;
}
openDefaultFileAtPage(properties.getRecentDocuments()[0], lastPageViewed);
}
} else {
final Runnable run = () -> {
if (args.length > 0) {
openDefaultFile(args[0]);
} else if ("true".equalsIgnoreCase(properties.getValue("openLastDocument"))
&& properties.getRecentDocuments() != null
&& properties.getRecentDocuments().length > 1) {
int lastPageViewed = Integer.parseInt(properties.getValue("lastDocumentPage"));
if (lastPageViewed < 0) {
lastPageViewed = 1;
}
openDefaultFileAtPage(properties.getRecentDocuments()[0], lastPageViewed);
}
};
try {
SwingUtilities.invokeAndWait(run);
} catch (InterruptedException | InvocationTargetException e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
}
}
/**
* General code to open file at specified boomark - do not call directly
*
* @param file File the PDF to be decoded
* @param bookmark - if not present, exception will be thrown
*/
private void openFile(final File file, final String bookmark) {
try {
final boolean fileCanBeOpened = OpenFile.openUpFile(file.getCanonicalPath(), commonValues, searchFrame, currentGUI, decode_pdf, properties, thumbnails);
String bookmarkPage = null;
int page = -1;
//reads tree and populates lookup table
if (decode_pdf.getOutlineAsXML() != null) {
final Node rootNode = decode_pdf.getOutlineAsXML().getFirstChild();
if (rootNode != null) {
bookmarkPage = currentGUI.getBookmark(bookmark);
}
if (bookmarkPage != null) {
page = Integer.parseInt(bookmarkPage);
}
}
//it may be a named destination ( ie bookmark=Test1)
if (bookmarkPage == null) {
bookmarkPage = decode_pdf.getIO().convertNameToRef(bookmark);
if (bookmarkPage != null) {
//read the object
final PdfObject namedDest = new OutlineObject(bookmarkPage);
decode_pdf.getIO().readObject(namedDest);
//still needed to init viewer
if (fileCanBeOpened) {
OpenFile.processPage(commonValues, decode_pdf, currentGUI, thumbnails);
}
//and generic open Dest code
decode_pdf.getFormRenderer().getActionHandler().gotoDest(namedDest, ActionHandler.MOUSECLICKED, PdfDictionary.Dest);
}
}
if (bookmarkPage == null) {
throw new PdfException("Unknown bookmark " + bookmark);
}
if (page > -1) {
commonValues.setCurrentPage(page);
if (fileCanBeOpened) {
OpenFile.processPage(commonValues, decode_pdf, currentGUI, thumbnails);
}
}
} catch (final IOException | PdfException | NumberFormatException e) {
LogWriter.writeLog(e);
Values.setProcessing(false);
}
}
/**
* General code to open file at specified page - do not call directly
*
* @param file File the PDF to be decoded
* @param page int page number to show the user
*/
private void openFile(final File file, final int page) {
try {
final boolean fileCanBeOpened = OpenFile.openUpFile(file.getCanonicalPath(), commonValues, searchFrame, currentGUI, decode_pdf, properties, thumbnails);
commonValues.setCurrentPage(page);
if (fileCanBeOpened) {
OpenFile.processPage(commonValues, decode_pdf, currentGUI, thumbnails);
}
} catch (final IOException | PdfException e) {
LogWriter.writeLog(e);
Values.setProcessing(false);
}
}
/**
* Execute Jpedal functionality from outside the library using this method.
* <p>
* EXAMPLES<br>
* commandID = Commands.OPENFILE, args = {"/PDFData/Hand_Test/crbtrader.pdf}"<br>
* commandID = Commands.OPENFILE, args = {byte[] = {0,1,1,0,1,1,1,0,0,1}, "/PDFData/Hand_Test/crbtrader.pdf}"<br>
* commandID = Commands.ROTATION, args = {"90"}<br>
* commandID = Commands.OPENURL, args = {"http://www.cs.bham.ac.uk/~axj/pub/papers/handy1.pdf"}
* <p>
* for full details see
* https://support.idrsolutions.com/jpedal/tutorials/viewer/access-pdf-viewer-features-from-your-code
*
* @param commandID :: static int value from Commands to specify which command is wanted
* @param args :: arguments for the desired command
*
* @return any returned value from executed command
* @deprecated use {@link #executeCommand(ViewerCommands, Object[])} instead.
*/
@Deprecated
@SuppressWarnings("UnusedReturnValue")
public Object executeCommand(final int commandID, final Object[] args) {
//far too easy to miss this step (I did!) so warn user
if (!isSetup) {
throw new RuntimeException("You must call viewer.setupViewer(); before you call any commands");
}
final ViewerCommands command = ViewerCommands.createFromID(commandID);
if (command != null) {
return currentCommands.executeCommand(command, args);
} else {
LogWriter.writeLog("Command for ID value " + commandID + " does not exist.");
return null;
}
}
/**
* Execute Jpedal functionality from outside the library using this method.
* <p>
* EXAMPLES <br>
* command = Command.OPENFILE, args = {"/PDFData/Hand_Test/crbtrader.pdf}"<br>
* command = Command.OPENFILE, args = {byte[] = {0,1,1,0,1,1,1,0,0,1}, "/PDFData/Hand_Test/crbtrader.pdf}"<br>
* command = Command.ROTATION, args = {"90"}<br>
* command = Command.OPENURL, args = {"http://www.cs.bham.ac.uk/~axj/pub/papers/handy1.pdf"}
* <p>
* for full details see
* https://support.idrsolutions.com/jpedal/tutorials/viewer/access-pdf-viewer-features-from-your-code
*
* @param command :: enum value from ViewerCommands to specify which command is wanted
* @param args :: arguments for the desired command
*
* @return any returned value from executed command
*/
public Object executeCommand(final ViewerCommands command, final Object... args) {
if (!isSetup) {
throw new RuntimeException("You must call viewer.setupViewer(); before you call any commands");
}
return currentCommands.executeCommand(command, args);
}
/**
* Query the Viewer for the values it holds.
*
* @param value :: enum value from ViewerValues to specify which value is wanted
*
* @return any returned value or null
*/
public Object getViewerValue(final ViewerValues value) {
if (!isSetup) {
throw new RuntimeException("You must call viewer.setupViewer(); before query and values");
}
return currentCommands.getValue(value);
}
/**
* Get the outline panel.
*
* @return the returned object is a SwingOutline panel
*/
public Object getOutlinePanel() {
return currentGUI.getOutlinePanel();
}
/**
* Get the thumbnail panel.
*
* @return the returned object is a SwingThumbnailPanel
*/
public SwingThumbnailPanel getThumbnailPanel() {
return currentGUI.getThumbnailPanel();
}
/**
* Get the page grouping.
*
* @param pageNumber the page number
*
* @return the PdfGrouping object for the page to access text content
*/
public Object getPageGrouping(final int pageNumber) {
PdfGroupingAlgorithms grouping = null;
if (pageNumber == decode_pdf.getlastPageDecoded()) {
try {
grouping = decode_pdf.getGroupingObject();
} catch (final PdfException e) {
LogWriter.writeLog(e);
}
} else {
try {
decode_pdf.decodePageInBackground(pageNumber);
grouping = decode_pdf.getBackgroundGroupingObject();
} catch (final Exception e) {
LogWriter.writeLog(e);
}
}
//ensure done
decode_pdf.waitForDecodingToFinish();
return grouping;
}
/**
* Get the page counter
*
* @return the returned object is a JTextField
*/
public Object getPageCounter() {
return currentGUI.getPageCounter(SwingGUI.PageCounter.PAGECOUNTER2);
}
/**
* Allows external helper classes to be added to JPedal to alter default functionality.
* <br><br>If Options.FormsActionHandler is the type then the <b>newHandler</b> should be
* of the form <b>org.jpedal.objects.acroforms.ActionHandler</b>
* <br><br>If Options.JPedalActionHandler is the type then the <b>newHandler</b> should be
* of the form <b>Map</b> which contains Command Integers, mapped onto their respective
* <b>org.jpedal.examples.viewer.gui.swing.JPedalActionHandler</b> implementations. For example,
* to create a custom help action, you would add to your map, Integer(Commands.HELP) -> JPedalActionHandler. For
* a tutorial on creating custom actions in the Viewer, see
* <b>https://support.idrsolutions.com/jpedal/api-documents/custom-interfaces</b>
*
* @param newHandler Implementation of interface provided by IDR solutions
* @param type Defined value into org.jpedal.external.Options class
*/
public void addExternalHandler(final java.util.Map<Integer, Object> newHandler, final int type) {
decode_pdf.addExternalHandler(newHandler, type);
}
/**
* run with caution and only at end of usage if you really need
*/
public void dispose() {
commonValues = null;
if (thumbnails != null) {
thumbnails.dispose();
}
thumbnails = null;
if (properties != null) {
properties.dispose();
}
properties = null;
if (currentGUI != null) {
currentGUI.dispose();
}
currentGUI = null;
searchFrame = null;
currentCommands = null;
if (decode_pdf != null) {
decode_pdf.dispose();
}
decode_pdf = null;
Messages.dispose();
}
}
|