All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.icepdf.ri.common.SwingController Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2006-2019 ICEsoft Technologies Canada Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS
 * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.icepdf.ri.common;

import org.icepdf.core.SecurityCallback;
import org.icepdf.core.exceptions.PDFSecurityException;
import org.icepdf.core.io.SizeInputStream;
import org.icepdf.core.pobjects.*;
import org.icepdf.core.pobjects.actions.Action;
import org.icepdf.core.pobjects.actions.GoToAction;
import org.icepdf.core.pobjects.actions.URIAction;
import org.icepdf.core.pobjects.annotations.Annotation;
import org.icepdf.core.pobjects.annotations.MarkupAnnotation;
import org.icepdf.core.pobjects.annotations.PopupAnnotation;
import org.icepdf.core.pobjects.security.Permissions;
import org.icepdf.core.search.DocumentSearchController;
import org.icepdf.core.util.*;
import org.icepdf.core.util.updater.WriteMode;
import org.icepdf.ri.common.preferences.PreferencesDialog;
import org.icepdf.ri.common.print.PrintHelper;
import org.icepdf.ri.common.print.PrintHelperFactory;
import org.icepdf.ri.common.print.PrintHelperFactoryImpl;
import org.icepdf.ri.common.print.PrinterTask;
import org.icepdf.ri.common.properties.FontDialog;
import org.icepdf.ri.common.properties.InformationDialog;
import org.icepdf.ri.common.properties.PermissionsDialog;
import org.icepdf.ri.common.properties.PropertiesDialog;
import org.icepdf.ri.common.search.DocumentSearchControllerImpl;
import org.icepdf.ri.common.utility.annotation.AnnotationFilter;
import org.icepdf.ri.common.utility.annotation.AnnotationPanel;
import org.icepdf.ri.common.utility.annotation.properties.AnnotationPropertiesDialog;
import org.icepdf.ri.common.utility.attachment.AttachmentPanel;
import org.icepdf.ri.common.utility.layers.LayersPanel;
import org.icepdf.ri.common.utility.outline.OutlineItemTreeNode;
import org.icepdf.ri.common.utility.search.SearchPanel;
import org.icepdf.ri.common.utility.search.SearchToolBar;
import org.icepdf.ri.common.utility.signatures.SignaturesHandlerPanel;
import org.icepdf.ri.common.utility.thumbs.ThumbnailsPanel;
import org.icepdf.ri.common.views.*;
import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent;
import org.icepdf.ri.common.views.annotations.MarkupAnnotationComponent;
import org.icepdf.ri.common.views.annotations.summary.AnnotationSummaryFrame;
import org.icepdf.ri.common.views.destinations.DestinationComponent;
import org.icepdf.ri.common.widgets.AbstractColorButton;
import org.icepdf.ri.common.widgets.annotations.AnnotationColorToggleButton;
import org.icepdf.ri.util.*;
import org.icepdf.ri.viewer.WindowManager;

import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.PrintQuality;
import javax.swing.Timer;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.icepdf.core.util.PropertyConstants.ANNOTATION_COLOR_PROPERTY_PANEL_CHANGE;
import static org.icepdf.ri.common.KeyEventConstants.*;
import static org.icepdf.ri.util.ViewerPropertiesManager.*;


/**
 * Controller is the meat of a PDF viewing application. It is the Controller
 * aspect of the Model-View-Controller (MVC) framework.
*
* Controller acts as a bridge between a Swing user interface, as built by * SwingViewerBuilder; the Document class, which is the root accessor to the PDF content; * and the ViewerModel, which maintains the state of the user's perspective of said Document. * * @author Mark Collette * @see SwingViewBuilder * @see org.icepdf.core.pobjects.Document * @see ViewModel * @since 2.0 */ public class SwingController extends ComponentAdapter implements org.icepdf.ri.common.views.Controller, ActionListener, FocusListener, ItemListener, TreeSelectionListener, WindowListener, DropTargetListener, PropertyChangeListener { protected static final Logger logger = Logger.getLogger(SwingController.class.toString()); private static final boolean USE_JFILECHOOSER; static { USE_JFILECHOOSER = Defs.booleanProperty("org.icepdf.ri.viewer.jfilechooser", false); } private static final boolean IS_READONLY = Defs.booleanProperty("org.icepdf.ri.viewer.readonly", false); public static final int CURSOR_OPEN_HAND = 1; public static final int CURSOR_CLOSE_HAND = 2; public static final int CURSOR_ZOOM_IN = 3; public static final int CURSOR_ZOOM_OUT = 4; public static final int CURSOR_WAIT = 6; public static final int CURSOR_SELECT = 7; public static final int CURSOR_DEFAULT = 8; protected static final int MAX_SELECT_ALL_PAGE_COUNT = 250; private JMenuItem openFileMenuItem; private JMenu recentFilesSubMenu; private JMenuItem openURLMenuItem; private JMenuItem closeMenuItem; private JMenuItem saveFileMenuItem; private JMenuItem saveAsFileMenuItem; private JMenuItem exportDocumentFileMenuItem; private JMenuItem sendMailMenuItem; private JMenuItem exportTextMenuItem; private JMenuItem propertiesMenuItem; private JMenuItem permissionsMenuItem; private JMenuItem preferencesMenuItem; private JMenuItem informationMenuItem; private JMenuItem fontInformationMenuItem; private JMenuItem printSetupMenuItem; private JMenuItem printMenuItem; private JMenuItem exitMenuItem; private JMenuItem undoMenuItem; private JMenuItem redoMenuItem; private JMenuItem copyMenuItem; private JMenuItem copyContextMenuItem; private JMenuItem deleteMenuItem; private JMenuItem selectAllMenuItem; private JMenuItem deselectAllMenuItem; private JMenuItem fitActualSizeMenuItem; private JMenuItem fitPageMenuItem; private JMenuItem fitWidthMenuItem; private JMenuItem fullScreenMenuItem; private JMenuItem zoomInMenuItem; private JMenuItem zoomOutMenuItem; private JMenuItem rotateLeftMenuItem; private JMenuItem rotateRightMenuItem; private JMenuItem showHideToolBarMenuItem; private JMenuItem showHideUtilityPaneMenuItem; private JMenuItem firstPageMenuItem; private JMenuItem previousPageMenuItem; private JMenuItem nextPageMenuItem; private JMenuItem lastPageMenuItem; private JMenuItem searchMenuItem; private JMenuItem advancedSearchMenuItem; private JMenuItem searchNextMenuItem; private JMenuItem searchPreviousMenuItem; private JMenuItem goToPageMenuItem; private JMenuItem minimiseAllMenuItem; private JMenuItem bringAllToFrontMenuItem; private JMenuItem annotationPreviewMenuItem; private List windowListMenuItems; private JMenuItem aboutMenuItem; private JButton openFileButton; private JButton saveFileButton; private JButton printButton; private JButton searchButton; private JToggleButton showHideUtilityPaneButton; private JButton showAnnotationUtilityPaneButton; private JButton showBookmarkUtilityPaneButton; private JButton firstPageButton; private JButton previousPageButton; private JButton nextPageButton; private JButton lastPageButton; private JTextField currentPageNumberTextField; private JLabel numberOfPagesLabel; private JButton zoomInButton; private JButton zoomOutButton; private JComboBox zoomComboBox; private JComboBox annotationPrivacyComboBox; private JToggleButton fitActualSizeButton; private JToggleButton fitHeightButton; private JToggleButton fitWidthButton; private JButton fullScreenButton; private JToggleButton facingPageViewContinuousButton; private JToggleButton singlePageViewContinuousButton; private JToggleButton facingPageViewNonContinuousButton; private JToggleButton singlePageViewNonContinuousButton; private JButton rotateLeftButton; private JButton rotateRightButton; private JToggleButton panToolButton; private JToggleButton textSelectToolButton; private JToggleButton zoomInToolButton; private JToggleButton zoomDynamicToolButton; private JToggleButton selectToolButton; // main annotation toolbar private JButton deleteAllAnnotationsButton; private AnnotationColorToggleButton highlightAnnotationToolButton; private JToggleButton redactionAnnotationToolButton; private JToggleButton linkAnnotationToolButton; private AnnotationColorToggleButton strikeOutAnnotationToolButton; private AnnotationColorToggleButton underlineAnnotationToolButton; private AnnotationColorToggleButton lineAnnotationToolButton; private AnnotationColorToggleButton lineArrowAnnotationToolButton; private AnnotationColorToggleButton squareAnnotationToolButton; private AnnotationColorToggleButton circleAnnotationToolButton; private AnnotationColorToggleButton inkAnnotationToolButton; private JToggleButton freeTextAnnotationToolButton; private AnnotationColorToggleButton textAnnotationToolButton; private JButton annotationSummaryButton; private JToggleButton annotationEditingModeButton; private JToggleButton formHighlightButton; // search toolbar private JToolBar quickSearchToolBar; // annotation properties toolbar. private JToggleButton linkAnnotationPropertiesToolButton; private JToggleButton highlightAnnotationPropertiesToolButton; private JToggleButton strikeOutAnnotationPropertiesToolButton; private JToggleButton underlineAnnotationPropertiesToolButton; private JToggleButton lineAnnotationPropertiesToolButton; private JToggleButton lineArrowAnnotationPropertiesToolButton; private JToggleButton squareAnnotationPropertiesToolButton; private JToggleButton circleAnnotationPropertiesToolButton; private JToggleButton inkAnnotationPropertiesToolButton; private JToggleButton freeTextAnnotationPropertiesToolButton; private JToggleButton textAnnotationPropertiesToolButton; private JToolBar completeToolBar; // annotation summary view. private AnnotationSummaryFrame annotationSummaryFrame; // Printing in background thread monitors private ProgressMonitor printProgressMonitor; private Timer printActivityMonitor; private JTree outlinesTree; private JScrollPane outlinesScrollPane; private SearchPanel searchPanel; private AttachmentPanel attachmentPanel; private ThumbnailsPanel thumbnailsPanel; private LayersPanel layersPanel; private SignaturesHandlerPanel signaturesPanel; protected AnnotationPanel annotationPanel; protected JTabbedPane utilityTabbedPane; protected JSplitPane utilityAndDocumentSplitPane; private int utilityAndDocumentSplitPaneLastDividerLocation; private JLabel statusLabel; private Frame viewer; protected WindowManagementCallback windowManagementCallback; // simple model for swing controller, mainly printer and file loading state. protected ViewModel viewModel; // sub controller for document view or document page views. protected DocumentViewControllerImpl documentViewController; // sub controller for document text searching. protected DocumentSearchController documentSearchController; protected Document document; protected boolean disposed; // internationalization messages, loads message for default JVM locale. protected static ResourceBundle messageBundle = null; protected ViewerPropertiesManager propertiesManager; private String saveFilePath = null; static { PrintHelper.preloadServices(); } /** * Create a Controller object, and its associated ViewerModel * * @see ViewModel */ public SwingController() { this(null); } public SwingController(ResourceBundle currentMessageBundle) { viewModel = new ViewModel(); // page view controller documentViewController = new DocumentViewControllerImpl(this); // document search controller. documentSearchController = new DocumentSearchControllerImpl(this); // register Property change listeners, for zoom, rotation, current page changes documentViewController.addPropertyChangeListener(this); // load the resource bundle using the default local if (currentMessageBundle != null) { SwingController.messageBundle = currentMessageBundle; } else { SwingController.messageBundle = ResourceBundle.getBundle( ViewerPropertiesManager.DEFAULT_MESSAGE_BUNDLE); } } /** * Sets a custom document view controller. Previously constructed documentView controllers are unregistered * from the propertyChangeListener, the provided controller will be registered with the propertyChangeListener. * * @param documentViewController new document controller. */ public void setDocumentViewController(DocumentViewControllerImpl documentViewController) { if (this.documentViewController != null) { this.documentViewController.removePropertyChangeListener(this); } this.documentViewController = documentViewController; // register Property change listeners, for zoom, rotation, current page changes documentViewController.addPropertyChangeListener(this); } /** * Gets controller responsible for the page multiple page views. * * @return page view controller. */ public DocumentViewController getDocumentViewController() { return documentViewController; } /** * Gets controller responsible for the document text searches. * * @return page view controller. */ public DocumentSearchController getDocumentSearchController() { return documentSearchController; } /** * Gets the message bundle used by this class. Message bundle resources * are loaded via the JVM default locale. * * @return message bundle used by this class. */ public ResourceBundle getMessageBundle() { return messageBundle; } /** * The WindowManagementCallback is used for creating new Document windows, * and quitting the application * * @param wm The new WindowManagementCallback * @see #getWindowManagementCallback */ public void setWindowManagementCallback(WindowManagementCallback wm) { windowManagementCallback = wm; } /** * The WindowManagementCallback is used for creating new Document windows, * and quitting the application * * @return The current WindowManagementCallback * @see #setWindowManagementCallback */ public WindowManagementCallback getWindowManagementCallback() { return windowManagementCallback; } /** * Called by SwingViewerBuilder, so that Controller has access to all properties * * @param propertiesManager current properties manager instance. */ public void setPropertiesManager(ViewerPropertiesManager propertiesManager) { this.propertiesManager = propertiesManager; } /** * Gets an instance of the PropertiesManager so that other builders can use the properties manager. */ public ViewerPropertiesManager getPropertiesManager() { return propertiesManager; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setOpenFileMenuItem(JMenuItem mi) { openFileMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setRecentFilesSubMenu(JMenu mi) { recentFilesSubMenu = mi; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setOpenURLMenuItem(JMenuItem mi) { openURLMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setCloseMenuItem(JMenuItem mi) { closeMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSaveFileMenuItem(JMenuItem mi) { saveFileMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSaveAsFileMenuItem(JMenuItem mi) { saveAsFileMenuItem = mi; mi.addActionListener(this); } public void setExportDocumentFileMenuItem(JMenuItem mi) { exportDocumentFileMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSendMailMenuItem(JMenuItem mi) { sendMailMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setExportTextMenuItem(JMenuItem mi) { exportTextMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setPermissionsMenuItem(JMenuItem mi) { permissionsMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setPropertiesMenuItem(JMenuItem mi) { propertiesMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setInformationMenuItem(JMenuItem mi) { informationMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setFontInformationMenuItem(JMenuItem mi) { fontInformationMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setPrintSetupMenuItem(JMenuItem mi) { printSetupMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setPrintMenuItem(JMenuItem mi) { printMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setExitMenuItem(JMenuItem mi) { exitMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setUndoMenuItem(JMenuItem mi) { undoMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setReduMenuItem(JMenuItem mi) { redoMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setCopyMenuItem(JMenuItem mi) { copyMenuItem = mi; mi.addActionListener(this); } public void setCopyContextMenuItem(JMenuItem mi) { if (copyContextMenuItem != null) { copyContextMenuItem.removeActionListener(this); } copyContextMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setDeleteMenuItem(JMenuItem mi) { deleteMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSelectAllMenuItem(JMenuItem mi) { selectAllMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setDeselectAllMenuItem(JMenuItem mi) { deselectAllMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setPreferencesMenuItem(JMenuItem mi) { preferencesMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setFitActualSizeMenuItem(JMenuItem mi) { fitActualSizeMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setFitPageMenuItem(JMenuItem mi) { fitPageMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setFitWidthMenuItem(JMenuItem mi) { fitWidthMenuItem = mi; mi.addActionListener(this); } public void setFullScreenMenuItem(JMenuItem mi) { fullScreenMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setZoomInMenuItem(JMenuItem mi) { zoomInMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setZoomOutMenuItem(JMenuItem mi) { zoomOutMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setRotateLeftMenuItem(JMenuItem mi) { rotateLeftMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setRotateRightMenuItem(JMenuItem mi) { rotateRightMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setShowHideToolBarMenuItem(JMenuItem mi) { showHideToolBarMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setShowHideUtilityPaneMenuItem(JMenuItem mi) { showHideUtilityPaneMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setFirstPageMenuItem(JMenuItem mi) { firstPageMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setPreviousPageMenuItem(JMenuItem mi) { previousPageMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setNextPageMenuItem(JMenuItem mi) { nextPageMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setLastPageMenuItem(JMenuItem mi) { lastPageMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSearchMenuItem(JMenuItem mi) { searchMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerbuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setAdvancedSearchMenuItem(JMenuItem mi) { advancedSearchMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSearchNextMenuItem(JMenuItem mi) { searchNextMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setSearchPreviousMenuItem(JMenuItem mi) { searchPreviousMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setGoToPageMenuItem(JMenuItem mi) { goToPageMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setMinimiseAllMenuItem(JMenuItem mi) { minimiseAllMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setBringAllToFrontMenuItem(JMenuItem mi) { bringAllToFrontMenuItem = mi; mi.addActionListener(this); } public void setAnnotationPreviewMenuItem(JMenuItem mi) { annotationPreviewMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param menuItems menu item of opened windows. */ public void setWindowListMenuItems(List menuItems) { windowListMenuItems = menuItems; int count = (windowListMenuItems != null) ? windowListMenuItems.size() : 0; for (int i = 0; i < count; i++) { JMenuItem mi = (JMenuItem) windowListMenuItems.get(i); mi.addActionListener(this); } } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param mi menu item to assign */ public void setAboutMenuItem(JMenuItem mi) { aboutMenuItem = mi; mi.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setOpenFileButton(JButton btn) { openFileButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setSaveFileButton(JButton btn) { saveFileButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setPrintButton(JButton btn) { printButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setSearchButton(JButton btn) { searchButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setShowHideUtilityPaneButton(JToggleButton btn) { showHideUtilityPaneButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setShowAnnotationUtilityPaneButton(JButton btn) { showAnnotationUtilityPaneButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setShowBookmarkUtilityPaneButton(JButton btn) { showBookmarkUtilityPaneButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setFirstPageButton(JButton btn) { firstPageButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setPreviousPageButton(JButton btn) { previousPageButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setNextPageButton(JButton btn) { nextPageButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLastPageButton(JButton btn) { lastPageButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param textField current page number text field value. */ public void setCurrentPageNumberTextField(JTextField textField) { currentPageNumberTextField = textField; currentPageNumberTextField.addActionListener(this); currentPageNumberTextField.addFocusListener(this); currentPageNumberTextField.addKeyListener(new NumberTextFieldKeyListener()); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param lbl number of pages label. */ public void setNumberOfPagesLabel(JLabel lbl) { numberOfPagesLabel = lbl; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setZoomOutButton(JButton btn) { zoomOutButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param zcb zoom level combo box values. * @param zl default zoom level. */ public void setZoomComboBox(JComboBox zcb, float[] zl) { zoomComboBox = zcb; documentViewController.setZoomLevels(zl); zoomComboBox.setSelectedItem(NumberFormat.getPercentInstance().format(1.0)); zoomComboBox.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setZoomInButton(JButton btn) { zoomInButton = btn; btn.addActionListener(this); } public void setAnnotationPermissionComboBox(JComboBox zcb) { annotationPrivacyComboBox = zcb; zcb.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setFitActualSizeButton(JToggleButton btn) { fitActualSizeButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setFitHeightButton(JToggleButton btn) { fitHeightButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setFitWidthButton(JToggleButton btn) { fitWidthButton = btn; btn.addItemListener(this); } public void setFullScreenButton(JButton btn) { fullScreenButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setRotateLeftButton(JButton btn) { rotateLeftButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setRotateRightButton(JButton btn) { rotateRightButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setPanToolButton(JToggleButton btn) { panToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setZoomInToolButton(JToggleButton btn) { zoomInToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setTextSelectToolButton(JToggleButton btn) { textSelectToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setSelectToolButton(JToggleButton btn) { selectToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLinkAnnotationToolButton(JToggleButton btn) { this.linkAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setStrikeOutAnnotationToolButton(AnnotationColorToggleButton btn) { this.strikeOutAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setUnderlineAnnotationToolButton(AnnotationColorToggleButton btn) { this.underlineAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLineAnnotationToolButton(AnnotationColorToggleButton btn) { this.lineAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLineArrowAnnotationToolButton(AnnotationColorToggleButton btn) { this.lineArrowAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setSquareAnnotationToolButton(AnnotationColorToggleButton btn) { this.squareAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setCircleAnnotationToolButton(AnnotationColorToggleButton btn) { this.circleAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setInkAnnotationToolButton(AnnotationColorToggleButton btn) { this.inkAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setFreeTextAnnotationToolButton(JToggleButton btn) { this.freeTextAnnotationToolButton = btn; btn.addItemListener(this); } public void setAnnotationSummaryButton(JButton btn) { this.annotationSummaryButton = btn; btn.addActionListener(this); } public void setAnnotationEditingModeToolButton(JToggleButton btn) { this.annotationEditingModeButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setDeleteAllButton(final JButton btn) { deleteAllAnnotationsButton = btn; btn.addActionListener(e -> { documentViewController.getDocumentViewModel().getPageComponents().forEach(pvc -> { final List comps = ((PageViewComponentImpl) pvc).getAnnotationComponents(); if (comps != null) { final Collection toDelete = comps.stream().filter(comp -> comp instanceof MarkupAnnotationComponent && ((MarkupAnnotation) comp.getAnnotation()).isCurrentUserOwner()).collect(Collectors.toSet()); documentViewController.deleteAnnotations(toDelete); reflectUndoCommands(); } }); }); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLinkAnnotationPropertiesToolButton(JToggleButton btn) { linkAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setHighlightAnnotationToolButton(AnnotationColorToggleButton btn) { highlightAnnotationToolButton = btn; btn.addItemListener(this); } public void setRedactionAnnotationToolButton(JToggleButton btn) { redactionAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setHighlightAnnotationPropertiesToolButton(JToggleButton btn) { highlightAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setStrikeOutAnnotationPropertiesToolButton(JToggleButton btn) { strikeOutAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setUnderlineAnnotationPropertiesToolButton(JToggleButton btn) { underlineAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLineAnnotationPropertiesToolButton(JToggleButton btn) { lineAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setLineArrowAnnotationPropertiesToolButton(JToggleButton btn) { lineArrowAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setSquareAnnotationPropertiesToolButton(JToggleButton btn) { squareAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setCircleAnnotationPropertiesToolButton(JToggleButton btn) { circleAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setInkAnnotationPropertiesToolButton(JToggleButton btn) { inkAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setFreeTextAnnotationPropertiesToolButton(JToggleButton btn) { freeTextAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setTextAnnotationToolButton(AnnotationColorToggleButton btn) { textAnnotationToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * for the form highlight button. * * @param btn button to assign */ public void setFormHighlightButton(JToggleButton btn) { formHighlightButton = btn; btn.addActionListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup enabled/disabled state * * @param toolBar toolBar to assign */ public void setQuickSearchToolBar(JToolBar toolBar) { quickSearchToolBar = toolBar; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setTextAnnotationPropertiesToolButton(JToggleButton btn) { textAnnotationPropertiesToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param btn button to assign */ public void setZoomDynamicToolButton(JToggleButton btn) { zoomDynamicToolButton = btn; btn.addItemListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param toolbar assignment of complete toolbar. */ public void setCompleteToolBar(JToolBar toolbar) { completeToolBar = toolbar; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param tree outline tree component * @param scroll outline scroll parent. */ public void setOutlineComponents(JTree tree, JScrollPane scroll) { outlinesTree = tree; outlinesScrollPane = scroll; outlinesTree.addTreeSelectionListener(this); } public JTree getOutlineTree() { return outlinesTree; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param sp search panel */ public void setSearchPanel(SearchPanel sp) { searchPanel = sp; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param atp attachment panel */ public void setAttachmentPanel(AttachmentPanel atp) { attachmentPanel = atp; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param tn thumbnails panel. */ public void setThumbnailsPanel(ThumbnailsPanel tn) { thumbnailsPanel = tn; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param tn layers panel. */ public void setLayersPanel(LayersPanel tn) { layersPanel = tn; } public void setSignaturesPanel(SignaturesHandlerPanel tn) { signaturesPanel = tn; } public void setAnnotationPanel(AnnotationPanel lp) { annotationPanel = lp; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param util utility tabbed pane. */ public void setUtilityTabbedPane(JTabbedPane util) { utilityTabbedPane = util; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param embeddableComponent indicates usage of component viewer. */ public void setIsEmbeddedComponent(boolean embeddableComponent) { if (embeddableComponent) { if (documentViewController.getDocumentView() != null) { prepareKeyMap((JComponent) documentViewController.getDocumentView()); } else if (documentViewController.getViewContainer() != null) { prepareKeyMap((JComponent) documentViewController.getViewContainer()); } } else { prepareKeyMap((JComponent) documentViewController.getViewContainer()); } } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param splitPane main split pain that divides utility from page view pane. */ public void setUtilityAndDocumentSplitPane(JSplitPane splitPane) { utilityAndDocumentSplitPane = splitPane; // default is to hide the tabbed pane on first load. setUtilityPaneVisible(false); // add the valueChangeListener. utilityAndDocumentSplitPane.addPropertyChangeListener(this); } /** * Called by SwingViewerBuilder, so that Controller can setup event handling * * @param lbl status label value. */ public void setStatusLabel(JLabel lbl) { statusLabel = lbl; } /** * Called by SwingViewerBuilder, so that Controller can setup event handling. * * @param v paren view frame. */ public void setViewerFrame(Frame v) { viewer = v; viewer.addWindowListener(this); viewer.addComponentListener(this); if (windowManagementCallback == null) { // apply last opened window location WindowManager.newWindowLocation(viewer); } // add drag and drop listeners new DropTarget(viewer, // component DnDConstants.ACTION_COPY_OR_MOVE, // actions this); // DropTargetListener reflectStateInComponents(); } /** * Not all uses of Controller would result in there existing a Viewer Frame, * so this may well return null. */ public Frame getViewerFrame() { return viewer; } /** * Tests to see if the PDF document is a collection and should be treated as such. * * @return true if PDF collection otherwise false. */ public boolean isPdfCollection() { Catalog catalog = document.getCatalog(); HashMap collection = catalog.getCollection(); if (collection != null) { // one final check as some docs will have meta data but will specify a page mode. // check to see that at least one of the files is a PDF if (catalog.getEmbeddedFilesNameTree() != null) { NameTree embeddedFilesNameTree = catalog.getEmbeddedFilesNameTree(); java.util.List filePairs = embeddedFilesNameTree.getNamesAndValues(); boolean found = false; if (filePairs != null) { Library library = catalog.getLibrary(); // check to see if at least one file is a PDF. for (int i = 0, max = filePairs.size(); i < max; i += 2) { // get the name and document for // file name and file specification pairs. String fileName = Utils.convertStringObject(library, (StringObject) filePairs.get(i)); if (fileName != null && fileName.toLowerCase().endsWith(".pdf")) { found = true; break; } } } return found; } } return false; } /** * Utility method to set the state of all the different GUI elements. Mainly * to enable/disable the GUI elements when a file is opened/closed respectively. */ protected void reflectStateInComponents() { boolean opened = document != null; boolean pdfCollection = opened && isPdfCollection(); int nPages = (getPageTree() != null) ? getPageTree().getNumberOfPages() : 0; // get security information for printing and text extraction boolean canPrint = havePermissionToPrint(); boolean canExtract = havePermissionToExtractContent(); boolean canModify = havePermissionToModifyDocument(); // check if full scren is available boolean canDoFullScreen = false; try { GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice defaultScreenDevice = graphicsEnvironment.getDefaultScreenDevice(); if (defaultScreenDevice != null && defaultScreenDevice.isFullScreenSupported()) { canDoFullScreen = true; } } catch (Exception e) { // quiet eat exception as we are only concerned if we have full screen support. } reflectPageChangeInComponents(); // menu items. setEnabled(closeMenuItem, opened); setEnabled(saveFileMenuItem, opened && !IS_READONLY); setEnabled(saveAsFileMenuItem, opened); setEnabled(exportDocumentFileMenuItem, opened); setEnabled(sendMailMenuItem, opened); setEnabled(exportTextMenuItem, opened && canExtract && !pdfCollection); setEnabled(propertiesMenuItem, opened); setEnabled(permissionsMenuItem, opened); setEnabled(informationMenuItem, opened); setEnabled(fontInformationMenuItem, opened); // Printer setup is global to all PDFs, so don't limit it by this one PDF setEnabled(printSetupMenuItem, opened && canPrint && !pdfCollection); setEnabled(printMenuItem, opened && canPrint && !pdfCollection); // set initial sate for undo/redo edit, afterwards state is set by // valueChange events depending on tool selection. setEnabled(undoMenuItem, false); setEnabled(redoMenuItem, false); setEnabled(copyMenuItem, false); setEnabled(deleteMenuItem, false); setEnabled(selectAllMenuItem, opened && canExtract && !pdfCollection); setEnabled(deselectAllMenuItem, false); setEnabled(fitActualSizeMenuItem, opened && !pdfCollection); setEnabled(fitPageMenuItem, opened && !pdfCollection); setEnabled(fitWidthMenuItem, opened && !pdfCollection); setEnabled(fullScreenMenuItem, opened && !pdfCollection && canDoFullScreen); setEnabled(zoomInMenuItem, opened && !pdfCollection); setEnabled(zoomOutMenuItem, opened && !pdfCollection); setEnabled(rotateLeftMenuItem, opened && !pdfCollection); setEnabled(rotateRightMenuItem, opened && !pdfCollection); // setEnabled(facingPageViewContinuousMenuItem , opened ); // setEnabled(singlePageViewContinuousMenuItem , opened ); // setEnabled(facingPageViewNonContinuousMenuItem , opened ); // setEnabled(singlePageViewNonContinuousMenuItem , opened ); if (showHideToolBarMenuItem != null) { boolean vis = (completeToolBar != null) && completeToolBar.isVisible(); showHideToolBarMenuItem.setText( vis ? messageBundle.getString("viewer.toolbar.hideToolBar.label") : messageBundle.getString("viewer.toolbar.showToolBar.label")); } setEnabled(showHideToolBarMenuItem, completeToolBar != null); if (showHideUtilityPaneMenuItem != null) { boolean vis = isUtilityPaneVisible(); showHideUtilityPaneMenuItem.setText( (opened && vis) ? messageBundle.getString("viewer.toolbar.hideUtilityPane.label") : messageBundle.getString("viewer.toolbar.showUtilityPane.label")); } setEnabled(showHideUtilityPaneMenuItem, opened && utilityTabbedPane != null); setEnabled(searchMenuItem, opened && searchPanel != null && !pdfCollection); setEnabled(advancedSearchMenuItem, opened && searchPanel != null && !pdfCollection); setEnabled(searchNextMenuItem, opened && searchPanel != null && !pdfCollection); setEnabled(searchPreviousMenuItem, opened && searchPanel != null && !pdfCollection); setEnabled(goToPageMenuItem, opened && nPages > 1 && !pdfCollection); setEnabled(saveFileButton, opened && !IS_READONLY); setEnabled(printButton, opened && canPrint && !pdfCollection); setEnabled(searchButton, opened && searchPanel != null && !pdfCollection); setEnabled(showHideUtilityPaneButton, opened && utilityTabbedPane != null); setEnabled(showAnnotationUtilityPaneButton, opened && utilityTabbedPane != null); setEnabled(showBookmarkUtilityPaneButton, opened && utilityTabbedPane != null); setEnabled(currentPageNumberTextField, opened && nPages > 1 && !pdfCollection); if (numberOfPagesLabel != null) { Object[] messageArguments = new Object[]{String.valueOf(nPages)}; MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.toolbar.pageIndicator")); String numberOfPages = formatter.format(messageArguments); numberOfPagesLabel.setText( opened ? numberOfPages : ""); } setEnabled(zoomInButton, opened && !pdfCollection); setEnabled(zoomOutButton, opened && !pdfCollection); setEnabled(zoomComboBox, opened && !pdfCollection); setEnabled(fitActualSizeButton, opened && !pdfCollection); setEnabled(fitHeightButton, opened && !pdfCollection); setEnabled(fitWidthButton, opened && !pdfCollection); setEnabled(fullScreenButton, opened && !pdfCollection && canDoFullScreen); setEnabled(rotateLeftButton, opened && !pdfCollection); setEnabled(rotateRightButton, opened && !pdfCollection); setEnabled(panToolButton, opened && !pdfCollection); setEnabled(zoomInToolButton, opened && !pdfCollection); setEnabled(zoomDynamicToolButton, opened && !pdfCollection); setEnabled(textSelectToolButton, opened && canExtract && !pdfCollection); setEnabled(selectToolButton, opened && canModify && !pdfCollection); setEnabled(deleteAllAnnotationsButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(highlightAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(redactionAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(strikeOutAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(underlineAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(lineAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(linkAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(lineArrowAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(squareAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(circleAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(inkAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(freeTextAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(textAnnotationToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(annotationSummaryButton, opened && canModify && !pdfCollection); setEnabled(annotationPreviewMenuItem, opened && canModify && !pdfCollection); setEnabled(annotationEditingModeButton, opened && !pdfCollection && !IS_READONLY); setEnabled(linkAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(highlightAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(strikeOutAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(underlineAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(lineAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(lineArrowAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(squareAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(circleAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(inkAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(freeTextAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(annotationPrivacyComboBox, opened && !pdfCollection && !IS_READONLY); setEnabled(textAnnotationPropertiesToolButton, opened && canModify && !pdfCollection && !IS_READONLY); setEnabled(formHighlightButton, opened && !pdfCollection && hasForms()); setEnabled(quickSearchToolBar, opened && !pdfCollection); setEnabled(facingPageViewContinuousButton, opened && !pdfCollection); setEnabled(singlePageViewContinuousButton, opened && !pdfCollection); setEnabled(facingPageViewNonContinuousButton, opened && !pdfCollection); setEnabled(singlePageViewNonContinuousButton, opened && !pdfCollection); if (opened) { reflectZoomInZoomComboBox(); reflectFitInFitButtons(); reflectDocumentViewModeInButtons(); reflectToolInToolButtons(); reflectFormHighlightButtons(); reflectAnnotationEditModeButtons(); reflectAnnotationDefaultPrivacy(); } } private boolean hasForms() { return document != null && !(document.getCatalog().getInteractiveForm() == null || document.getCatalog().getInteractiveForm().getFields() == null || document.getCatalog().getInteractiveForm().getFields().size() == 0); } private void reflectPageChangeInComponents() { boolean opened = document != null; int nPages = (getPageTree() != null) ? getPageTree().getNumberOfPages() : 0; int currentPage = isCurrentPage() ? documentViewController.getCurrentPageDisplayValue() : 0; setEnabled(firstPageMenuItem, opened && currentPage != 1); setEnabled(previousPageMenuItem, opened && currentPage != 1); setEnabled(nextPageMenuItem, opened && currentPage != nPages); setEnabled(lastPageMenuItem, opened && currentPage != nPages); setEnabled(firstPageButton, opened && currentPage != 1); setEnabled(previousPageButton, opened && currentPage != 1); setEnabled(nextPageButton, opened && currentPage != nPages); setEnabled(lastPageButton, opened && currentPage != nPages); if (currentPageNumberTextField != null) { currentPageNumberTextField.setText( opened ? Integer.toString(currentPage) : ""); } } public boolean havePermissionToPrint() { if (document == null) return false; org.icepdf.core.pobjects.security.SecurityManager securityManager = document.getSecurityManager(); if (securityManager == null) return true; Permissions permissions = securityManager.getPermissions(); return permissions == null || permissions.getPermissions(Permissions.PRINT_DOCUMENT); } public boolean havePermissionToExtractContent() { if (document == null) return false; org.icepdf.core.pobjects.security.SecurityManager securityManager = document.getSecurityManager(); if (securityManager == null) return true; Permissions permissions = securityManager.getPermissions(); return permissions == null || permissions.getPermissions(Permissions.CONTENT_EXTRACTION); } public boolean havePermissionToModifyDocument() { if (document == null) return false; org.icepdf.core.pobjects.security.SecurityManager securityManager = document.getSecurityManager(); if (securityManager == null) return true; Permissions permissions = securityManager.getPermissions(); return permissions == null || permissions.getPermissions(Permissions.MODIFY_DOCUMENT); } protected void setEnabled(JComponent comp, boolean ena) { if (comp != null) comp.setEnabled(ena); } private void setZoomFromZoomComboBox() { if (reflectingZoomInZoomComboBox) return; final int selIndex = zoomComboBox.getSelectedIndex(); float[] zoomLevels = documentViewController.getZoomLevels(); if (selIndex >= 0 && selIndex < zoomLevels.length) { float zoom = 1.0f; try { zoom = zoomLevels[selIndex]; } catch (IndexOutOfBoundsException ex) { logger.log(Level.FINE, "Error apply zoom levels"); } finally { if (zoom != documentViewController.getZoom()) { setZoom(zoom); } } } else { boolean success = false; try { Object selItem = zoomComboBox.getSelectedItem(); if (selItem != null) { String str = selItem.toString(); str = str.replace('%', ' '); str = str.trim(); float zoom = Float.parseFloat(str); zoom /= 100.0f; if (zoom != documentViewController.getZoom()) { setZoom(zoom); } success = true; } } catch (Exception e) { // Most likely a NumberFormatException success = false; } if (!success) { Toolkit.getDefaultToolkit().beep(); } } } /** * Method to determine if the Undo and Redo menu items can be enabled * This will query the UndoCaretaker for the status of the queue first */ public void reflectUndoCommands() { UndoCaretaker undoCaretaker = ((DocumentViewModelImpl) documentViewController.getDocumentViewModel()). getAnnotationCareTaker(); setEnabled(undoMenuItem, undoCaretaker.isUndo()); setEnabled(redoMenuItem, undoCaretaker.isRedo()); } private void reflectZoomInZoomComboBox() { if (reflectingZoomInZoomComboBox) return; if (document == null) return; int index = -1; final float zoom = documentViewController.getZoom(); final float belowZoom = zoom * 0.99f; final float aboveZoom = zoom * 1.01f; float[] zoomLevels = documentViewController.getZoomLevels(); if (zoomLevels != null) { for (int i = 0; i < zoomLevels.length; i++) { final float curr = zoomLevels[i]; if (curr >= belowZoom && curr <= aboveZoom) { index = i; break; } } } try { reflectingZoomInZoomComboBox = true; if (zoomComboBox != null) { if (index > -1) { zoomComboBox.setSelectedIndex(index); } else { zoomComboBox.setSelectedItem(NumberFormat.getPercentInstance().format(zoom)); } } // update the page fit values if they are in the correct zoom range // if( viewModel.fitPageFlag == .PAGE_FIT_NONE ) { // float fitActualZoom = calcZoomForFitActualSize(); // if( fitActualZoom >= belowZoom && fitActualZoom <= aboveZoom ) // viewModel.fitPageFlag = ViewModel.PAGE_FIT_ACTUAL_SIZE; // else { // float fitPageZoom = calcZoomForFitPage(); // if( fitPageZoom >= belowZoom && fitPageZoom <= aboveZoom ) // viewModel.fitPageFlag = ViewModel.PAGE_FIT_IN_WINDOW; // else { // float fitWidthZoom = calcZoomForFitWidth(); // if( fitWidthZoom >= belowZoom && fitWidthZoom <= aboveZoom ) // viewModel.fitPageFlag = ViewModel.PAGE_FIT_WINDOW_WIDTH; // } // } // } } finally { reflectingZoomInZoomComboBox = false; } } private boolean reflectingZoomInZoomComboBox = false; private void setAnnotationPrivacy(boolean isPublic) { // store the value in the view model viewModel.setAnnotationPrivacy(isPublic); // and save the value to backing store. Preferences preferences = ViewerPropertiesManager.getInstance().getPreferences(); preferences.putBoolean(ViewerPropertiesManager.PROPERTY_ANNOTATION_LAST_USED_PUBLIC_FLAG, isPublic); } private void reflectAnnotationDefaultPrivacy() { // check properties to get last state. Preferences preferences = ViewerPropertiesManager.getInstance().getPreferences(); boolean annotationPrivacy = !SystemProperties.PRIVATE_PROPERTY_ENABLED || preferences.getBoolean(ViewerPropertiesManager.PROPERTY_ANNOTATION_LAST_USED_PUBLIC_FLAG, true); // store the current state in the model and annotation tool handlers will pull from the current state. setAnnotationPrivacy(annotationPrivacy); // set the default value of the combo box. if (annotationPrivacyComboBox != null) { annotationPrivacyComboBox.setSelectedIndex(annotationPrivacy ? 0 : 1); } } /** * Gets the current display tool value for the display panel. * * @return constant representing the state of the display tool for the * display panel. * @see #setDisplayTool */ public int getDocumentViewToolMode() { return documentViewController.getToolMode(); } /** * Sets the display tool used when the document is viewed in interactive * mode. A display changes the icon of the mouse when it is over the panel * that displays a document page. There are currently four possible tool * modes: *
    *
  • DISPLAY_TOOL_PAN - Changes the mouse icon to a hand and allows * the user to click and drag the document view (Pan). This pan feature * is only available when the display window has scrollbars.
  • *
  • DISPLAY_TOOL_ZOOM_IN - Changes the mouse icon to a magnifying glass * and adds a left mouse click listener to the display panel. One left mouse * click increases the zoom factor by 20%.
  • *
  • DISPLAY_TOOL_ZOOM_OUT - Changes the mouse icon to a magnifying glass * and adds a left mouse click listener to the display panel. One left * mouse click decreases the zoom factor by 20%.
  • *
  • DISPLAY_TOOL_NONE - Changes the mouse icon to the default icon * and removes mouse properties from the display panel.
  • *
* * @param argToolName DocumentViewModel tool name. * @see #getDocumentViewToolMode */ public void setDisplayTool(final int argToolName) { try { boolean actualToolMayHaveChanged = false; if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_PAN) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_PAN); documentViewController.setViewCursor(DocumentViewController.CURSOR_HAND_OPEN); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION); documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SELECTION); documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_REDACTION_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_REDACTION_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_TEXT_SELECTION); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION) { actualToolMayHaveChanged = documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION); documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN) { actualToolMayHaveChanged = documentViewController.setToolMode( DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN); documentViewController.setViewCursor(DocumentViewController.CURSOR_ZOOM_IN); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC) { actualToolMayHaveChanged = documentViewController.setToolMode( DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC); documentViewController.setViewCursor(DocumentViewController.CURSOR_MAGNIFY); setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_WAIT) { setCursorOnComponents(DocumentViewController.CURSOR_WAIT); } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_NONE) { setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); } if (actualToolMayHaveChanged) { reflectToolInToolButtons(); } // disabled the annotation panels, selection will activate them again. if (annotationPanel != null) { annotationPanel.setEnabled(false); } // repaint the page views. documentViewController.getViewContainer().repaint(); } catch (java.awt.HeadlessException e) { e.printStackTrace(); logger.log(Level.FINE, "Headless exception during tool selection", e); } } private void getDefaultDisplayTool() { setDisplayTool(propertiesManager.getPreferences().getInt(PROPERTY_DEFAULT_DISPLAY_TOOL, DocumentViewModelImpl.DISPLAY_TOOL_PAN)); } private void setCursorOnComponents(final int cursorType) { Cursor cursor = documentViewController.getViewCursor(cursorType); if (utilityTabbedPane != null) utilityTabbedPane.setCursor(cursor); // if( documentViewController != null ) { // documentViewController.setViewCursor( cursorType ); // } if (viewer != null) viewer.setCursor(cursor); } /** * Sets the state of the "Tools" buttons. This ensure that correct button * is depressed when the state of the Document class specifies it. */ private void reflectToolInToolButtons() { reflectSelectionInButton(panToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_PAN )); reflectSelectionInButton(textSelectToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION )); reflectSelectionInButton(selectToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_SELECTION )); reflectSelectionInButton(highlightAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION )); reflectSelectionInButton(redactionAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_REDACTION_ANNOTATION )); reflectSelectionInButton(underlineAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION )); reflectSelectionInButton(strikeOutAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION )); reflectSelectionInButton(lineAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION )); reflectSelectionInButton(linkAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION )); reflectSelectionInButton(lineArrowAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION )); reflectSelectionInButton(squareAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION )); reflectSelectionInButton(circleAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION )); reflectSelectionInButton(inkAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION )); reflectSelectionInButton(freeTextAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION )); reflectSelectionInButton(textAnnotationToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION )); reflectSelectionInButton(linkAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION )); reflectSelectionInButton(highlightAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION )); reflectSelectionInButton(strikeOutAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION )); reflectSelectionInButton(underlineAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION )); reflectSelectionInButton(lineAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION )); reflectSelectionInButton(lineArrowAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION )); reflectSelectionInButton(squareAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION )); reflectSelectionInButton(circleAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION )); reflectSelectionInButton(inkAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION )); reflectSelectionInButton(freeTextAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION )); reflectSelectionInButton(textAnnotationPropertiesToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION )); reflectSelectionInButton(zoomInToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN )); reflectSelectionInButton(zoomDynamicToolButton, documentViewController.isToolModeSelected( DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC )); reflectSelectionInButton(showHideUtilityPaneButton, isUtilityPaneVisible()); reflectSelectionInButton(showAnnotationUtilityPaneButton, isAnnotationUtilityPaneVisible()); reflectSelectionInButton(showBookmarkUtilityPaneButton, isBookmarkUtilityPaneVisible()); reflectSelectionInButton(formHighlightButton, viewModel.isWidgetAnnotationHighlight()); reflectSelectionInButton(annotationEditingModeButton, viewModel.isAnnotationEditingMode()); } /** * Sets the state of the "Fit" buttons. This ensure that correct button * is depressed when the state of the Document class specifies it. */ private void reflectFitInFitButtons() { if (document == null) { return; } reflectSelectionInButton(fitWidthButton, isDocumentFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH)); reflectSelectionInButton(fitHeightButton, isDocumentFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT)); reflectSelectionInButton(fitActualSizeButton, isDocumentFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE)); } /** * Sets the state of the highlight forms button. Insures button is depressed when active. */ private void reflectFormHighlightButtons() { if (document == null) { return; } reflectSelectionInButton(formHighlightButton, viewModel.isWidgetAnnotationHighlight()); } private void reflectAnnotationEditModeButtons() { if (document == null) { return; } reflectSelectionInButton(annotationEditingModeButton, viewModel.isAnnotationEditingMode()); } /** * Sets the state of the "Document View" buttons. This ensure that correct button * is depressed when the state of the view controller class specifies it. */ private void reflectDocumentViewModeInButtons() { if (document == null) { return; } if (isDocumentViewMode(DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW)) { return; } reflectSelectionInButton( singlePageViewContinuousButton, isDocumentViewMode( DocumentViewControllerImpl.ONE_COLUMN_VIEW)); reflectSelectionInButton( facingPageViewNonContinuousButton, isDocumentViewMode( DocumentViewControllerImpl.TWO_PAGE_RIGHT_VIEW)); reflectSelectionInButton( facingPageViewContinuousButton, isDocumentViewMode( DocumentViewControllerImpl.TWO_COLUMN_RIGHT_VIEW)); reflectSelectionInButton( singlePageViewNonContinuousButton, isDocumentViewMode( DocumentViewControllerImpl.ONE_PAGE_VIEW)); } private void reflectSelectionInButton(AbstractButton btn, boolean selected) { if (btn != null) { if (btn.isSelected() != selected) { btn.setSelected(selected); } btn.setBorder( selected ? BorderFactory.createLoweredBevelBorder() : BorderFactory.createEmptyBorder()); } } /** * Utility method for opening a file. Shows a dialog for the user to * select which file to open. */ public void openFile() { openFile(""); } /** * Utility method for opening a file. Shows a dialog for the user to * select which file to open. * * @param initialDirPath The directory to show to the user when opening the FileDialog */ public void openFile(String initialDirPath) { final File file; if (!USE_JFILECHOOSER) { // Create and display a file open dialog final FileDialog fileDialog = new FileDialog(getViewerFrame()); fileDialog.setMultipleMode(false); fileDialog.setMode(FileDialog.LOAD); fileDialog.setFilenameFilter((f, s) -> s.endsWith(FileExtensionUtils.pdf)); if (initialDirPath != null && !initialDirPath.isEmpty()) { fileDialog.setDirectory(initialDirPath); } else if (ViewModel.getDefaultFile() != null) { fileDialog.setDirectory(ViewModel.getDefaultFile().getParentFile().getAbsolutePath()); fileDialog.setFile(ViewModel.getDefaultFile().getAbsolutePath()); } // show the dialog fileDialog.setTitle(messageBundle.getString("viewer.dialog.openFile.title")); fileDialog.setVisible(true); final String filePath = fileDialog.getFile(); final String dirPath = fileDialog.getDirectory(); if (filePath != null && dirPath != null) { file = new File(dirPath + filePath); } else { file = null; } fileDialog.setVisible(false); } else { // Create and display a file open dialog final JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.addChoosableFileFilter(FileExtensionUtils.getPDFFileFilter()); if (ViewModel.getDefaultFile() != null) { fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); fileChooser.setSelectedFile(ViewModel.getDefaultFile()); fileChooser.ensureFileIsVisible(ViewModel.getDefaultFile()); } // show the dialog fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.openFile.title")); final int returnVal = fileChooser.showOpenDialog(viewer); if (returnVal == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile(); } else { file = null; } fileChooser.setVisible(false); } if (file != null) { // make sure file being opened is valid final String extension = FileExtensionUtils.getExtension(file); if (extension != null) { if (extension.equals(FileExtensionUtils.pdf)) { if (viewer != null) { viewer.toFront(); viewer.requestFocus(); } openFileInSomeViewer(file); } else { org.icepdf.ri.util.Resources.showMessageDialog(viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openFile.error.title", "viewer.dialog.openFile.error.msg", file.getPath()); } // save the default directory ViewModel.setDefaultFile(file); } } } private void openFileInSomeViewer(File file) { // openDocument the file if (document == null) { openDocument(file.getPath()); } else if (windowManagementCallback != null) { int oldTool = SwingController.this.getDocumentViewToolMode(); setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); try { windowManagementCallback.newWindow(file.getPath()); } finally { setDisplayTool(oldTool); } } } public void openFileInSomeViewer(String filename) { try { File pdfFile = new File(filename); openFileInSomeViewer(pdfFile); ViewModel.setDefaultFile(pdfFile); } catch (Exception e) { logger.warning("Error loading " + filename); } } /** * Adds the recently opened file to the "Recently Opened" file list. * * @param path path to be added to recent files list. */ protected void addRecentFileEntry(Path path) { // get reference to the backing store. Preferences preferences = ViewerPropertiesManager.getInstance().getPreferences(); int maxListSize = preferences.getInt(PROPERTY_RECENT_FILES_SIZE, 8); String recentFilesString = preferences.get(PROPERTY_RECENTLY_OPENED_FILES, ""); StringTokenizer toker = new StringTokenizer(recentFilesString, PROPERTY_TOKEN_SEPARATOR); ArrayList recentPaths = new ArrayList<>(maxListSize); String fileName, filePath; while (toker.hasMoreTokens()) { fileName = toker.nextToken(); filePath = toker.nextToken(); recentPaths.add(fileName + PROPERTY_TOKEN_SEPARATOR + Paths.get(filePath)); } // add our new path the start of the list, remove any existing file names. String newRecentFile = path.getFileName() + PROPERTY_TOKEN_SEPARATOR + path; if (recentPaths.contains(newRecentFile)) { recentPaths.remove(newRecentFile); } recentPaths.add(0, newRecentFile); // trim the list if (recentPaths.size() > maxListSize) { int size = recentPaths.size(); for (int i = size - maxListSize; i > 0; i--) { recentPaths.remove(size - i); } } // put the list back in teh properties. StringBuilder stringBuilder = new StringBuilder(); for (String recentPath : recentPaths) { stringBuilder.append(recentPath).append(PROPERTY_TOKEN_SEPARATOR); } preferences.put(PROPERTY_RECENTLY_OPENED_FILES, stringBuilder.toString()); refreshRecentFileMenuItem(); } /** * Builds out the recent file list and assembles the menuItems. */ protected void refreshRecentFileMenuItem() { if (recentFilesSubMenu != null) { recentFilesSubMenu.removeAll(); Preferences preferences = propertiesManager.getPreferences(); String recentFilesString = preferences.get(PROPERTY_RECENTLY_OPENED_FILES, ""); StringTokenizer toker = new StringTokenizer(recentFilesString, PROPERTY_TOKEN_SEPARATOR); String fileName; int count = 0; try { while (toker.hasMoreTokens()) { fileName = toker.nextToken(); final String filePath = toker.nextToken(); JMenuItem mi = SwingViewBuilder.makeMenuItem( fileName, SwingViewBuilder.buildKeyStroke(KeyEvent.VK_1 + count, KeyEventConstants.MODIFIER_OPEN_FILE)); mi.addActionListener(e -> openFileInSomeViewer(filePath)); recentFilesSubMenu.add(mi); count++; } } catch (Exception e) { // clear the invalid previous values. preferences.put(PROPERTY_RECENTLY_OPENED_FILES, ""); } } } /** * Setup the security handle if specified, if not then creates and uses the default implementation. * * @param document document to set securityCallback on . * @param securityCallback security callback for prompting users or owner passwords. */ protected void setupSecurityHandler(Document document, SecurityCallback securityCallback) { // create default security callback is user has not created one if (securityCallback == null) { document.setSecurityCallback( new MyGUISecurityCallback(viewer, messageBundle)); } else { document.setSecurityCallback(documentViewController.getSecurityCallback()); } } /** * Open a file specified by the given path name. * * @param pathname String representing a valid file path */ public void openDocument(String pathname) { if (pathname != null && pathname.length() > 0) { try { // dispose a currently open document, if one. if (document != null) { closeDocument(); } setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); addRecentFileEntry(Paths.get(pathname)); saveFilePath = getTempSaveFileName(pathname); File tmpFile = new File(saveFilePath); if (tmpFile.exists() && new File(pathname).exists()) { String[] options = {messageBundle.getString("viewer.button.yes.label"), messageBundle.getString( "viewer.button.no.label")}; int ret = JOptionPane.showOptionDialog(viewer, MessageFormat.format(messageBundle.getString( "viewer.dialog.restore.label"), new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(tmpFile.lastModified())), messageBundle.getString("viewer.dialog.restore.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if (ret == JOptionPane.YES_OPTION) { try { Files.copy(tmpFile.toPath(), new File(pathname).toPath(), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.restore.exception.title", "viewer.dialog.restore.exception.label", e.getMessage() != null && !e.getMessage().isEmpty() ? e.getMessage() : e.toString()); } } else { try { Files.delete(tmpFile.toPath()); } catch (IOException e) { logger.log(Level.FINE, "Couldn't delete file " + tmpFile.getAbsolutePath(), e); } } } document = new Document(); // create default security callback is user has not created one setupSecurityHandler(document, documentViewController.getSecurityCallback()); document.setFile(pathname); commonNewDocumentHandling(pathname); } catch (PDFSecurityException e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.pdfSecurityException.title", "viewer.dialog.openDocument.pdfSecurityException.msg", pathname); document = null; logger.log(Level.FINE, "Error opening document.", e); } catch (Exception e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.exception.title", "viewer.dialog.openDocument.exception.msg", pathname); document = null; logger.log(Level.FINE, "Error opening document.", e); } finally { getDefaultDisplayTool(); } } } private static String getTempSaveFileName(final String originalFilePath) { final String separator = File.separator; final String[] pathSplit = originalFilePath.split(Pattern.quote(separator)); final String name = pathSplit[pathSplit.length - 1]; final String[] dotSplit = name.split("\\."); final String basename = getBasename(dotSplit); return Arrays.stream(pathSplit).limit(pathSplit.length - 1).collect(Collectors.joining(separator)) + separator + '.' + basename + "-tmp.pdf"; } private static String getBasename(final String[] dotSplit) { if (dotSplit.length == 1) { return dotSplit[0]; } else { return Arrays.stream(dotSplit).limit(dotSplit.length - 1).collect(Collectors.joining(".")); } } /** * Utility method for opening a URL. Shows a dialog for the user to * type what URL to open. */ public void openURL() { String urlLocation = ((ViewModel.getDefaultURL() != null) ? ViewModel.getDefaultURL() : ""); // display url input dialog Object o = JOptionPane.showInputDialog( viewer, "URL:", "Open URL", JOptionPane.QUESTION_MESSAGE, null, null, urlLocation); if (o != null) { URLAccess urlAccess = URLAccess.doURLAccess(o.toString()); urlAccess.closeConnection(); if (urlAccess.errorMessage != null) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openURL.exception.title", "viewer.dialog.openURL.exception.msg", urlAccess.errorMessage, urlAccess.urlLocation ); } else { if (viewer != null) { viewer.toFront(); viewer.requestFocus(); } openURLInSomeViewer(urlAccess.url); } ViewModel.setDefaultURL(urlAccess.urlLocation); urlAccess.dispose(); } } private void openURLInSomeViewer(URL url) { // openDocument the URL if (document == null) { openDocument(url); } else if (windowManagementCallback != null) { int oldTool = SwingController.this.getDocumentViewToolMode(); setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); try { windowManagementCallback.newWindow(url); } finally { setDisplayTool(oldTool); } } } /** * Open a URL specified by the location variable. * * @param location location of a valid PDF document */ public void openDocument(final URL location) { if (location != null) { // dispose a currently open document, if one. if (document != null) { closeDocument(); } setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); // load the document document = new Document(); try { // make a connection final URLConnection urlConnection = location.openConnection(); final int size = urlConnection.getContentLength(); SwingWorker worker = new SwingWorker() { InputStream in = null; @Override protected void done() { try { // Create ProgressMonitorInputStream String pathOrURL = location.toString(); Object[] messageArguments = {pathOrURL}; MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.dialog.openURL.downloading.msg")); ProgressMonitorInputStream progressMonitorInputStream = new ProgressMonitorInputStream( viewer, formatter.format(messageArguments), new SizeInputStream(urlConnection.getInputStream(), size)); // Create a stream on the URL connection in = new BufferedInputStream(progressMonitorInputStream); document.setInputStream(in, pathOrURL); // create default security callback is user has not created one setupSecurityHandler(document, documentViewController.getSecurityCallback()); commonNewDocumentHandling(location.getPath()); getDefaultDisplayTool(); } catch (IOException ex) { if (in != null) { try { in.close(); } catch (IOException e) { logger.log(Level.FINE, "Error opening document.", e); } } closeDocument(); document = null; } catch (PDFSecurityException e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.pdfSecurityException.title", "viewer.dialog.openDocument.pdfSecurityException.msg", location); document = null; logger.log(Level.FINE, "Error opening document.", e); } catch (Exception e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.exception.title", "viewer.dialog.openDocument.exception.msg", location); document = null; logger.log(Level.FINE, "Error opening document.", e); } } @Override protected Object doInBackground() throws Exception { // Create ProgressMonitorInputStream String pathOrURL = location.toString(); Object[] messageArguments = {pathOrURL}; MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.dialog.openURL.downloading.msg")); ProgressMonitorInputStream progressMonitorInputStream = new ProgressMonitorInputStream( viewer, formatter.format(messageArguments), new SizeInputStream(urlConnection.getInputStream(), size)); // Create a stream on the URL connection in = new BufferedInputStream(progressMonitorInputStream); return null; } }; worker.execute(); } catch (Exception e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.exception.title", "viewer.dialog.openDocument.exception.msg", location); document = null; logger.log(Level.FINE, "Error opening document.", e); } } } /** * Opens a Document via the specified InputStream. This method is a convenience method provided for * backwards compatibility. *
*

Note: This method is less efficient than * {@link #openDocument(String)} or {@link #openDocument(URL)} as it * may have to do intermediary data copying, using more memory. * * @param inputStream InputStream containing a valid PDF document. * @param description When in the GUI for describing this document. * @param pathOrURL Either a file path, or file name, or URL, describing the * origin of the PDF file. This is typically null. If non-null, it is * used to populate the default file name in the File..Save a Copy * dialog summoned in saveFile() */ public void openDocument(InputStream inputStream, String description, String pathOrURL) { if (inputStream != null) { try { // dispose a currently open document, if one. if (document != null) { closeDocument(); } setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); // load the document document = new Document(); // create default security callback is user has not created one setupSecurityHandler(document, documentViewController.getSecurityCallback()); document.setInputStream(inputStream, pathOrURL); commonNewDocumentHandling(description); } catch (PDFSecurityException e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.pdfSecurityException.title", "viewer.dialog.openDocument.pdfSecurityException.msg", description); document = null; logger.log(Level.FINE, "Error opening document.", e); } catch (Exception e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.exception.title", "viewer.dialog.openDocument.exception.msg", description); document = null; logger.log(Level.FINE, "Error opening document.", e); } finally { getDefaultDisplayTool(); } } } /** * Load the specified file in a new Viewer RI window. * * @param embeddedDocument document to load in ne window * @param fileName file name of the document in question */ public void openDocument(Document embeddedDocument, String fileName) { if (embeddedDocument != null) { try { // dispose a currently open document, if one. if (document != null) { closeDocument(); } setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); // load the document document = embeddedDocument; // create default security callback is user has not created one setupSecurityHandler(document, documentViewController.getSecurityCallback()); commonNewDocumentHandling(fileName); } catch (Exception e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.exception.title", "viewer.dialog.openDocument.exception.msg", fileName); document = null; logger.log(Level.FINE, "Error opening document.", e); } finally { getDefaultDisplayTool(); } } } /** * Opens a Document via the specified byte array. * * @param data Byte array containing a valid PDF document. * @param offset the index into the byte array where the PDF data begins * @param length the number of bytes in the byte array belonging to the PDF data * @param description When in the GUI for describing this document. * @param pathOrURL Either a file path, or file name, or URL, describing the * origin of the PDF file. This is typically null. If non-null, it is * used to populate the default file name in the File..Save a Copy * dialog summoned in saveFile() */ public void openDocument(byte[] data, int offset, int length, String description, String pathOrURL) { if (data != null) { try { // dispose a currently open document, if one. if (document != null) { closeDocument(); } setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); // load the document document = new Document(); // create default security callback is user has not created one setupSecurityHandler(document, documentViewController.getSecurityCallback()); document.setByteArray(data, offset, length, pathOrURL); commonNewDocumentHandling(description); } catch (PDFSecurityException e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.pdfSecurityException.title", "viewer.dialog.openDocument.pdfSecurityException.msg", description); document = null; logger.log(Level.FINE, "Error opening document.", e); } catch (Exception e) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.openDocument.exception.title", "viewer.dialog.openDocument.exception.msg", description); document = null; logger.log(Level.FINE, "Error opening document.", e); } finally { getDefaultDisplayTool(); } } } public void commonNewDocumentHandling(String fileDescription) { // utility pane visibility boolean showUtilityPane = false; // get data on how the view should look from the document dictionary // if no data, use settings from last viewed document, fit and view type Catalog catalog = document.getCatalog(); // Page layout, the default value is singlePage, but we currently // remember the users last view mode via the properties manager. Possible // values are SinglePage, OnceColumn, TwoColumnLeft, TwoColumnRight, // TwoPageLeft, TwoPageRight. Object tmp = catalog.getObject(Catalog.PAGELAYOUT_KEY); if (tmp instanceof Name) { String pageLayout = ((Name) tmp).getName(); int viewType = DocumentViewControllerImpl.ONE_PAGE_VIEW; if (pageLayout.equalsIgnoreCase("OneColumn")) { viewType = DocumentViewControllerImpl.ONE_COLUMN_VIEW; } else if (pageLayout.equalsIgnoreCase("TwoColumnLeft")) { viewType = DocumentViewControllerImpl.TWO_COLUMN_LEFT_VIEW; } else if (pageLayout.equalsIgnoreCase("TwoColumnRight")) { viewType = DocumentViewControllerImpl.TWO_COLUMN_RIGHT_VIEW; } else if (pageLayout.equalsIgnoreCase("TwoPageLeft")) { viewType = DocumentViewControllerImpl.TWO_PAGE_LEFT_VIEW; } else if (pageLayout.equalsIgnoreCase("TwoPageRight")) { viewType = DocumentViewControllerImpl.TWO_PAGE_RIGHT_VIEW; } documentViewController.setViewType(viewType); } // make sure we don't keep Attachments view around from a previous load // as we don't want to use it for a none attachments PDF file. if (documentViewController.getViewMode() == DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW) { documentViewController.setViewType(DocumentViewControllerImpl.ONE_COLUMN_VIEW); } // check to see if we have collection if (isPdfCollection()) { documentViewController.setViewType(DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW); } if (utilityTabbedPane != null) { // Page mode by default is UseNone, where other options are, UseOutlines, // UseThumbs, FullScreen (ignore), UseOC(ignore), Use Attachments(ignore); Name pageMode = catalog.getPageMode(); showUtilityPane = pageMode.equals(Catalog.PAGE_MODE_USE_OUTLINES_VALUE) || pageMode.equals(Catalog.PAGE_MODE_OPTIONAL_CONTENT_VALUE) || pageMode.equals(Catalog.PAGE_MODE_USE_ATTACHMENTS_VALUE) || pageMode.equals(Catalog.PAGE_MODE_USE_THUMBS_VALUE); } // selected the utility tab defined by the page mode key if (showUtilityPane) { Name pageMode = catalog.getPageMode(); if (pageMode.equals(Catalog.PAGE_MODE_USE_OUTLINES_VALUE) && utilityTabbedPane.indexOfComponent(outlinesScrollPane) > 0) { utilityTabbedPane.setSelectedComponent(outlinesScrollPane); } else if (pageMode.equals(Catalog.PAGE_MODE_OPTIONAL_CONTENT_VALUE) && utilityTabbedPane.indexOfComponent(layersPanel) > 0) { utilityTabbedPane.setSelectedComponent(layersPanel); } else if (pageMode.equals(Catalog.PAGE_MODE_USE_ATTACHMENTS_VALUE) && utilityTabbedPane.indexOfComponent(attachmentPanel) > 0) { utilityTabbedPane.setSelectedComponent(attachmentPanel); } else if (pageMode.equals(Catalog.PAGE_MODE_USE_THUMBS_VALUE) && utilityTabbedPane.indexOfComponent(thumbnailsPanel) > 0) { utilityTabbedPane.setSelectedComponent(thumbnailsPanel); } else { // Catalog.PAGE_MODE_USE_NONE_VALUE showUtilityPane = false; } } // initiates the view layout model, page coordinates and preferred size documentViewController.setDocument(document); // setup custom search utility tool if (searchPanel != null) searchPanel.refreshDocumentInstance(); if (thumbnailsPanel != null) { thumbnailsPanel.refreshDocumentInstance(); } if (layersPanel != null) { layersPanel.refreshDocumentInstance(); } if (signaturesPanel != null) { signaturesPanel.refreshDocumentInstance(); } if (annotationPanel != null) { annotationPanel.refreshDocumentInstance(); } if (attachmentPanel != null) { attachmentPanel.refreshDocumentInstance(); } if (annotationSummaryFrame != null) { annotationSummaryFrame.refreshDocumentInstance(); } // Refresh the properties manager object if we don't already have one // This would be not null if the UI was constructed manually if (propertiesManager == null) { propertiesManager = ViewerPropertiesManager.getInstance(); } // Set the default zoom level from the backing store float defaultZoom = propertiesManager.checkAndStoreFloatProperty( ViewerPropertiesManager.PROPERTY_DEFAULT_ZOOM_LEVEL); documentViewController.setZoom(defaultZoom); // set the default rotation level form the backing store. float defaultRotation = propertiesManager.checkAndStoreFloatProperty( ViewerPropertiesManager.PROPERTY_DEFAULT_ROTATION, 0); documentViewController.setRotation(defaultRotation); // Set the default page fit mode setPageFitMode(propertiesManager.checkAndStoreIntProperty( ViewerPropertiesManager.PROPERTY_DEFAULT_PAGEFIT, DocumentViewController.PAGE_FIT_NONE), false); // Apply any ViewerPreferences from the doc applyViewerPreferences(catalog, propertiesManager); // Only show utility panel if there is an outline or layers OutlineItem item = null; Outlines outlines = document.getCatalog().getOutlines(); if (outlines != null && outlinesTree != null) item = outlines.getRootOutlineItem(); if (item != null) { outlinesTree.setModel(new DefaultTreeModel(new OutlineItemTreeNode(item))); outlinesTree.setRootVisible(!item.isEmpty()); outlinesTree.setShowsRootHandles(true); if (utilityTabbedPane != null && outlinesScrollPane != null) { if (utilityTabbedPane.indexOfComponent(outlinesScrollPane) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(outlinesScrollPane), true); } } } else { if (utilityTabbedPane != null && outlinesScrollPane != null) { if (utilityTabbedPane.indexOfComponent(outlinesScrollPane) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(outlinesScrollPane), false); } } } // showUtilityPane will be true the document has an outline, but the // visibility can be over-ridden with the property application.utilitypane.show boolean hideUtilityPane = propertiesManager.getPreferences().getBoolean( ViewerPropertiesManager.PROPERTY_HIDE_UTILITYPANE, false); // hide utility pane if (hideUtilityPane) { setUtilityPaneVisible(false); } else { setUtilityPaneVisible(showUtilityPane); } // apply state value for whether form highlight is being used or not. boolean showFormHighlight = propertiesManager.getPreferences().getBoolean( ViewerPropertiesManager.PROPERTY_VIEWPREF_FORM_HIGHLIGHT, true); setFormHighlightVisible(showFormHighlight); boolean showAnnotationEditingMode = propertiesManager.getPreferences().getBoolean( ViewerPropertiesManager.PROPERTY_VIEWPREF_ANNOTATION_EDIT_MODE, false); setAnnotationEditModeVisible(showAnnotationEditingMode); // check if there are layers and enable/disable the tab as needed OptionalContent optionalContent = document.getCatalog().getOptionalContent(); if (layersPanel != null && utilityTabbedPane != null) { if (optionalContent == null || optionalContent.getOrder() == null) { if (utilityTabbedPane.indexOfComponent(layersPanel) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(layersPanel), false); } } else { if (utilityTabbedPane.indexOfComponent(layersPanel) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(layersPanel), true); } } } // check if there are any attachments and enable/disable the tab as needed if (attachmentPanel != null && utilityTabbedPane != null) { if (catalog.getEmbeddedFilesNameTree() != null && catalog.getEmbeddedFilesNameTree().getRoot() != null) { if (utilityTabbedPane.indexOfComponent(attachmentPanel) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(attachmentPanel), true); } } else { if (utilityTabbedPane.indexOfComponent(attachmentPanel) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(attachmentPanel), false); } } } // check if there are signatures and enable/disable the tab as needed boolean signaturesExist = document.getCatalog().getInteractiveForm() != null && document.getCatalog().getInteractiveForm().isSignatureFields(); if (signaturesPanel != null && utilityTabbedPane != null) { if (signaturesExist) { if (utilityTabbedPane.indexOfComponent(signaturesPanel) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(signaturesPanel), true); } } else { if (utilityTabbedPane.indexOfComponent(signaturesPanel) > -1) { utilityTabbedPane.setEnabledAt( utilityTabbedPane.indexOfComponent(signaturesPanel), false); } } } // add to the main pdfContentPanel the document peer if (viewer != null) { File f = new File(fileDescription); String title = null; if (document.getInfo() != null) { title = document.getInfo().getTitle(); } String filename = f.exists() ? f.getName() : fileDescription; Object[] messageArguments = title == null ? new String[]{filename} : new String[]{title, filename}; String titleResource = title == null ? "notitle" : "default"; MessageFormat formatter = new MessageFormat(messageBundle.getString("viewer.window.title.open." + titleResource)); viewer.setTitle(formatter.format(messageArguments)); } // disable the annotation properties panel by default if (annotationPanel != null) { annotationPanel.setEnabled(false); } // set the go to page combo box in the mainToolbar reflectStateInComponents(); updateDocumentView(); } /** * Close the currently opened PDF Document. The toolbar component's states * are also changed to their default values and made inactive.
*
* Note: If you create several SwingControllers to manipulate a single * Document, and each Controller would be disposed of at a different * time, while the others continue to use that same shared Document, then * you should not call Document.dispose() inside of here, or alternatively * implement reference counting, so that only the last Controller would * call Document.dispose() * * @see Document */ public void closeDocument() { // Clear the SearchPane, but also stop any search in progress if (searchPanel != null) { searchPanel.disposeDocument(); } if (thumbnailsPanel != null) { thumbnailsPanel.disposeDocument(); } if (layersPanel != null) { layersPanel.disposeDocument(); } if (attachmentPanel != null) { attachmentPanel.disposeDocument(); } if (signaturesPanel != null) { signaturesPanel.disposeDocument(); } if (annotationSummaryFrame != null) { annotationSummaryFrame.disposeDocument(); annotationSummaryFrame.dispose(); } // set the default cursor. documentViewController.closeDocument(); // clear search controller caches. documentSearchController.dispose(); // free the document if (document != null) { document.dispose(); document = null; } // remove the page numbers in the go to page combo box in the mainToolbar if (currentPageNumberTextField != null) currentPageNumberTextField.setText(""); if (numberOfPagesLabel != null) numberOfPagesLabel.setText(""); if (currentPageNumberTextField != null) currentPageNumberTextField.setEnabled(false); if (statusLabel != null) statusLabel.setText(" "); // set the scale level back to 100%, default if (zoomComboBox != null) zoomComboBox.setSelectedItem(NumberFormat.getPercentInstance().format(1.0)); // update thew view to show no pages in the view updateDocumentView(); // tear down the outline tree. TreeModel treeModel = (outlinesTree != null) ? outlinesTree.getModel() : null; if (treeModel != null) { OutlineItemTreeNode root = (OutlineItemTreeNode) treeModel.getRoot(); if (root != null) root.recursivelyClearOutlineItems(); outlinesTree.getSelectionModel().clearSelection(); outlinesTree.getSelectionModel().setSelectionPath(null); outlinesTree.setSelectionPath(null); outlinesTree.setModel(null); } setUtilityPaneVisible(false); if (viewer != null) { viewer.setTitle(messageBundle.getString("viewer.window.title.default")); viewer.invalidate(); viewer.validate(); viewer.repaint(); } reflectStateInComponents(); } /** * Way to dispose of all memory references, and clean up the Document resources
*
* Note: If you create several SwingControllers to manipulate a single * Document, and each Controller would be disposed of at a different * time, while the others continue to use that same shared Document, then * you should not call Document.dispose() inside of here. Alternatively, * implement reference counting, so that only the last Controller would * call Document.dispose() */ public void dispose() { if (disposed) return; disposed = true; closeDocument(); openFileMenuItem = null; openURLMenuItem = null; closeMenuItem = null; saveAsFileMenuItem = null; sendMailMenuItem = null; exportTextMenuItem = null; permissionsMenuItem = null; propertiesMenuItem = null; informationMenuItem = null; printSetupMenuItem = null; printMenuItem = null; exitMenuItem = null; fitActualSizeMenuItem = null; fitPageMenuItem = null; fitWidthMenuItem = null; fullScreenMenuItem = null; zoomInMenuItem = null; zoomOutMenuItem = null; rotateLeftMenuItem = null; rotateRightMenuItem = null; showHideToolBarMenuItem = null; showHideUtilityPaneMenuItem = null; preferencesMenuItem = null; firstPageMenuItem = null; previousPageMenuItem = null; nextPageMenuItem = null; lastPageMenuItem = null; searchMenuItem = null; advancedSearchMenuItem = null; searchNextMenuItem = null; searchPreviousMenuItem = null; goToPageMenuItem = null; minimiseAllMenuItem = null; bringAllToFrontMenuItem = null; windowListMenuItems = null; aboutMenuItem = null; openFileButton = null; saveFileButton = null; printButton = null; searchButton = null; showHideUtilityPaneButton = null; firstPageButton = null; previousPageButton = null; nextPageButton = null; lastPageButton = null; if (currentPageNumberTextField != null) { currentPageNumberTextField.removeActionListener(this); currentPageNumberTextField.removeFocusListener(this); Arrays.stream(currentPageNumberTextField.getKeyListeners()).forEach(currentPageNumberTextField::removeKeyListener); currentPageNumberTextField = null; } numberOfPagesLabel = null; zoomInButton = null; zoomOutButton = null; if (zoomComboBox != null) { zoomComboBox.removeItemListener(this); zoomComboBox = null; } if (annotationPrivacyComboBox != null) { annotationPrivacyComboBox.removeActionListener(this); annotationPrivacyComboBox = null; } fitActualSizeButton = null; fitHeightButton = null; fitWidthButton = null; fullScreenButton = null; rotateLeftButton = null; rotateRightButton = null; panToolButton = null; zoomInToolButton = null; zoomDynamicToolButton = null; textSelectToolButton = null; selectToolButton = null; highlightAnnotationToolButton = null; redactionAnnotationToolButton = null; strikeOutAnnotationToolButton = null; underlineAnnotationToolButton = null; lineAnnotationToolButton = null; linkAnnotationToolButton = null; lineArrowAnnotationToolButton = null; squareAnnotationToolButton = null; circleAnnotationToolButton = null; inkAnnotationToolButton = null; freeTextAnnotationToolButton = null; textAnnotationToolButton = null; linkAnnotationPropertiesToolButton = null; highlightAnnotationPropertiesToolButton = null; underlineAnnotationPropertiesToolButton = null; strikeOutAnnotationPropertiesToolButton = null; lineAnnotationPropertiesToolButton = null; lineArrowAnnotationPropertiesToolButton = null; squareAnnotationPropertiesToolButton = null; circleAnnotationPropertiesToolButton = null; inkAnnotationPropertiesToolButton = null; freeTextAnnotationPropertiesToolButton = null; textAnnotationPropertiesToolButton = null; formHighlightButton = null; annotationEditingModeButton = null; completeToolBar = null; outlinesTree = null; if (outlinesScrollPane != null) { outlinesScrollPane.removeAll(); outlinesScrollPane = null; } if (searchPanel != null) { searchPanel.disposeDocument(); searchPanel = null; } if (thumbnailsPanel != null) { thumbnailsPanel.disposeDocument(); thumbnailsPanel = null; } if (layersPanel != null) { layersPanel.disposeDocument(); } if (attachmentPanel != null) { attachmentPanel.disposeDocument(); } if (signaturesPanel != null) { signaturesPanel.disposeDocument(); } if (annotationPanel != null) { annotationPanel.disposeDocument(); } if (utilityTabbedPane != null) { utilityTabbedPane.removeAll(); utilityTabbedPane = null; } // Clean up the document view controller if (documentViewController != null) { documentViewController.removePropertyChangeListener(this); documentViewController.dispose(); } // clean up search controller if (documentSearchController != null) { documentSearchController.dispose(); } if (utilityAndDocumentSplitPane != null) { utilityAndDocumentSplitPane.removeAll(); utilityAndDocumentSplitPane.removePropertyChangeListener(this); } statusLabel = null; if (viewer != null) { viewer.removeWindowListener(this); viewer.removeComponentListener(this); viewer.removeAll(); } viewModel = null; windowManagementCallback = null; } /** * Utility method for saving the current document to the same filename. * As it's not possible to write to the file while the document is open, * a temp file is created and this file will be renamed to the current open file * when the window is closed. */ public void saveFile() { if (IS_READONLY) return; // check for annotations if (hasUnburnedRedactions()) { int option = showRedactionWarningDialog(); if (option == JOptionPane.CANCEL_OPTION) { return; } else if (option == JOptionPane.YES_OPTION) { exportDocument(); return; } else if (option == JOptionPane.NO_OPTION) { // continue with saving the document } } if (document.getStateManager().isChange() && saveFilePath != null && !saveFilePath.isEmpty()) { File out = new File(saveFilePath); if (out.getParentFile() != null) { if (Files.isWritable(out.getParentFile().toPath())) { try (OutputStream stream = new BufferedOutputStream(new FileOutputStream(out))) { document.saveToOutputStream(stream); stream.flush(); document.getStateManager().setChangesSnapshot(); } catch (IOException | InterruptedException e) { logger.log(Level.FINE, "IO Exception ", e); } } } else { // Probably got loaded from an InputStream, can't inline save, so call saveAs saveFileAs(SaveMode.SAVE); } } else { // show saveAs dialog as this was legacy behaviour for the save button on the toolbar saveFileAs(SaveMode.SAVE); } } /** * Utility method for saving a copy of the currently opened * PDF to a file. This will check all valid permissions and * show a file save dialog for the user to select where to * save the file to, and what name to give it. */ public void saveFileAs() { saveFileAs(SaveMode.SAVE_AS); } /** * Utility method for saving a document using a full document write. The file will * be rewritten and indexed. All deleted objects will be removed. Any incremental * updates will be flattened and only the current object version will be written. * No previous document state will persist. * A save dialog will be shown will not be possible to overwrite the original * document. */ public void exportDocument() { saveFileAs(SaveMode.EXPORT); } protected boolean hasUnburnedRedactions() { return document.hasRedactions(); } protected int showRedactionWarningDialog() { // show dialog warning user they are about to save has unburned redaction annotations return JOptionPane.showConfirmDialog(getViewerFrame(), messageBundle.getString("viewer.dialog.redaction.unburned.msgs"), messageBundle.getString("viewer.dialog.redaction.unburned.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); } protected void saveFileAs(SaveMode saveMode) { if (saveMode != SaveMode.EXPORT && hasUnburnedRedactions()) { int option = showRedactionWarningDialog(); if (option == JOptionPane.CANCEL_OPTION) { return; } else if (option == JOptionPane.YES_OPTION) { exportDocument(); return; } else if (option == JOptionPane.NO_OPTION) { // continue with saving the document } } String originalFileName = getOriginalFileName(); String newFileName = originalFileName == null || originalFileName.isEmpty() ? null : generateNewSaveName(originalFileName); // Create and display a file saving dialog if (!USE_JFILECHOOSER) { final FileDialog fileDialog = new FileDialog(getViewerFrame()); fileDialog.setTitle(messageBundle.getString("viewer.dialog.saveAs.title")); fileDialog.setMultipleMode(false); fileDialog.setMode(FileDialog.SAVE); fileDialog.setFilenameFilter((file, s) -> s.endsWith(FileExtensionUtils.pdf)); if (ViewModel.getDefaultFile() != null) { fileDialog.setDirectory(ViewModel.getDefaultFile().getParentFile().getAbsolutePath()); } if (newFileName != null) { fileDialog.setFile(newFileName); } // show the dialog fileDialog.setVisible(true); final String filePath = fileDialog.getFile(); final String dirPath = fileDialog.getDirectory(); if (filePath != null && dirPath != null) { saveFileChecks(saveMode, originalFileName, new File(dirPath + filePath)); } } else { final JFileChooser fileChooser = new JFileChooser(); fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.saveAs.title")); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.addChoosableFileFilter(FileExtensionUtils.getPDFFileFilter()); if (ViewModel.getDefaultFile() != null) { fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); } if (newFileName != null) { fileChooser.setSelectedFile(new File(newFileName)); } // show the dialog if (fileChooser.showSaveDialog(viewer) == JFileChooser.APPROVE_OPTION) { saveFileChecks(saveMode, originalFileName, fileChooser.getSelectedFile()); } } } private String getOriginalFileName() { String origin = document.getDocumentOrigin(); if (origin != null) { int lastSeparator = Math.max( Math.max( origin.lastIndexOf('/'), origin.lastIndexOf('\\')), origin.lastIndexOf(File.separator) // Might not be / or \ ); if (lastSeparator >= 0) { return origin.substring(lastSeparator + 1); } } return null; } protected void saveFileChecks(SaveMode saveMode, String originalFileName, File file) { if (file != null) { if (Files.isWritable(file.getParentFile().toPath())) { // make sure file path being saved to is valid String extension = FileExtensionUtils.getExtension(file); if (extension == null) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.saveAs.noExtensionError.title", "viewer.dialog.saveAs.noExtensionError.msg"); saveFileAs(saveMode); } else if (!extension.equals(FileExtensionUtils.pdf)) { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.saveAs.extensionError.title", "viewer.dialog.saveAs.extensionError.msg", file.getName()); saveFileAs(saveMode); } else if (originalFileName != null && originalFileName.equalsIgnoreCase(file.getName())) { // Ensure a unique filename org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.saveAs.noneUniqueName.title", "viewer.dialog.saveAs.noneUniqueName.msg", file.getName()); saveFileAs(saveMode); } else { // save file stream // If we don't know where the file came from, it's because we // used Document.contentStream() or Document.setByteArray(), // or we used setUrl() with disk caching disabled. // with no path or URL as the origin. // Note that we used to detect scenarios where we could access // the file directly, or re-download it, to avoid locking our // internal data structures for long periods for large PDFs, // but that could cause problems with slow network links too, // and would complicate the incremental update code, so we're // harmonising on this approach. try (final FileOutputStream fileOutputStream = new FileOutputStream(file); final BufferedOutputStream buf = new BufferedOutputStream(fileOutputStream, 8192)) { // We want 'save as' or 'save a copy to always occur if (saveMode == SaveMode.EXPORT) { // save as copy document.writeToOutputStream(buf, WriteMode.FULL_UPDATE); } else { // save as will append changes. document.saveToOutputStream(buf); } document.getStateManager().setChangesSnapshot(); } catch (MalformedURLException e) { logger.log(Level.WARNING, "Malformed URL Exception ", e); } catch (IOException e) { logger.log(Level.WARNING, "IO Exception ", e); } catch (Exception e) { logger.log(Level.WARNING, "Failed to append document changes", e); } // save the default directory ViewModel.setDefaultFile(file); } } else { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.saveAs.cantwrite.title", "viewer.dialog.saveAs.cantwrite.msg", file.getParentFile().getName()); saveFileAs(); } } } /** * Generates a file name based on the original file name but appends "-new". * If new file extension exists a ".pdf" is automatically added. * * @param fileName file name that new file name is derived from. * @return original file name with the "-new" appended to it. */ protected String generateNewSaveName(String fileName) { if (fileName != null) { // Return the file with "-new" in the filename, before the extension // For example Test.pdf would become Test-new.pdf int endIndex = fileName.toLowerCase().indexOf(FileExtensionUtils.pdf) - 1; String result; if (endIndex < 0) { result = fileName + "-new." + FileExtensionUtils.pdf; } else { result = fileName.substring(0, endIndex) + "-new." + FileExtensionUtils.pdf; } return result; } return null; } /** * Utility method for exporting all of a Document's text to a text file. * Shows a file save dialog for the user to select where to save the * exported text file to, and what name to give that file. */ public void exportText() { final File file; if (USE_JFILECHOOSER) { final JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if (ViewModel.getDefaultFile() != null) { fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); } if (fileChooser.showSaveDialog(getViewerFrame()) == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile(); } else { file = null; } fileChooser.setVisible(false); } else { // Create and display a file saving dialog final FileDialog fileChooser = new FileDialog(getViewerFrame()); fileChooser.setTitle(messageBundle.getString("viewer.dialog.exportText.title")); fileChooser.setMultipleMode(false); fileChooser.setMode(FileDialog.SAVE); fileChooser.setFilenameFilter((File f, String s) -> s.endsWith(FileExtensionUtils.txt)); if (ViewModel.getDefaultFile() != null) { fileChooser.setDirectory(ViewModel.getDefaultFile().getParentFile().getAbsolutePath()); } // show the dialog fileChooser.setVisible(true); final String filePath = fileChooser.getFile(); final String dirPath = fileChooser.getDirectory(); if (filePath != null && dirPath != null) { file = new File(dirPath + filePath); } else { file = null; } } if (file != null) { // make sure file being opened is valid String extension = FileExtensionUtils.getExtension(file); if (extension != null) { int lengthOfTask = document.getNumberOfPages(); ProgressMonitor progressMonitor = new ProgressMonitor( viewer, messageBundle.getString("viewer.dialog.exportText.progress.msg"), "", 0, lengthOfTask); new TextExtractionTask(document, file, progressMonitor, messageBundle).execute(); } else { org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.exportText.noExtensionError.title", "viewer.dialog.exportText.noExtensionError.msg"); exportText(); } } } /** * If there is a WindowManagementCallback in place, then this will invoke its quit method * * @return true indicates save was execute, false; cancelled. * @see #setWindowManagementCallback * @see #getWindowManagementCallback */ public boolean saveChangesDialog() { // check if document changes have been made, if so ask the user if they // want to save the changes. if (document != null && !IS_READONLY) { boolean documentChanges = document.getStateManager().hasChangedSinceLastSnapshot(); if (documentChanges) { MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.dialog.saveOnClose.noUpdates.msg")); String dialogMessage = formatter.format(new Object[]{document.getDocumentOrigin()}); int res = JOptionPane.showConfirmDialog(viewer, dialogMessage, messageBundle.getString("viewer.dialog.saveOnClose.noUpdates.title"), JOptionPane.YES_NO_CANCEL_OPTION); if (res == JOptionPane.OK_OPTION) { // start save as process. saveFileAs(); // fall though and close window. } else if (res == JOptionPane.NO_OPTION) { // nothing to do, just fall through. } else if (res == JOptionPane.CANCEL_OPTION) { // suppress the close action return true; } } } return false; } /** * Flips the visibility of the toolbar to the opposite of what it was * * @see #setToolBarVisible(boolean) */ public void toggleToolBarVisibility() { if (completeToolBar != null) setToolBarVisible(!completeToolBar.isVisible()); } /** * Sets the visibility of the toolbar * * @param show The new visibility of the toolbar */ public void setToolBarVisible(boolean show) { if (completeToolBar != null) completeToolBar.setVisible(show); reflectStateInComponents(); } /** * Show the About dialog. Subclasses may override this method to show an * alternate About dialog */ public void showAboutDialog() { // Added to swing thread to ensure it shows up on top of main // browser window Runnable doSwingWork = () -> { AboutDialog ad = new AboutDialog(viewer, messageBundle, true, AboutDialog.NO_TIMER); ad.setVisible(true); }; SwingUtilities.invokeLater(doSwingWork); } /** * Show the permissions set in the PDF file's Document, as relates to encryption, * altering, or extracting information from, the Document */ public void showDocumentPermissionsDialog() { PermissionsDialog pd = new PermissionsDialog( viewer, document, messageBundle); pd.setVisible(true); } /** * Show information about the PDF file's Document, such as the title, * subject, author, keywords, creator, producer, creation date, and * last modification date */ public void showDocumentInformationDialog() { InformationDialog did = new InformationDialog(viewer, document, messageBundle); did.setVisible(true); } /** * Show document font information. */ public void showDocumentFontDialog() { new FontDialog(viewer, this, document, messageBundle).setVisible(true); } /** * Show tabbed pane interface for document properties, info, security and fonts. */ public void showDocumentProperties() { new PropertiesDialog(viewer, this, messageBundle).setVisible(true); } /** * Show tabbed pane interface for viewer preferences, info, security and fonts. */ public void showViewerPreferences() { new PreferencesDialog(viewer, this, messageBundle).setVisible(true); } /** * Show tabbed pane interface for viewer preferences, info, security and fonts. */ public void showViewerPreferences(final String selectedPreference) { PreferencesDialog preferencesDialog = new PreferencesDialog(viewer, this, messageBundle); preferencesDialog.setSelectedPreference(selectedPreference); preferencesDialog.setVisible(true); } /** * Show tabbed pane interface for annotation properties. */ public void showAnnotationProperties(AnnotationComponent annotationComponent) { // grab a reference to the page so that it isn't de-referenced when the new // dialog get referenced. At least I think that's what might be happening. PageTree pageTree = getPageTree(); Page page = pageTree.getPage(documentViewController.getCurrentPageIndex()); showAnnotationProperties(annotationComponent, viewer); } /** * Show tabbed pane interface for annotation properties centered on the given frame */ public void showAnnotationProperties(AnnotationComponent annotationComponent, Frame frame) { AnnotationPropertiesDialog annotationPropertiesDialog = new AnnotationPropertiesDialog(frame, this, messageBundle); annotationPropertiesDialog.setAnnotationComponent(annotationComponent); annotationPropertiesDialog.setVisible(true); } /** * Show a print setup dialog, to alter the ViewerModel's PageFormat * * @see ViewModel */ public void showPrintSetupDialog() { PrintHelper printHelper = viewModel.getPrintHelper(); // create a new print helper for this document instance if (printHelper == null) { MediaSizeName mediaSizeName = PrintHelper.guessMediaSizeName(document); // create the new print help printHelper = getPrintHelperFactory().createPrintHelper(documentViewController.getViewContainer(), getPageTree(), documentViewController.getRotation(), mediaSizeName, PrintQuality.NORMAL); } // reuse previous print attributes if they exist. else { printHelper = getPrintHelperFactory().createPrintHelper(documentViewController.getViewContainer(), getPageTree(), documentViewController.getRotation(), printHelper.getDocAttributeSet(), printHelper.getPrintRequestAttributeSet()); } viewModel.setPrintHelper(printHelper); viewModel.getPrintHelper().showPrintSetupDialog(); } /** * Sets the default MediaSizeName and creates an new instance of the * the PrintHelp with the new media size. The media size is also * persisted to the PropertiesManager. *
* Note: this method should only be called after a valid file or * file stream has been loaded by the controller otherwise a null pointer * will result. * * @param mediaSize MediaSizeName constant of paper size to print to. */ public void setPrintDefaultMediaSizeName(MediaSizeName mediaSize) { PrintHelper printHelper = getPrintHelperFactory().createPrintHelper( documentViewController.getViewContainer(), getPageTree(), documentViewController.getRotation(), mediaSize, PrintQuality.NORMAL); viewModel.setPrintHelper(printHelper); } /** * @param withDialog If should show a print dialog before starting to print */ public void print(final boolean withDialog) { if (printMenuItem != null) { printMenuItem.setEnabled(false); } if (printButton != null) { printButton.setEnabled(false); } Runnable runner = () -> initialisePrinting(withDialog, null); Thread t = new Thread(runner); t.setPriority(Thread.NORM_PRIORITY); t.start(); } public void printAndExit(boolean showDialog, String printer) { //Do synchronously, because we're exiting after that initialisePrinting(showDialog, printer); } /** * If the withDialog parameter is true, show a print dialog, * defaulted to print all pages. If the click Ok, then print the page range * they have specified, else if they clicked Cancel, then abort the printing *
* If the withDialog parameter is false, then print all pages of * the PDF Document without showing and print dialogs * * @param withDialog If should show a print dialog before starting to print */ private void initialisePrinting(final boolean withDialog, final String printer) { boolean canPrint = havePermissionToPrint(); if (!canPrint) { renablePrintUI(); return; } final int documentIcon = getDocumentViewToolMode(); try { // set cursor for document view SwingUtilities.invokeLater(() -> setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT)); // create a new print helper, one-to-one with document, make sure that // previous printer properties are preserved. default values listed // below are for NA_letter in millimeters. PrintHelper printHelper = viewModel.getPrintHelper(); if (printHelper == null) { MediaSizeName mediaSizeName = PrintHelper.guessMediaSizeName(document); // create the new print help printHelper = getPrintHelperFactory().createPrintHelper(documentViewController.getViewContainer(), getPageTree(), documentViewController.getRotation(), mediaSizeName, PrintQuality.NORMAL); } else { printHelper = getPrintHelperFactory().createPrintHelper(documentViewController.getViewContainer(), getPageTree(), documentViewController.getRotation(), printHelper.getDocAttributeSet(), printHelper.getPrintRequestAttributeSet()); } viewModel.setPrintHelper(printHelper); if (printer != null) { printHelper.setPrinter(printer); } // set the printer to show a print dialog canPrint = printHelper.setupPrintService( 0, document.getNumberOfPages() - 1, viewModel.getPrintCopies(), // default number of copies. viewModel.isShrinkToPrintableArea(), // shrink to printable area withDialog // show print dialog ); // if user cancelled the print job from the dialog, don't start printing // in the background. if (!canPrint) { renablePrintUI(); return; } startBackgroundPrinting(printHelper); } finally { SwingUtilities.invokeLater(() -> setDisplayTool(documentIcon)); } } private void renablePrintUI() { SwingUtilities.invokeLater(() -> { // enable print UI controls. if (printMenuItem != null) { printMenuItem.setEnabled(true); } if (printButton != null) { printButton.setEnabled(true); } }); } /** * Utility method to setup a printer job to run as a background process. * * @param printHelper a PrintHelper object which is already setup and ready * to be printed to. */ private void startBackgroundPrinting(final PrintHelper printHelper) { // Create the ProgressMonitor in the Swing thread SwingUtilities.invokeLater(() -> { // launch progress dialog printProgressMonitor = new ProgressMonitor(viewer, messageBundle.getString("viewer.dialog.printing.status.start.msg"), "", 1, printHelper.getNumberOfPages()); }); final Thread printingThread = Thread.currentThread(); // create background printer job final PrinterTask printerTask = new PrinterTask(printHelper, this); // create activity monitor printActivityMonitor = new Timer(250, event -> { int limit = printHelper.getNumberOfPages(); int current = printHelper.getCurrentPage(); // progress bar for printing Object[] messageArguments = new Object[]{ String.valueOf(current + 1), String.valueOf(limit)}; MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.dialog.printing.status.progress.msg")); SwingUtilities.invokeLater(() -> { printProgressMonitor.setProgress(current); printProgressMonitor.setNote(formatter.format(messageArguments)); }); // check for job completed or cancelled. if (!printingThread.isAlive() || printProgressMonitor.isCanceled()) { printerTask.cancel(); // make sure kill the printing thread, otherwise we'll keep going for none cancellable jobs. printingThread.interrupt(); // stop the timers, monitors and thread. SwingUtilities.invokeLater(() -> { printProgressMonitor.close(); printActivityMonitor.stop(); // enable print UI controls. if (printMenuItem != null) { printMenuItem.setEnabled(true); } if (printButton != null) { printButton.setEnabled(true); } }); } }); // start the timer. SwingUtilities.invokeLater(() -> printActivityMonitor.start()); // start print job printerTask.run(); } /** * Takes the page number that the user has typed into the text field, * converts it into a page index, and then displays that page */ public void showPageFromTextField() { String ob = currentPageNumberTextField.getText(); if (ob != null) { try { int pageIndex = Integer.parseInt(ob) - 1; showPage(pageIndex); } catch (NumberFormatException nfe) { logger.log(Level.FINE, "Error converting page number."); } } } /** * When the user selects an OutlineItem from the Outlines (Bookmarks) JTree, * this displays the relevant target portion of the PDF Document * * @param outlineItem navigate to this outlines items destination. */ public void followOutlineItem(OutlineItem outlineItem) { if (outlineItem == null) return; int oldTool = getDocumentViewToolMode(); try { // set hour glass outlinesTree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); // capture the action if no destination is found and point to the // actions destination information Destination dest = outlineItem.getDest(); if (outlineItem.getAction() != null) { Action action = outlineItem.getAction(); if (action instanceof GoToAction) { dest = ((GoToAction) action).getDestination(); } else if (action instanceof URIAction) { BareBonesBrowserLaunch.openURL( ((URIAction) action).getURI()); } else { Library library = action.getLibrary(); DictionaryEntries entries = action.getEntries(); dest = new Destination(library, library.getObject(entries, Destination.D_KEY)); } } else if (dest.getNamedDestination() != null) { // building the namedDestination tree can be very time consuming, so we need // update the icons accordingly. NamedDestinations namedDestinations = document.getCatalog().getDestinations(); if (namedDestinations != null) { dest = namedDestinations.getDestination(dest.getNamedDestination()); } } // Process the destination information if (dest == null) return; // let the document view controller resolve the destination documentViewController.setDestinationTarget(dest); } finally { // set the icon back to the pointer setDisplayTool(oldTool); outlinesTree.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } // Utility method which alows copy or move drag actions private boolean isDragAcceptable(DropTargetDragEvent event) { // check to make sure that we only except the copy action return (event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0; } // Utility method which allows copy or move drop actions private boolean isDropAcceptable(DropTargetDropEvent event) { // check to make sure that we only except the copy action return (event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0; } /** * Increases the current page visualization zoom factor by 20%. */ public void zoomIn() { // zoom in the view documentViewController.setZoomIn(); // doCommonZoomUIUpdates(); } /** * Decreases the current page visualization zoom factor by 20%. */ public void zoomOut() { documentViewController.setZoomOut(); // doCommonZoomUIUpdates(); } /** * Zoom to a new zoom level, without centering on any new specific point * * @param zoom zoom value passed to view controller. */ public void setZoom(float zoom) { documentViewController.setZoom(zoom); } public void doCommonZoomUIUpdates(boolean becauseOfValidFitMode) { // update gui reflectZoomInZoomComboBox(); // Might change fit value if (!becauseOfValidFitMode) setPageFitMode(DocumentViewController.PAGE_FIT_NONE, false); } /** * Returns tree if there is a current page associated with this controller. * * @return true if their is a current page, otherwise false. */ public boolean isCurrentPage() { PageTree pageTree = getPageTree(); if (pageTree == null) return false; Page page = pageTree.getPage(documentViewController.getCurrentPageIndex()); return page != null; } /** * Gives access to the currently opened Document's Catalog's PageTree * * @return PageTree */ public PageTree getPageTree() { if (document == null) return null; return document.getPageTree(); } public void showAnnotationPreviewWindow() { if (annotationSummaryFrame == null) { annotationSummaryFrame = new AnnotationSummaryFrame(this); annotationSummaryFrame.refreshDocumentInstance(); WindowManager.newWindowLocation(annotationSummaryFrame); annotationSummaryFrame.setVisible(true); } // bring the window to the front. annotationSummaryFrame.setVisible(true); annotationSummaryFrame.setState(Frame.NORMAL); annotationSummaryFrame.toFront(); } /** * Sets the ViewerModel's current page index, and updates the display * to show the newly selected page * * @param nPage Index of the Page to show * @see org.icepdf.ri.common.views.DocumentViewControllerImpl#setCurrentPageIndex */ public void showPage(int nPage) { if (nPage >= 0 && nPage < getPageTree().getNumberOfPages()) { documentViewController.setCurrentPageIndex(nPage); updateDocumentView(); } } /** * Adds delta to the ViewerModel's current page index, and updates the display * to show the newly selected page. A positive delta indicates moving to later pages, * and a negative delta would move to a previous page * * @param delta Signed integer that's added to the current page index * @see org.icepdf.ri.common.views.DocumentViewControllerImpl#getCurrentPageIndex * @see org.icepdf.ri.common.views.DocumentViewControllerImpl#setCurrentPageIndex */ public void goToDeltaPage(int delta) { int currPage = documentViewController.getCurrentPageIndex(); int nPage = currPage + delta; int totalPages = getPageTree().getNumberOfPages(); if (totalPages == 0) return; if (nPage >= totalPages) nPage = totalPages - 1; if (nPage < 0) nPage = 0; if (nPage != currPage) { documentViewController.setCurrentPageIndex(nPage); updateDocumentView(); } } public void updateDocumentView() { if (disposed) return; int oldTool = getDocumentViewToolMode(); try { setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); reflectPageChangeInComponents(); PageTree pageTree = getPageTree(); if (currentPageNumberTextField != null) currentPageNumberTextField.setText(Integer.toString(documentViewController.getCurrentPageDisplayValue())); if (numberOfPagesLabel != null) { if (pageTree != null) { Object[] messageArguments = new Object[]{String.valueOf(pageTree.getNumberOfPages())}; MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.toolbar.pageIndicator")); String numberOfPages = formatter.format(messageArguments); numberOfPagesLabel.setText(numberOfPages); } } if (statusLabel != null) { if (pageTree != null) { // progress bar for printing Object[] messageArguments = new Object[]{ String.valueOf(documentViewController.getCurrentPageDisplayValue()), String.valueOf(pageTree.getNumberOfPages()) }; MessageFormat formatter = new MessageFormat( messageBundle.getString("viewer.statusbar.currentPage")); statusLabel.setText(formatter.format(messageArguments)); } } } catch (Exception e) { logger.log(Level.FINE, "Error updating page view.", e); } finally { setDisplayTool(oldTool); } } /** * Rotates the page visualization by 90 degrees in a counter-clockwise * direction. */ public void rotateLeft() { documentViewController.setRotateLeft(); // rest fit page mode, if any setPageFitMode(documentViewController.getFitMode(), true); } /** * Rotates the page visualization by 90 degrees in a clockwise * direction. */ public void rotateRight() { documentViewController.setRotateRight(); // rest fit page mode, if any setPageFitMode(documentViewController.getFitMode(), true); } public boolean isDocumentFitMode(final int fitMode) { return (documentViewController.getFitMode() == fitMode); } public boolean isDocumentViewMode(final int viewMode) { return (documentViewController.getViewMode() == viewMode); } public void setPageViewSinglePageConButton(JToggleButton btn) { singlePageViewContinuousButton = btn; btn.addItemListener(this); } public void setPageViewFacingPageConButton(JToggleButton btn) { facingPageViewContinuousButton = btn; btn.addItemListener(this); } public void setPageViewSinglePageNonConButton(JToggleButton btn) { singlePageViewNonContinuousButton = btn; btn.addItemListener(this); } public void setPageViewFacingPageNonConButton(JToggleButton btn) { facingPageViewNonContinuousButton = btn; btn.addItemListener(this); } /** * Set the ViewerModel's fit setting to fit the whole page, and update the display * * @param fitMode fit mode. * @param refresh true to refresh document page view. */ public void setPageFitMode(final int fitMode, boolean refresh) { if (!refresh && documentViewController.getFitMode() == fitMode) { return; } documentViewController.setFitMode(fitMode); // update button state. reflectZoomInZoomComboBox(); reflectFitInFitButtons(); } public void setFullScreenMode() { setPageViewMode(DocumentViewControllerImpl.FULL_SCREEN_VIEW, true); } public void setPageViewMode(final int viewMode, boolean refresh) { if (!refresh && documentViewController.getViewMode() == viewMode) { return; } documentViewController.setViewType(viewMode); // update button state. reflectDocumentViewModeInButtons(); reflectFitInFitButtons(); } public void setDocumentToolMode(final int toolType) { // nothing to do tool should already be setup. if (toolType == 0 || documentViewController.isToolModeSelected(toolType)) return; // set the tool mode documentViewController.setToolMode(toolType); // update the button state reflectToolInToolButtons(); } /** * If the utility pane is currently visible * * @return true if pane is visible false otherwise. */ public boolean isUtilityPaneVisible() { return (utilityTabbedPane != null) && utilityTabbedPane.isVisible(); } public boolean isAnnotationUtilityPaneVisible() { return isComponentUtilityPaneVisible(annotationPanel); } public boolean isBookmarkUtilityPaneVisible() { return isComponentUtilityPaneVisible(outlinesScrollPane); } public boolean isComponentUtilityPaneVisible(final Component component) { return isUtilityPaneVisible() && component != null && component.isVisible(); } /** * Makes the component visible or invisible. * * @param visible true to make the component visible; false to make it * invisible. */ public void setUtilityPaneVisible(boolean visible) { if (utilityTabbedPane != null) { utilityTabbedPane.setVisible(visible); } if (utilityAndDocumentSplitPane != null) { if (visible) { // use the last split pane value. utilityAndDocumentSplitPane.setDividerLocation( utilityAndDocumentSplitPaneLastDividerLocation); utilityAndDocumentSplitPane.setDividerSize(8); } else { // if we're hiding the panel then we grab the last know value // and set the width to zero or invisible. int divLoc = utilityAndDocumentSplitPane.getDividerLocation(); if (divLoc > 5) { utilityAndDocumentSplitPaneLastDividerLocation = divLoc; } utilityAndDocumentSplitPane.setDividerSize(0); } } reflectStateInComponents(); } /** * Set the form highlight mode for the viewer. * * @param visible true enables the highlight mode, otherwise; false. */ private void setFormHighlightVisible(boolean visible) { viewModel.setIsWidgetAnnotationHighlight(visible); // update annotation state for highlight document.setFormHighlight(viewModel.isWidgetAnnotationHighlight()); // repaint the page. documentViewController.getDocumentView().repaint(); } /** * Set the form highlight mode for the viewer. * * @param visible true enables the highlight mode, otherwise; false. */ private void setAnnotationEditModeVisible(boolean visible) { viewModel.setIsAnnotationEditingMode(visible); // repaint the page. documentViewController.getDocumentView().repaint(); } /** * Flips the visibility of the utility pane to the opposite of what it was * * @see #setUtilityPaneVisible(boolean) */ public void toggleUtilityPaneVisibility() { setUtilityPaneVisible(!isUtilityPaneVisible()); } /** * Flips the visibility of the form highlight functionality ot hte opposite of what it was. */ public void toggleFormHighlight() { viewModel.setIsWidgetAnnotationHighlight(!viewModel.isWidgetAnnotationHighlight()); // write the property for next viewing. propertiesManager.getPreferences().putBoolean(ViewerPropertiesManager.PROPERTY_VIEWPREF_FORM_HIGHLIGHT, viewModel.isWidgetAnnotationHighlight()); reflectFormHighlightButtons(); setFormHighlightVisible(viewModel.isWidgetAnnotationHighlight()); } /** * Flips the visibility of the form highlight functionality ot hte opposite of what it was. */ public void toggleAnnotationEditMode() { setAnnotationEditMode(!viewModel.isAnnotationEditingMode()); } public void setAnnotationEditMode(boolean enabled) { viewModel.setIsAnnotationEditingMode(enabled); // write the property for next viewing. propertiesManager.getPreferences().putBoolean(ViewerPropertiesManager.PROPERTY_VIEWPREF_ANNOTATION_EDIT_MODE, viewModel.isAnnotationEditingMode()); reflectAnnotationEditModeButtons(); setAnnotationEditModeVisible(viewModel.isAnnotationEditingMode()); } /** * Method to select the currently visible tab in the utility pane * Because tabs can be hidden via the properties file, we'll want to check first * whether the desired panel even exists * * @param comp to select * @return true on successful selection */ protected boolean safelySelectUtilityPanel(Component comp) { if ((utilityTabbedPane != null) && (comp != null)) { if (utilityTabbedPane.indexOfComponent(comp) > -1) { utilityTabbedPane.setSelectedComponent(comp); return true; } } return false; } protected boolean isUtilityTabSelected(Component comp) { if (utilityTabbedPane != null && comp != null) { return utilityTabbedPane.getSelectedComponent() == comp; } return false; } public void showSearch() { final SearchToolBar searchBar = (SearchToolBar) quickSearchToolBar; final String selectedText = documentViewController.getSelectedText(); if (searchBar != null) { if (selectedText != null && !selectedText.trim().isEmpty()) { searchBar.setSearchText(selectedText.trim()); } searchBar.focusTextField(); } else { showSearchPanel(); } } /** * Make the Search pane visible, and if necessary, the utility pane that encloses it * * @see #setUtilityPaneVisible(boolean) */ public void showSearchPanel() { final String selectedText = documentViewController.getSelectedText(); if (selectedText != null && !selectedText.trim().isEmpty()) { showSearchPanel(selectedText.trim()); } else { showSearchPanel(searchPanel.getSearchPhrase()); } } public void showSearchPanel(final String searchPhrase) { searchPanel.setSearchPhrase(searchPhrase); if (utilityTabbedPane != null && searchPanel != null) { // make sure the utility pane is visible if (!utilityTabbedPane.isVisible()) { setUtilityPaneVisible(true); } // if utility pane is shown then select the search tab and request focus if (isUtilityPaneVisible()) { if (utilityTabbedPane.getSelectedComponent() != searchPanel) { // select the search panel safelySelectUtilityPanel(searchPanel); } // request focus searchPanel.requestFocus(); } } } public void nextSearchResult() { if (documentSearchController != null) { documentSearchController.nextSearchHit(); } } public void previousSearchResult() { if (documentSearchController != null) { documentSearchController.previousSearchHit(); } } /** * Make the Annotation Link Panel visible, and if necessary, the utility pane that encloses it * * @param selectedDestination the destination to show in the panel * @see #setUtilityPaneVisible(boolean) */ public void showAnnotationDestinationPanel(DestinationComponent selectedDestination) { if (utilityTabbedPane != null) { // Pass the selected annotation to the link panel if (annotationPanel != null && selectedDestination != null) { annotationPanel.setEnabled(true); } setUtilityPaneVisible(true); // select the annotationPanel tab if (annotationPanel != null) { boolean show = safelySelectUtilityPanel(annotationPanel); if (show) { annotationPanel.setSelectedTab(ViewerPropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION_DESTINATIONS); } } } } public void showAnnotationDestinationPanel(TreePath path) { if (utilityTabbedPane != null) { // Pass the selected annotation to the link panel if (annotationPanel != null && path != null) { annotationPanel.setEnabled(true); } setUtilityPaneVisible(true); // select the annotationPanel tab if (annotationPanel != null) { boolean show = safelySelectUtilityPanel(annotationPanel); if (show) { annotationPanel.getDestinationsPanel().selectDestinationPath(path); annotationPanel.setSelectedTab(ViewerPropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION_DESTINATIONS); } } } } /** * Make the Annotation Link Panel visible, and if necessary, the utility pane that encloses it * * @param forceShow Forces the utility pane to be visible * @see #setUtilityPaneVisible(boolean) */ public void showAnnotationPanel(final boolean forceShow) { final boolean isShowing = showUtilityPanel(annotationPanel, forceShow); if (annotationPanel != null && isShowing) { annotationPanel.setSelectedTab(ViewerPropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION_MARKUP); } } /** * Shows the given component in the utility panel * * @param panelToShow The component to show * @param forceShow Whether to force showing the utility panel or not * @return whether the panel has been selected or not */ protected boolean showUtilityPanel(final Component panelToShow, final boolean forceShow) { if (utilityTabbedPane != null && panelToShow != null) { // Pass the selected annotation to the link panel panelToShow.setEnabled(true); } setUtilityPaneVisible(forceShow || (!isUtilityPaneVisible() || !isUtilityTabSelected(panelToShow) || utilityAndDocumentSplitPane.getLeftComponent() != utilityTabbedPane)); // select the annotationPanel tab if (!isUtilityTabSelected(panelToShow)) { return safelySelectUtilityPanel(panelToShow); } else { return true; } } /** * Make the outline panel panel visible * * @param forceShow Whether to force showing the utility pane or not */ public void showOutlinePanel(final boolean forceShow) { showUtilityPanel(outlinesScrollPane, forceShow); } /** * Show a dialog, listing every page in the PDF Document, for the user * to select which page to show. * * @see #showPage(int) */ public void showPageSelectionDialog() { int numPages = getPageTree().getNumberOfPages(); Object[] s = new Object[numPages]; for (int i = 0; i < numPages; i++) { s[i] = Integer.toString(i + 1); } Object initialSelection = s[documentViewController.getCurrentPageIndex()]; Object ob = JOptionPane.showInputDialog( viewer, messageBundle.getString("viewer.dialog.goToPage.description.label"), messageBundle.getString("viewer.dialog.goToPage.title"), JOptionPane.QUESTION_MESSAGE, null, s, initialSelection); if (ob != null) { try { int pageIndex = Integer.parseInt(ob.toString()) - 1; showPage(pageIndex); } catch (NumberFormatException nfe) { logger.log(Level.FINE, "Error selecting page number."); } } } /** * Method to try to read any ViewerPreferences present in the document, and apply them * Otherwise we will try to check the properties file for any overriding to these values * * @param catalog to lookup view preferences from * @param propertiesManager to check properties in */ protected void applyViewerPreferences(Catalog catalog, ViewerPropertiesManager propertiesManager) { if (catalog == null) { return; } ViewerPreferences viewerPref = catalog.getViewerPreferences(); // Hide the toolbar? if ((viewerPref != null) && (viewerPref.hasHideToolbar())) { if (viewerPref.getHideToolbar()) { if (completeToolBar != null) { completeToolBar.setVisible(false); } } } else { if (completeToolBar != null) { completeToolBar.setVisible( !propertiesManager.getPreferences().getBoolean( ViewerPropertiesManager.PROPERTY_VIEWPREF_HIDETOOLBAR, false)); } } // Hide the menubar? if (viewer instanceof JFrame) { final JMenuBar menuBar = ((JFrame) viewer).getJMenuBar(); if (viewerPref != null && viewerPref.hasHideMenubar()) { if (viewerPref.getHideMenubar()) { if (menuBar != null) { menuBar.setVisible(false); } } } else { if (menuBar != null) { menuBar.setVisible( !propertiesManager.getPreferences().getBoolean( ViewerPropertiesManager.PROPERTY_VIEWPREF_HIDEMENUBAR, false)); } } } // Fit the GUI frame to the size of the document? if (viewerPref != null && viewerPref.hasFitWindow()) { if (viewerPref.getFitWindow()) { if (viewer != null) { viewer.setSize(documentViewController.getDocumentView().getDocumentSize()); } } } else { if (propertiesManager.getPreferences().getBoolean( ViewerPropertiesManager.PROPERTY_VIEWPREF_FITWINDOW, false) && viewer != null) { viewer.setSize(documentViewController.getDocumentView().getDocumentSize()); } } } /** * Gives access to this Controller's ViewerModel * * @return The Controller's ViewerModel * @see ViewModel */ public ViewModel getViewModel() { return viewModel; } // // Controller interface // @Override public PrintHelperFactory getPrintHelperFactory() { return PrintHelperFactoryImpl.getInstance(); } /** * A Document is the root of the object hierarchy, giving access * to the contents of a PDF file. * Significantly: getDocument().getCatalog().getPageTree().getPage(int pageIndex) * gives access to each Page, so that it might be drawn. * * @return Document root of the PDF file */ public Document getDocument() { return document; } /** * When viewing a PDF file, one or more pages may be viewed at * a single time, but this is the single page which is most * predominantly being displayed. * * @return The zero-based index of the current Page being displayed */ public int getCurrentPageNumber() { return documentViewController.getCurrentPageIndex(); } // // ActionListener interface // /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void actionPerformed(ActionEvent event) { Object source = event.getSource(); if (source == null) return; boolean cancelSetFocus = false; try { if (source == openFileMenuItem || source == openFileButton) { cancelSetFocus = true; openFile(); } else if (source == openURLMenuItem) { cancelSetFocus = true; openURL(); } else if (source == closeMenuItem) { boolean isCanceled = saveChangesDialog(); if (!isCanceled) { closeDocument(); } } else if (source == saveFileMenuItem || source == saveFileButton) { saveFile(); } else if (source == exportDocumentFileMenuItem) { exportDocument(); } else if (source == saveAsFileMenuItem) { saveFileAs(); } else if (source == sendMailMenuItem) { MailSender.sendMail(this); } else if (source == exportTextMenuItem) { exportText(); } else if (source == exitMenuItem) { boolean isCanceled = saveChangesDialog(); if (!isCanceled && windowManagementCallback != null) { windowManagementCallback.disposeWindow(this, viewer, propertiesManager.getPreferences()); } } else if (source == showHideToolBarMenuItem) { toggleToolBarVisibility(); } else if (source == minimiseAllMenuItem) { if (getWindowManagementCallback() != null) { getWindowManagementCallback().minimiseAllWindows(); } } else if (source == bringAllToFrontMenuItem) { if (getWindowManagementCallback() != null) { getWindowManagementCallback().bringAllWindowsToFront(this); } } else if (windowListMenuItems != null && windowListMenuItems.contains(source)) { final int index = windowListMenuItems.indexOf(source); if (getWindowManagementCallback() != null) { getWindowManagementCallback().bringWindowToFront(index); } } else if (source == aboutMenuItem) { showAboutDialog(); } else if (source == fontInformationMenuItem) { showDocumentFontDialog(); } else if (source == preferencesMenuItem) { SwingUtilities.invokeLater(this::showViewerPreferences); } else if (document != null) { // get document previous icon int documentIcon = getDocumentViewToolMode(); try { // set cursor for document view setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); if (source == propertiesMenuItem) { Runnable doSwingWork = this::showDocumentProperties; SwingUtilities.invokeLater(doSwingWork); } else if (source == permissionsMenuItem) { SwingUtilities.invokeLater(this::showDocumentPermissionsDialog); } else if (source == informationMenuItem) { SwingUtilities.invokeLater(this::showDocumentInformationDialog); } else if (source == printSetupMenuItem) { SwingUtilities.invokeLater(this::showPrintSetupDialog); } else if (source == printMenuItem) { print(true); } else if (source == printButton) { print(true); // Used to be 'false' PDF-86 } else if (source == undoMenuItem) { documentViewController.undo(); // refresh undo buttons. reflectUndoCommands(); } else if (source == redoMenuItem) { documentViewController.redo(); reflectUndoCommands(); } else if (source == deleteMenuItem) { documentViewController.deleteCurrentAnnotation(); reflectUndoCommands(); } else if (source == copyMenuItem || source == copyContextMenuItem) { if (document != null && havePermissionToExtractContent() && !(documentViewController.getDocumentViewModel().isSelectAll() && document.getNumberOfPages() > MAX_SELECT_ALL_PAGE_COUNT)) { // get the text. StringSelection stringSelection = new StringSelection( documentViewController.getFlatSelectedText()); Toolkit.getDefaultToolkit().getSystemClipboard() .setContents(stringSelection, stringSelection); } else { Runnable doSwingWork = () -> org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.information.copyAll.title", "viewer.dialog.information.copyAll.msg", MAX_SELECT_ALL_PAGE_COUNT); SwingUtilities.invokeLater(doSwingWork); } } else if (source == selectAllMenuItem) { // check to see how many page are in the document documentViewController.selectAllText(); } else if (source == deselectAllMenuItem) { documentViewController.clearSelectedText(); } else if (source == fitActualSizeMenuItem) { // Clicking only seems to invoke an itemStateChanged() event, // so this is probably redundant setPageFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE, false); } else if (source == fitPageMenuItem) { // Clicking only seems to invoke an itemStateChanged() event // so this is probably redundant setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false); } else if (source == fitWidthMenuItem) { // Clicking only seems to invoke an itemStateChanged() event // so this is probably redundant setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH, false); } else if (source == fullScreenMenuItem || source == fullScreenButton) { setFullScreenMode(); cancelSetFocus = true; } else if (source == zoomInMenuItem || source == zoomInButton) { zoomIn(); } else if (source == zoomOutMenuItem || source == zoomOutButton) { zoomOut(); } else if (source == rotateLeftMenuItem || source == rotateLeftButton) { rotateLeft(); } else if (source == rotateRightMenuItem || source == rotateRightButton) { rotateRight(); } else if (source == showHideUtilityPaneMenuItem || source == showHideUtilityPaneButton) { toggleUtilityPaneVisibility(); } else if (source == showAnnotationUtilityPaneButton) { showAnnotationPanel(false); } else if (source == showBookmarkUtilityPaneButton) { showOutlinePanel(false); } else if (source == formHighlightButton) { toggleFormHighlight(); } else if (source == annotationEditingModeButton) { toggleAnnotationEditMode(); } else if (source == firstPageMenuItem || source == firstPageButton) { showPage(0); } else if (source == previousPageMenuItem || source == previousPageButton) { DocumentView documentView = documentViewController.getDocumentView(); goToDeltaPage(-documentView.getPreviousPageIncrement()); } else if (source == nextPageMenuItem || source == nextPageButton) { DocumentView documentView = documentViewController.getDocumentView(); goToDeltaPage(documentView.getNextPageIncrement()); } else if (source == lastPageMenuItem || source == lastPageButton) { showPage(getPageTree().getNumberOfPages() - 1); } else if (source == searchMenuItem || source == searchButton) { cancelSetFocus = true; showSearch(); } else if (source == advancedSearchMenuItem) { cancelSetFocus = true; showSearchPanel(); } else if (source == searchNextMenuItem) { nextSearchResult(); } else if (source == searchPreviousMenuItem) { previousSearchResult(); } else if (source == goToPageMenuItem) { showPageSelectionDialog(); } else if (source == currentPageNumberTextField) { showPageFromTextField(); } else if (source == annotationSummaryButton || source == annotationPreviewMenuItem) { showAnnotationPreviewWindow(); } else { logger.log(Level.FINE, "Unknown action event: " + source); } } finally { // set view pane back to previous icon setDisplayTool(documentIcon); } } } catch (Exception e) { String message = e.getMessage() == null || e.getMessage().isEmpty() ? e.toString() : e.getMessage(); Runnable doSwingWork = () -> org.icepdf.ri.util.Resources.showMessageDialog( viewer, JOptionPane.INFORMATION_MESSAGE, messageBundle, "viewer.dialog.error.exception.title", "viewer.dialog.error.exception.msg", message); SwingUtilities.invokeLater(doSwingWork); logger.log(Level.FINE, "Error processing action event.", e); } if (!cancelSetFocus) { // setup focus to ensure page up and page down keys work documentViewController.requestViewFocusInWindow(); } } // // FocusListener interface // /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void focusGained(FocusEvent e) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void focusLost(FocusEvent e) { Object src = e.getSource(); if (src == null) return; if (src == currentPageNumberTextField) { String fieldValue = currentPageNumberTextField.getText(); String modelValue = Integer.toString(documentViewController.getCurrentPageDisplayValue()); if (!fieldValue.equals(modelValue)) currentPageNumberTextField.setText(modelValue); } } // // ItemListener interface // /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void itemStateChanged(ItemEvent e) { Object source = e.getSource(); if (source == null) return; boolean doSetFocus = false; int tool = getDocumentViewToolMode(); setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); try { if (source == zoomComboBox) { if (e.getStateChange() == ItemEvent.SELECTED) { setZoomFromZoomComboBox(); // Since combo box is an entry component, we don't force focus to the document } } else if (source == annotationPrivacyComboBox) { if (e.getStateChange() == ItemEvent.SELECTED) { setAnnotationPrivacy(annotationPrivacyComboBox.getSelectedIndex() == 0); } } else if (source == fitActualSizeButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE, false); } } else if (source == fitHeightButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false); } } else if (source == fitWidthButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH, false); } } // tool selection - a call to setDocumentToolMode will generate // the property change even which the view and child components // will adjust to. else if (source == panToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_PAN; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_PAN); } } else if (source == zoomInToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN); } } else if (source == zoomDynamicToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC); } } else if (source == textSelectToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION); } } // annotations selection and creation tools. else if (source == selectToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_SELECTION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SELECTION); } } else if (source == linkAnnotationToolButton || source == linkAnnotationPropertiesToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION); } } else if (checkAnnotationButton(source, highlightAnnotationToolButton, highlightAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION); } } else if (source == redactionAnnotationToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_REDACTION_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_REDACTION_ANNOTATION); } } else if (checkAnnotationButton(source, strikeOutAnnotationToolButton, strikeOutAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION); } } else if (checkAnnotationButton(source, underlineAnnotationToolButton, underlineAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION); } } else if (checkAnnotationButton(source, lineAnnotationToolButton, lineAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION); } } else if (checkAnnotationButton(source, lineArrowAnnotationToolButton, lineArrowAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION); } } else if (checkAnnotationButton(source, squareAnnotationToolButton, squareAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION); } } else if (checkAnnotationButton(source, circleAnnotationToolButton, circleAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION); } } else if (checkAnnotationButton(source, inkAnnotationToolButton, inkAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION); } } else if (source == freeTextAnnotationToolButton || source == freeTextAnnotationPropertiesToolButton) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION); } } else if (checkAnnotationButton(source, textAnnotationToolButton, textAnnotationPropertiesToolButton)) { if (e.getStateChange() == ItemEvent.SELECTED) { tool = DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION; setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION); } } // page view events, changes the page layout component. else if (source == facingPageViewNonContinuousButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageViewMode( DocumentViewControllerImpl.TWO_PAGE_RIGHT_VIEW, false); } } else if (source == facingPageViewContinuousButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageViewMode( DocumentViewControllerImpl.TWO_COLUMN_RIGHT_VIEW, false); } } else if (source == singlePageViewNonContinuousButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageViewMode( DocumentViewControllerImpl.ONE_PAGE_VIEW, false); } } else if (source == singlePageViewContinuousButton) { if (e.getStateChange() == ItemEvent.SELECTED) { setPageViewMode( DocumentViewControllerImpl.ONE_COLUMN_VIEW, false); } } // if (doSetFocus) { // // setup focus to ensure page up and page down keys work // documentViewController.requestViewFocusInWindow(); // } } finally { setDisplayTool(tool); } } private static boolean checkAnnotationButton(final Object source, final AnnotationColorToggleButton button, final JToggleButton propertiesButton) { return source == button || (button != null && source == button.getColorButton()) || source == propertiesButton; } // // TreeSelectionListener interface // /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void valueChanged(TreeSelectionEvent e) { if (outlinesTree == null) return; TreePath treePath = outlinesTree.getSelectionPath(); if (treePath == null) return; OutlineItemTreeNode node = (OutlineItemTreeNode) treePath.getLastPathComponent(); followOutlineItem(node); } public void followOutlineItem(OutlineItemTreeNode node) { OutlineItem o = node.getOutlineItem(); followOutlineItem(o); // return focus so that dropDownArrowButton keys will work on list outlinesTree.requestFocus(); } public void followDestinationItem(NameTreeNode node) { if (node.getReference() != null && node.isLeaf()) { Object tmp = node.getReference(); Library library = getDocument().getCatalog().getLibrary(); if (tmp instanceof Reference) { tmp = library.getObject((Reference) tmp); } Destination dest = new Destination(library, tmp); dest.setNamedDestination(node.getName().toString()); // set the focus. PageComponentSelector.SelectDestinationComponent(this, dest); } } // // WindowListener interface // /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowActivated(WindowEvent e) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowClosed(WindowEvent e) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowClosing(WindowEvent e) { // We have to call dispose() before using the WindowManagementCallback, because the // WindowManagementCallback may well call System.exit(). If System.exit() is called // before dispose() closes our temporary files, then they won't be deleted. // So, we need to temporarily save what we'll need, for our later invocation of // WindowManagementCallback.disposeWindow(), that dispose() would otherwise trash WindowManagementCallback wc = windowManagementCallback; Frame v = viewer; // save last used location. WindowManager.saveViewerState(v); // assign view properties so that they can be saved on close DocumentViewController viewControl = getDocumentViewController(); Preferences viewerPreferences = ViewerPropertiesManager.getInstance().getPreferences(); viewerPreferences.putInt(ViewerPropertiesManager.PROPERTY_DEFAULT_PAGEFIT, viewControl.getFitMode()); viewerPreferences.putInt("document.viewtype", viewControl.getViewMode()); // last rotation. if (documentViewController.getDocumentViewModel() != null) { float rotation = documentViewController.getDocumentViewModel().getViewRotation(); viewerPreferences.putFloat(PROPERTY_DEFAULT_ROTATION, rotation); } if (viewControl.getZoom() > 0) { viewerPreferences.putFloat(PROPERTY_DEFAULT_ZOOM_LEVEL, viewControl.getZoom()); } // save changes and close window boolean cancelled = saveChangesDialog(); String origFilePath = document != null ? document.getDocumentOrigin() : null; if (!cancelled) { // dispose the document and other resources. dispose(); if (saveFilePath != null && !saveFilePath.isEmpty() && origFilePath != null) { try { File tmpFile = new File(saveFilePath); if (tmpFile.exists()) { Files.move(tmpFile.toPath(), new File(origFilePath).toPath(), StandardCopyOption.REPLACE_EXISTING); } } catch (IOException ex) { logger.log(Level.FINE, "IO Exception ", e); } } if (wc != null) { wc.disposeWindow(this, v, viewerPreferences); } } } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowDeactivated(WindowEvent e) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowDeiconified(WindowEvent e) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowIconified(WindowEvent e) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void windowOpened(WindowEvent e) { } // // ComponentAdapter class // @Override public void componentResized(ComponentEvent e) { if (viewer != null) { WindowManager.saveViewerState(viewer); } } @Override public void componentMoved(ComponentEvent e) { if (viewer != null) { WindowManager.saveViewerState(viewer); } } // // DropTargetListener interface // /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void dragEnter(DropTargetDragEvent event) { if (!isDragAcceptable(event)) { event.rejectDrag(); } } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void dragOver(DropTargetDragEvent event) { } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void dropActionChanged(DropTargetDragEvent event) { if (!isDragAcceptable(event)) { event.rejectDrag(); } } /** * Handle drop event when a user drags and drops one or more files onto the viewer frame. * * @param event information about the drag and drop data. */ public void drop(DropTargetDropEvent event) { try { // check to make sure that event type is ok if (!isDropAcceptable(event)) { event.rejectDrop(); return; } // accept the drop action, must do this to proceed event.acceptDrop(DnDConstants.ACTION_COPY); Transferable transferable = event.getTransferable(); DataFlavor[] flavors = transferable.getTransferDataFlavors(); for (DataFlavor dataFlavor : flavors) { // Check to see if a file was dropped on the viewer frame if (dataFlavor.equals(DataFlavor.javaFileListFlavor)) { List fileList = (List) transferable.getTransferData(dataFlavor); // load all the files that where dragged for (Object aFileList : fileList) { File file = (File) aFileList; if (file.getName().toLowerCase().endsWith(".pdf")) { openFileInSomeViewer(file); ViewModel.setDefaultFile(file); } } } else if (dataFlavor.equals(DataFlavor.stringFlavor)) { String s = (String) transferable.getTransferData(dataFlavor); int startIndex = s.toLowerCase().indexOf("https://"); int endIndex = s.toLowerCase().indexOf(".pdf"); if (startIndex >= 0 && endIndex >= 0) { s = s.substring(startIndex, endIndex + 4); URL url; try { url = new URL(s); openURLInSomeViewer(url); ViewModel.setDefaultURL(s); } catch (MalformedURLException e) { // eat the error } } } } event.dropComplete(true); } catch (IOException ioe) { logger.log(Level.FINE, "IO exception during file drop", ioe); } catch (UnsupportedFlavorException ufe) { logger.log(Level.FINE, "Drag and drop not supported", ufe); } } /** * Controller takes AWT/Swing events, and maps them to its own events * related to PDF Document manipulation */ public void dragExit(DropTargetEvent event) { } protected void prepareKeyMap(JComponent component) { addKeyAction(component, KEY_CODE_SAVE, MODIFIER_SAVE, new BaseAction(this::saveFile)); addKeyAction(component, KEY_CODE_SAVE_AS, MODIFIER_SAVE_AS, new BaseAction(this::saveFileAs)); addKeyAction(component, KEY_CODE_EXPORT_TEXT, MODIFIER_EXPORT_TEXT, new BaseAction(this::exportText)); addKeyAction(component, KEY_CODE_PRINT_SETUP, MODIFIER_PRINT_SETUP, new BaseAction(this::showPrintSetupDialog)); addKeyAction(component, KEY_CODE_PRINT, MODIFIER_PRINT, new BaseAction(() -> print(true))); addKeyAction(component, KEY_CODE_FIT_ACTUAL, MODIFIER_FIT_ACTUAL, new BaseAction(() -> setPageFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE, false))); addKeyAction(component, KEY_CODE_FIT_PAGE, MODIFIER_FIT_PAGE, new BaseAction(() -> setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false))); addKeyAction(component, KEY_CODE_FIT_WIDTH, MODIFIER_FIT_WIDTH, new BaseAction(() -> setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH, false))); addKeyAction(component, KEY_CODE_ZOOM_IN, MODIFIER_ZOOM_IN, new BaseAction(this::zoomIn)); addKeyAction(component, KEY_CODE_ZOOM_OUT, MODIFIER_ZOOM_OUT, new BaseAction(this::zoomOut)); addKeyAction(component, KEY_CODE_ROTATE_LEFT, MODIFIER_ROTATE_LEFT, new BaseAction(this::rotateLeft)); addKeyAction(component, KEY_CODE_ROTATE_RIGHT, MODIFIER_ROTATE_RIGHT, new BaseAction(this::rotateRight)); addKeyAction(component, KEY_CODE_FIRST_PAGE, MODIFIER_FIRST_PAGE, new BaseAction(() -> showPage(0))); addKeyAction(component, KEY_CODE_PREVIOUS_PAGE, MODIFIER_PREVIOUS_PAGE, new BaseAction(() -> goToDeltaPage(-(documentViewController.getDocumentView().getPreviousPageIncrement())))); addKeyAction(component, KEY_CODE_NEXT_PAGE, MODIFIER_NEXT_PAGE, new BaseAction(() -> goToDeltaPage(documentViewController.getDocumentView().getNextPageIncrement()))); addKeyAction(component, KEY_CODE_LAST_PAGE, MODIFIER_LAST_PAGE, new BaseAction(() -> showPage(getPageTree().getNumberOfPages() - 1))); addKeyAction(component, KEY_CODE_SEARCH, MODIFIER_SEARCH, new BaseAction(this::showSearch)); addKeyAction(component, KEY_CODE_SEARCH, MODIFIER_ADVANCED_SEARCH, new BaseAction(this::showSearchPanel)); addKeyAction(component, KEY_CODE_SEARCH_PREVIOUS, MODIFIER_SEARCH_PREVIOUS, new BaseAction(this::previousSearchResult)); addKeyAction(component, KEY_CODE_SEARCH_NEXT, MODIFIER_SEARCH_NEXT, new BaseAction(this::nextSearchResult)); addKeyAction(component, KEY_CODE_GOTO, MODIFIER_GOTO, new BaseAction(this::showPageSelectionDialog)); addKeyAction(component, KEY_CODE_PREFERENCES, MODIFIER_PREFERENCES, new BaseAction(this::showViewerPreferences)); } protected final void addKeyAction(final JComponent component, final int keyCode, final int modifier, final BaseAction action) { final InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); final ActionMap actionMap = component.getActionMap(); final String key = keyCode + "-" + modifier; inputMap.put(KeyStroke.getKeyStroke(keyCode, modifier), key); actionMap.put(key, action); } @FunctionalInterface protected interface ActionMethod { void doAction(); } protected class BaseAction extends AbstractAction { private final ActionMethod action; public BaseAction(ActionMethod action) { this.action = action; } @Override public void actionPerformed(ActionEvent actionEvent) { int documentIcon = getDocumentViewToolMode(); setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); try { action.doAction(); } finally { // set view pain back to previous icon setDisplayTool(documentIcon); } } } private final class NumberTextFieldKeyListener extends KeyAdapter { @Override public void keyTyped(KeyEvent e) { JTextField currentPageNumberTextField = (JTextField) e.getComponent(); char c = e.getKeyChar(); if (c == KeyEvent.VK_ESCAPE) { String fieldValue = currentPageNumberTextField.getText(); String modelValue = Integer.toString( documentViewController.getCurrentPageDisplayValue()); if (!fieldValue.equals(modelValue)) currentPageNumberTextField.setText(modelValue); } } } /** * Listen for property change events from the page view. This method * acts like a mediator passing on the new states to the interested parties. * * @param evt property change event */ public void propertyChange(PropertyChangeEvent evt) { Object newValue = evt.getNewValue(); Object oldValue = evt.getOldValue(); String propertyName = evt.getPropertyName(); switch (propertyName) { case PropertyConstants.DOCUMENT_CURRENT_PAGE: if (currentPageNumberTextField != null && newValue instanceof Integer) { updateDocumentView(); } break; // text selected, case PropertyConstants.TEXT_SELECTED: { // enable the copy menu boolean canExtract = havePermissionToExtractContent(); setEnabled(copyMenuItem, canExtract); setEnabled(deselectAllMenuItem, canExtract); break; } // text deselected case PropertyConstants.TEXT_DESELECTED: { // disable the copy menu boolean canExtract = havePermissionToExtractContent(); setEnabled(copyMenuItem, false); setEnabled(deselectAllMenuItem, false); setEnabled(selectAllMenuItem, canExtract); break; } // select all case PropertyConstants.TEXT_SELECT_ALL: { boolean canExtract = havePermissionToExtractContent(); setEnabled(selectAllMenuItem, false); setEnabled(deselectAllMenuItem, canExtract); setEnabled(copyMenuItem, canExtract); break; } // annotation is selected or has focus case PropertyConstants.ANNOTATION_SELECTED: case PropertyConstants.ANNOTATION_FOCUS_GAINED: // enable the delete menu setEnabled(deleteMenuItem, true); // get the current selected tool, we only care about the select tool or // link annotation tool. if (documentViewController.getToolMode() == DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { AnnotationComponent annotationComponent = (AnnotationComponent) newValue; if (annotationComponent != null && annotationComponent.getAnnotation() != null) { // set the annotationPane with the new annotation component if (logger.isLoggable(Level.FINE)) { logger.fine("selected annotation " + annotationComponent); } showAnnotationPanel(true); } } break; // annotation is selected or has focus case PropertyConstants.DESTINATION_FOCUS_GAINED: case PropertyConstants.DESTINATION_FOCUS_LOST: // enable the delete menu setEnabled(deleteMenuItem, true); // get the current selected tool, we only care about the select tool or // link annotation tool. if (documentViewController.getToolMode() == DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { DestinationComponent destinationComponent = (DestinationComponent) newValue; if (destinationComponent != null && destinationComponent.getDestination() != null) { // set the annotationPane with the new annotation component if (logger.isLoggable(Level.FINE)) { logger.fine("selected destination " + destinationComponent); } showAnnotationDestinationPanel(destinationComponent); } } break; // annotation is deselected case PropertyConstants.ANNOTATION_DESELECTED: if (documentViewController.getToolMode() == DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { if (logger.isLoggable(Level.FINE)) { logger.fine("Deselected current annotation"); } // disable the delete menu setEnabled(deleteMenuItem, false); } break; // annotation bounds have changed or annotation as been deleted or added. case PropertyConstants.ANNOTATION_BOUNDS: case PropertyConstants.ANNOTATION_DELETED: case PropertyConstants.ANNOTATION_ADDED: // check to see if undo/redo can be enabled/disabled. reflectUndoCommands(); break; // divider has been moved, save the location as it changes. case JSplitPane.LAST_DIVIDER_LOCATION_PROPERTY: JSplitPane sourceSplitPane = (JSplitPane) evt.getSource(); int dividerLocation = (Integer) evt.getNewValue(); if (sourceSplitPane.getDividerLocation() != dividerLocation) { if (propertiesManager != null && dividerLocation > 5) { utilityAndDocumentSplitPaneLastDividerLocation = dividerLocation; propertiesManager.getPreferences().putInt( ViewerPropertiesManager.PROPERTY_DIVIDER_LOCATION, utilityAndDocumentSplitPaneLastDividerLocation); } } break; case ANNOTATION_COLOR_PROPERTY_PANEL_CHANGE: getColorButtons().stream().filter(Objects::nonNull).forEach(AbstractColorButton::refreshColorPanel); if (annotationPanel != null && annotationPanel.getMarkupAnnotationPanel() != null) { annotationPanel.getMarkupAnnotationPanel().refreshColorPanel(); } if (annotationSummaryFrame != null && annotationSummaryFrame.getAnnotationSummaryPanel() != null) { annotationSummaryFrame.getAnnotationSummaryPanel().refreshDocumentInstance(); } break; case PropertyConstants.DESTINATION_ADDED: // add the new destination as a page component. Destination destination = (Destination) evt.getNewValue(); if (annotationPanel != null && annotationPanel.getDestinationsPanel() != null) { annotationPanel.getDestinationsPanel().refreshNameTree(null); } documentViewController.addNewDestination(destination); getDocumentViewController().getDocumentView().repaint(); break; case PropertyConstants.DESTINATION_UPDATED: Destination newDestination = (Destination) evt.getNewValue(); Destination oldDestination = (Destination) evt.getOldValue(); // the tree dialog does the catalog insertion so we don't have to worry about that // but we do need to refresh the tree as the name may have changed. if (annotationPanel != null && annotationPanel.getDestinationsPanel() != null) { annotationPanel.getDestinationsPanel().refreshNameTree(null); } // we need to update the destination page component documentViewController.updateDestination(oldDestination, newDestination); getDocumentViewController().getDocumentView().repaint(); break; case PropertyConstants.DESTINATION_DELETED: destination = (Destination) evt.getOldValue(); // remove the destination Catalog catalog = getDocument().getCatalog(); catalog.deleteNamedDestination(destination.getNamedDestination()); // update the tree and remove this node. if (annotationPanel != null && annotationPanel.getDestinationsPanel() != null) { annotationPanel.getDestinationsPanel().removeNameTreeNode(destination); } // remove the destination component from the page component documentViewController.deleteDestination(destination); getDocumentViewController().getDocumentView().repaint(); break; } } private Collection getColorButtons() { return new HashSet<>(Arrays.asList(highlightAnnotationToolButton, strikeOutAnnotationToolButton, underlineAnnotationToolButton, lineAnnotationToolButton, lineArrowAnnotationToolButton, squareAnnotationToolButton, circleAnnotationToolButton, inkAnnotationToolButton, textAnnotationToolButton)); } public void changeAnnotationsVisibility(final AnnotationFilter filter, final boolean visible, final boolean execInvert) { callOnFilteredAnnotations(a -> a instanceof MarkupAnnotation && filter.filter(a), a -> { a.setFlag(Annotation.FLAG_HIDDEN, !visible); a.setFlag(Annotation.FLAG_INVISIBLE, !visible); final PopupAnnotation pa = ((MarkupAnnotation) a).getPopupAnnotation(); if (pa != null) { if (pa.isOpen() && !visible) { pa.setOpen(false); final int idx = pa.getPageIndex(); final AbstractAnnotationComponent comp = (AbstractAnnotationComponent) ((PageViewComponentImpl) documentViewController.getDocumentViewModel().getPageComponents().get(idx)).getComponentFor(pa); if (comp != null) { comp.setVisible(false); } } } }); if (execInvert) { changeAnnotationsVisibility(filter.invertFilter(), !visible, false); } if (viewer != null) { viewer.validate(); viewer.repaint(); } } /** * Changes privacy flag of the MarkupAnnotations given by the annotations filter * * @param filter The filter used to filter the annotations * @param priv The privacy status to use (true = private) */ public void changeAnnotationsPrivacy(final AnnotationFilter filter, final boolean priv) { callOnFilteredAnnotations(a -> a instanceof MarkupAnnotation && filter.filter(a), a -> { final MarkupAnnotation ma = (MarkupAnnotation) a; ma.setFlag(Annotation.FLAG_PRIVATE_CONTENTS, priv); ma.setModifiedDate(PDate.formatDateTime(new Date())); final PopupAnnotation pa = ma.getPopupAnnotation(); if (pa != null) { pa.setFlag(Annotation.FLAG_PRIVATE_CONTENTS, priv); pa.setModifiedDate(PDate.formatDateTime(new Date())); } final PageViewComponentImpl pvc = (PageViewComponentImpl) documentViewController.getDocumentViewModel().getPageComponents().get(ma.getPageIndex()); final MarkupAnnotationComponent comp = (MarkupAnnotationComponent) pvc.getComponentFor(ma); if (comp != null) { if (comp.getPopupAnnotationComponent() != null) { comp.getPopupAnnotationComponent().refreshPopupState(); } documentViewController.updateAnnotation(comp); } }); } private void callOnFilteredAnnotations(final AnnotationFilter filter, final Consumer toExecute) { if (document != null) { final PageTree pt = document.getPageTree(); for (int i = 0; i < pt.getNumberOfPages(); ++i) { final Page p = pt.getPage(i); if (p.getAnnotations() != null) { final List annotations = p.getAnnotations().stream().filter(filter::filter).collect(Collectors.toList()); annotations.forEach(toExecute); } } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy