org.jpedal.examples.viewer.gui.JavaFxGUI Maven / Gradle / Ivy
Show all versions of OpenViewerFX Show documentation
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/support/
*
* (C) Copyright 1997-2017 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
@LICENSE@
*
* ---------------
* JavaFxGUI.java
* ---------------
*/
package org.jpedal.examples.viewer.gui;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.*;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.Transition;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.*;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
import javax.imageio.ImageIO;
import org.jpedal.FileAccess;
import org.jpedal.PdfDecoderFX;
import org.jpedal.PdfDecoderInt;
import org.jpedal.display.Display;
import org.jpedal.display.GUIModes;
import org.jpedal.display.GUIThumbnailPanel;
import org.jpedal.display.PageOffsets;
import org.jpedal.display.javafx.PageFlowDisplayFX;
import org.jpedal.display.javafx.SingleDisplayFX;
import org.jpedal.examples.viewer.*;
import org.jpedal.examples.viewer.commands.OpenFile;
import org.jpedal.examples.viewer.commands.javafx.JavaFXOpenFile;
import org.jpedal.examples.viewer.gui.generic.*;
import org.jpedal.examples.viewer.gui.javafx.*;
import org.jpedal.examples.viewer.gui.javafx.FXViewerTransitions.TransitionDirection;
import org.jpedal.examples.viewer.gui.javafx.FXViewerTransitions.TransitionType;
import org.jpedal.examples.viewer.gui.javafx.dialog.FXInputDialog;
import org.jpedal.examples.viewer.gui.javafx.dialog.FXMessageDialog;
import org.jpedal.examples.viewer.gui.javafx.dialog.FXOptionDialog;
import org.jpedal.examples.viewer.paper.PaperSizes;
import org.jpedal.examples.viewer.utils.PropertiesFile;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.external.Options;
import org.jpedal.fonts.tt.TTGlyph;
import org.jpedal.gui.GUIFactory;
import org.jpedal.io.StatusBarFX;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.acroforms.AcroRenderer;
import org.jpedal.objects.acroforms.actions.ActionHandler;
import org.jpedal.objects.layers.PdfLayerList;
import org.jpedal.objects.raw.FormObject;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.parser.DecoderOptions;
import org.jpedal.render.DynamicVectorRenderer;
import org.jpedal.utils.BrowserLauncher;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.Messages;
import org.w3c.dom.Node;
/**
*
Description: GUI functions in Viewer implemented in JavaFX
*/
@SuppressWarnings("MagicConstant")
public class JavaFxGUI extends GUI {
private RefreshLayout viewListener;
protected final JavaFXButtons fxButtons;
//GUICursor object that holds everything todo with Cursor for SwingGUI
private final SwingCursor guiCursor = new SwingCursor();
//all mouse actions
private GUIMouseHandler mouseHandler;
private Timeline memoryMonitor;
//flag for marks new thumbnail preview
private boolean debugThumbnail;
private boolean sideTabBarOpenByDefault;
private String startSelectedTab = "Pages";
//use new GUI layout
// public static String windowTitle;
private boolean hasListener;
private boolean isSetup;
private int lastTabSelected = -1;
private boolean tabsExpanded;
private PaperSizes paperSizes;
/*
* Multibox for new GUI Layout Component to contain memory, cursor and
* loading bars IMPORTANT : the width of the multibox needs to be the same
* size as the width of pagesToolBar to ensure that it is centered on the
* page.
*/
private HBox multiboxfx;
private FXProgressBarWithText memoryBarFX;
//visual display of current cursor co-ords on page
private TextField coordsFX;
//Track whether both pages are properly displayed
private static final boolean pageTurnScalingAppropriate = true;
//holds back/forward buttons at bottom of page
private HBox navButtons;
//displayed on left to hold thumbnails, bookmarks
private TabPane navOptionsPanel;
//tell user on first form change it can be saved
private static final boolean firstTimeFormMessage = true;
private Label pageCounter1;
public TextField pageCounter2;
private Label pageCounter3;
private final JavaFXSignaturesPanel signaturesPanel;
private final JavaFXLayersPanel layersPanel;
//stop user forcing open tab before any pages loaded
private boolean tabsNotInitialised = true;
//private boolean thumbnailsInitialised;
private boolean hasPageChanged;
private ToolBar navToolBar;
private ToolBar pagesToolBar;
//The main JavaFX Stage
private final Stage stage;
//The main JavaFX Scene
private Scene scene;
//BorderPane lays out children in top, left, right, bottom, and center positions.
private final BorderPane root;
private static final int dropshadowDepth = 40;
private Group group;
// Scrollpane to contain the PDF page
private ScrollPane pageContainer;
private SplitPane center;
private final VBox topPane;
private StatusBarFX downloadBar;
private boolean searchInMenu;
private TextField searchText;
private GUISearchList results;
private MenuBar options;
private boolean cursorOverPage;
private TransitionType transitionType = TransitionType.None;
// Scrolls between pages when the pdf is not zoomed in
private ScrollBar pageScroll;
private ChangeListener fxChangeListener;
public JavaFxGUI(final Stage stage, final PdfDecoderInt decode_pdf, final Values commonValues, final GUIThumbnailPanel thumbnails, final PropertiesFile properties) {
super(decode_pdf, commonValues, thumbnails, properties);
isJavaFX = true;
if (debugFX) {
System.out.println("JavaFxGUI");
}
this.stage = stage;
root = new BorderPane();
topPane = new VBox();
pageCounter2 = new TextField();
navButtons = new HBox();
fxButtons = new JavaFXButtons();
pageCounter3 = new Label();
navToolBar = new ToolBar();
pagesToolBar = new ToolBar();
tree = new JavaFXOutline();
layersPanel = new JavaFXLayersPanel();
signaturesPanel = new JavaFXSignaturesPanel();
setLookAndFeel();
setupDisplay();
}
/**
* Returns the scroll bar used in single page mode that shows page thumbnails as you scroll
*
* @return ScrollBar used for the thumbnail scroll in single page mode
*/
@Override
public Object getThumbnailScrollBar() {
if (debugFX) {
System.out.println("getThumbnailScrollBar - Implemented");
}
return pageScroll;
}
/**
* Control thumbnail scroll bars visibility
*
* @param isVisible boolean value to control visibility
*/
@Override
public void setThumbnailScrollBarVisibility(final boolean isVisible) {
if (debugFX) {
System.out.println("setThumbnailScrollBarVisibility - Implemented");
}
pageScroll.setVisible(isVisible);
//#making invisible still shows the gap so iam padding negative to hide it
if (isVisible) {
pageScroll.setStyle("-fx-padding:0px");
} else {
pageScroll.setStyle("-fx-padding:-10px");
}
}
/**
* Set the position of the scroll bar based on desired page number
*
* @param pageNum int value for the page
*/
@Override
public void setThumbnailScrollBarValue(final int pageNum) {
if (debugFX) {
System.out.println("setThumbnailScrollBarValue - Implemented");
}
pageScroll.setValue(pageNum);
}
/**
* set the look and feel for the GUI components to be the default for the
* system it is running on
*/
private void setLookAndFeel() {
if (debugFX) {
System.out.println("setLookAndFeel - Not yet implemented in JavaFX");
}
/*
* JavaFX has no look and feel option, 2.2 has a theme called Caspian
* (the default theme) only. FX8 has Moderna and Caspian, which can be
* set in the class which overrides Application with
* setUserAgentStylesheet(url)
*
* We can also define our own rules on top of this with:
* root.getStylesheets().clear();
* root.getStylesheets().add("stylesheetlocation"); Also see:
* http://blog.idrsolutions.com/2014/04/use-external-css-files-javafx/
*/
root.getStylesheets().clear();
root.getStylesheets().add(getClass().getResource("/org/jpedal/examples/viewer/res/css/JavaFXForms.css").toExternalForm());
root.getStylesheets().add(getClass().getResource("/org/jpedal/examples/viewer/res/css/JavaFXPages.css").toExternalForm());
}
private void setupDisplay() {
setDisplayView(Display.SINGLE_PAGE, Display.DISPLAY_CENTERED);
//pass in SwingGUI so we can call via callback
decode_pdf.addExternalHandler(this, Options.GUIContainer);
menuItems = new JavaFXMenuItems(properties);
}
/**
* Returns the split pane used in the display area of the viewer.
*
* @return SplitPane used to hold the page display and the side tab bar
*/
@Override
public SplitPane getDisplayPane() {
return center;
}
/**
* Used in Swing MultiViewer only
*/
@Override
public Object getMultiViewerFrames() {
if (debugFX) {
System.out.println("getMultiViewerFrames");
}
return null;
}
/**
* Gets the file path for the properties file used in the viewer.
*
* @return String containing the properties file name
*/
@Override
public String getPropertiesFileLocation() {
if (debugFX) {
System.out.println("getPropertiesFileLocation");
}
return properties.getConfigFile();
}
/**
* Gets the page number of the given bookmark
*
* @param bookmark String value of the bookmark
* @return String value of the page number
*/
@Override
public String getBookmark(final String bookmark) {
if (debugFX) {
System.out.println("getBookmark");
}
return tree.getPage(bookmark);
}
/**
* Set the side tab bar state and set any values required for that state.
*
* @param showVisible true to expand the side tab bar, false to collapse
*/
@Override
public void reinitialiseTabs(final boolean showVisible) {
if (debugFX) {
System.out.println("reinitialiseTabs");
}
//not needed
if (commonValues.getModeOfOperation() == Values.RUNNING_PLUGIN) {
return;
}
if (properties.getValue("ShowSidetabbar").equalsIgnoreCase("true")) {
if (!showVisible && !properties.getValue("consistentTabBar").equalsIgnoreCase("true")) {
if (sideTabBarOpenByDefault) {
setSplitDividerLocation(expandedSize);
tabsExpanded = true;
} else {
setSplitDividerLocation(collapsedSize);
tabsExpanded = false;
}
}
lastTabSelected = -1;
if (!commonValues.isPDF()) {
navOptionsPanel.setVisible(false);
} else {
navOptionsPanel.setVisible(true);
/*
* add/remove optional tabs
*/
if (!decode_pdf.hasOutline()) {
int outlineTab = -1;
//see if there is an outlines tab
for (int jj = 0; jj < navOptionsPanel.getTabs().size(); jj++) {
if (navOptionsPanel.getTabs().get(jj).getText().equals(bookmarksTitle)) {
outlineTab = jj;
}
}
if (outlineTab != -1) {
navOptionsPanel.getTabs().remove(outlineTab);
}
} else if (properties.getValue("Bookmarkstab").equalsIgnoreCase("true")) {
int outlineTab = -1;
//see if there is an outlines tab
for (int jj = 0; jj < navOptionsPanel.getTabs().size(); jj++) {
if (navOptionsPanel.getTabs().get(jj).getText().equals(bookmarksTitle)) {
outlineTab = jj;
}
}
if (outlineTab == -1) {
navOptionsPanel.getTabs().add(navOptionsPanel.getTabs().size() - 1, (Tab) tree);
}
}
/*
* handle signatures pane
*/
final AcroRenderer currentFormRenderer = decode_pdf.getFormRenderer();
Iterator signatureObjects = null;
if (currentFormRenderer != null) {
signatureObjects = currentFormRenderer.getSignatureObjects();
}
if (signatureObjects != null) {
signaturesPanel.reinitialise(decode_pdf, signatureObjects);
checkTabShown(signaturesTitle);
} else {
removeTab(signaturesTitle);
}
/*
* add a control Panel to enable/disable layers
*/
//layers object
layersObject = (PdfLayerList) decode_pdf.getJPedalObject(PdfDictionary.Layer);
if (layersObject != null && layersObject.getLayersCount() > 0) { //some files have empty Layers objects
checkTabShown(layersTitle);
layersPanel.reinitialise(layersObject, decode_pdf, null, commonValues.getCurrentPage());
} else {
removeTab(layersTitle);
}
setBookmarks(false);
}
if (tabsNotInitialised) {
for (int i = 0; i != navOptionsPanel.getTabs().size(); i++) {
if (navOptionsPanel.getTabs().get(i).getText().equals(startSelectedTab)) {
navOptionsPanel.getSelectionModel().select(i);
break;
}
}
}
}
}
private void checkTabShown(final String title) {
if (debugFX) {
System.out.println("checkTabShown");
}
int outlineTab = -1;
//see if there is an outlines tab
for (int jj = 0; jj < navOptionsPanel.getTabs().size(); jj++) {
if (navOptionsPanel.getTabs().get(jj).getText().equals(title)) {
outlineTab = jj;
}
}
if (outlineTab == -1) {
if (title.equals(signaturesTitle) && properties.getValue("Signaturestab").equalsIgnoreCase("true")) { //stop spurious display of Sig tab
navOptionsPanel.getTabs().add(navOptionsPanel.getTabs().size() - 1, signaturesPanel);
} else if (title.equals(layersTitle) && properties.getValue("Layerstab").equalsIgnoreCase("true")) {
navOptionsPanel.getTabs().add(navOptionsPanel.getTabs().size() - 1, layersPanel);
}
}
}
private void removeTab(final String title) {
if (debugFX) {
System.out.println("removeTab");
}
int outlineTab = -1;
//see if there is an outlines tab
for (int jj = 0; jj < navOptionsPanel.getTabs().size(); jj++) {
if (navOptionsPanel.getTabs().get(jj).getText().equals(title)) {
outlineTab = jj;
}
}
if (outlineTab != -1) {
navOptionsPanel.getTabs().remove(outlineTab);
}
}
/**
* Stop thumbnail generation in the pages thumbnail tab
*/
@Override
public void stopThumbnails() {
if (debugFX) {
System.out.println("stopThumbnails");
}
if (thumbnails.isShownOnscreen()) {
thumbnails.terminateDrawing();
thumbnails.removeAllListeners();
}
}
/**
* Flags the pages thumbnail tab as requiring reinitialisation
*/
@Override
public void reinitThumbnails() {
if (debugFX) {
System.out.println("reinitThumbnails");
}
isSetup = false;
}
/**
* reset the navigation bar so that it appears closed
*/
@Override
public void resetNavBar() {
if (debugFX) {
System.out.println("resetNavBar");
}
if (!properties.getValue("consistentTabBar").equalsIgnoreCase("true")) {
setSplitDividerLocation(collapsedSize);
tabsExpanded = false;
tabsNotInitialised = true;
}
//disable page view buttons until we know we have multiple pages
fxButtons.setPageLayoutButtonsEnabled(false);
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#setNoPagesDecoded()
*
* Called when new file opened so we set flags here
*/
@Override
public void setNoPagesDecoded() {
if (debugFX) {
System.out.println("setNoPagesDecoded");
}
bookmarksGenerated = false;
resetNavBar();
}
/**
* setDisplayMode not supported in ViewerFX
*/
@Override
public void setDisplayMode(final Integer mode) {
if (debugFX) {
System.out.println("setDisplayMode not implemented for JavaFX in JavaFxGUI");
}
}
/**
* JavaFX is only in single mode
*
* @return Always returns true
*/
@Override
public boolean isSingle() {
if (debugFX) {
System.out.println("isSingle");
}
return true;
}
/**
* Gets the object used for the thumbnail panel.
*
* @return an Object that extends GUIThumbnailPanel
*/
@Override
public Object getThumbnailPanel() {
if (debugFX) {
System.out.println("getThumbnailPanel");
}
return thumbnails;
}
/**
* Gets the object used for the outline panel
*
* @return an Object that extends GUIOutline
*/
@Override
public Object getOutlinePanel() {
if (debugFX) {
System.out.println("getOutlinePanel");
}
return tree;
}
/**
* Can't get the scrollbar from a scroll pane, other methods should be
* implemented to circumvent this when needed
*/
@Override
public Object getVerticalScrollBar() {
if (debugFX) {
System.out.println("getVerticalScrollBar");
}
// Altered function due to above comments, return thumbscroll only when shown
if (pageScroll.isVisible()) {
return pageScroll;
} else {
return null;
}
}
/*
*Allows user to embed viewer into own application
*/
@Override
public void setRootContainer(final Object rawValue) {
if (rawValue == null) {
throw new RuntimeException("Null containers not allowed.");
}
final Parent parentPane = (Parent) rawValue;
//We add the Viewer to the parent pane depending on its type.
if (parentPane instanceof Pane) {
((Pane) parentPane).getChildren().add(root);
} else if (parentPane instanceof ScrollPane) {
((ScrollPane) parentPane).setContent(root);
}
//Load width and height from properties file
int width = Integer.parseInt(properties.getValue("startViewerWidth"));
int height = Integer.parseInt(properties.getValue("startViewerHeight"));
//Used to prevent infinite scroll issue as a preferred size has been set
final Rectangle2D d = Screen.getPrimary().getVisualBounds();
if (width < 0) {
width = (int) (d.getWidth() / 2);
if (width < 700) {
width = 700;
}
properties.setValue("startViewerWidth", String.valueOf(width));
}
if (height < 0) {
height = (int) (d.getHeight() / 2);
properties.setValue("startViewerHeight", String.valueOf(height));
}
//allow user to alter size
final String customWindowSize = System.getProperty("org.jpedal.startWindowSize");
if (customWindowSize != null) {
final StringTokenizer values = new StringTokenizer(customWindowSize, "x");
if (values.countTokens() != 2) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300");
}
}
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#resetRotationBox()
*/
@Override
public void resetRotationBox() {
if (debugFX) {
System.out.println("resetRotationBox");
}
final PdfPageData currentPageData = decode_pdf.getPdfPageData();
if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
rotation = currentPageData.getRotation(commonValues.getCurrentPage());
}
if (getSelectedComboIndex(Commands.ROTATION) != (rotation / 90)) {
setSelectedComboIndex(Commands.ROTATION, (rotation / 90));
} else if (!Values.isProcessing()) {
// ((PdfDecoder)decode_pdf).repaint();
}
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#getProperties()
*/
@Override
public PropertiesFile getProperties() {
return properties;
}
/**
* Set Search Bar to be in the Left hand Tabbed pane
*/
@Override
public void searchInTab(final GUISearchWindow searchFrame) {
if (debugFX) {
System.out.println("searchInTab");
}
this.searchFrame = searchFrame;
this.searchFrame.init(decode_pdf, commonValues);
}
/**
* Adds Drop-Down Search Menu Options to the In-Menu Search Field.
*
* @return
*/
private MenuBar createMenuBarSearchOptions() {
//Setup Search In Menu Options.
final CheckMenuItem cb1 = new CheckMenuItem(Messages.getMessage("PdfViewerSearch.WholeWords"));
final CheckMenuItem cb2 = new CheckMenuItem(Messages.getMessage("PdfViewerSearch.CaseSense"));
final CheckMenuItem cb3 = new CheckMenuItem(Messages.getMessage("PdfViewerSearch.MultiLine"));
//Add Search 0ptions listeners.
cb1.selectedProperty().addListener(new ChangeListener() {
@Override
public void changed(final ObservableValue ov,
final Boolean old_val, final Boolean new_val) {
searchFrame.setWholeWords(cb1.isSelected());
}
});
cb2.selectedProperty().addListener(new ChangeListener() {
@Override
public void changed(final ObservableValue ov,
final Boolean old_val, final Boolean new_val) {
searchFrame.setCaseSensitive(cb2.isSelected());
}
});
cb3.selectedProperty().addListener(new ChangeListener() {
@Override
public void changed(final ObservableValue ov,
final Boolean old_val, final Boolean new_val) {
searchFrame.setMultiLine(cb3.isSelected());
}
});
//Setup Menu Apply Image, and Add Items.
final Menu menu = new Menu();
final Image image = new Image(guiCursor.getURLForImage("menuSearchOptions.png").toString());
menu.setGraphic(new ImageView(image));
menu.getItems().addAll(cb1, cb2, cb3);
//Setup Menu Bar and Add Menu.
options = new MenuBar();
options.setBackground(Background.EMPTY);
options.setFocusTraversable(false);
options.setTooltip(new Tooltip(Messages.getMessage("PdfViewerSearch.Options")));
options.getMenus().add(menu);
return options;
}
/*
* Set Search Bar to be in the Top Button Bar
*/
private void searchInMenu(final GUISearchWindow searchFrame) {
this.searchFrame = searchFrame;
searchInMenu = true;
searchFrame.find(decode_pdf, commonValues);
fxButtons.getTopButtons().getItems().add(searchText);
fxButtons.getTopButtons().getItems().add(createMenuBarSearchOptions());
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerSearch.Previous"), "search_previous.gif", Commands.PREVIOUSRESULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerSearch.Next"), "search_next.gif", Commands.NEXTRESULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
fxButtons.getButton(Commands.NEXTRESULT).setEnabled(false);
fxButtons.getButton(Commands.PREVIOUSRESULT).setEnabled(false);
fxButtons.getButton(Commands.NEXTRESULT).setVisible(true);
fxButtons.getButton(Commands.PREVIOUSRESULT).setVisible(true);
}
/**
* Sets the properties file to be used
*
* @param file String file name for the properties file to be used
*/
@Override
public void setPropertiesFileLocation(final String file) {
properties.loadProperties(file);
}
/**
* Gets the Commands object used by the user interface
*
* @return Commands object for executing commands
*/
@Override
public Commands getCommand() {
return currentCommands;
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#init(java.lang.String[], org.jpedal.examples.viewer.Commands, org.jpedal.examples.viewer.utils.Printer)
*/
@Override
public void init(final Commands currentCommands) {
if (debugFX) {
System.out.println("init");
}
updateTransitionType();
mouseHandler = new JavaFXMouseListener((PdfDecoderFX) decode_pdf, this, commonValues, currentCommands);
mouseHandler.setupMouse();
//single listener to execute all commands
currentCommandListener = new CommandListenerFX(currentCommands);
super.init(currentCommands);
//Set up from properties
try {
//Set whether to use hinting
String propValue = properties.getValue("useHinting");
final String propValue2 = System.getProperty("org.jpedal.useTTFontHinting");
//check JVM flag first
if (propValue2 != null) {
//check if properties file conflicts
if (!propValue.isEmpty() && !propValue2.equalsIgnoreCase(propValue.toLowerCase())) {
showMessageDialog(Messages.getMessage("PdfCustomGui.hintingFlagFileConflict"));
}
TTGlyph.useHinting = propValue2.equalsIgnoreCase("true");
//check properties file
} else {
TTGlyph.useHinting = !propValue.isEmpty() && propValue.equalsIgnoreCase("true");
}
//Set icon location
propValue = properties.getValue("iconLocation");
if (!propValue.isEmpty() && GUI.debugFX) {
System.out.println("guiCursor is not set to JavaFXCursor in method init() in class JavaFxGUI.java");
}
//guiCursor.setIconLocation(propValue);
} catch (final Exception e) {
e.printStackTrace();
}
//setup combo boxes
setupComboBoxes();
if (LogWriter.isRunningFromIDE) {
nameElements();
}
//Initialise the Swing Buttons *
fxButtons.init(true);
//create a menu bar and add to display
createTopMenuBar();
//create other tool bars and add to display
createOtherToolBars();
//set colours on display boxes and add listener to page number
setupBottomToolBarItems();
//sets up all the toolbar items
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.openFile"), "open.gif", Commands.OPENFILE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
if (searchFrame != null && searchFrame.getViewStyle() == GUISearchWindow.SEARCH_EXTERNAL_WINDOW) {
searchFrame.setViewStyle(GUISearchWindow.SEARCH_EXTERNAL_WINDOW);
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.search"), "find.gif", Commands.FIND, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
}
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.properties"), "properties.gif", Commands.DOCINFO, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
if (commonValues.getModeOfOperation() == Values.RUNNING_PLUGIN) {
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.about"), "about.gif", Commands.ABOUT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
}
//snapshot screen function
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.snapshot"), "snapshot.gif", Commands.SNAPSHOT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
final Separator sep = new Separator();
sep.setPrefSize(5, 32);
//combo boxes on toolbar
addCombo(Messages.getMessage("PdfViewerToolbarTooltip.zoomin"), Commands.SCALING);
addCombo(Messages.getMessage("PdfViewerToolbarTooltip.rotation"), Commands.ROTATION);
//rotation buttons
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.rotateLeft"), "rotateLeft.gif", Commands.ROTATELEFT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.rotateRight"), "rotateRight.gif", Commands.ROTATERIGHT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.mouseMode"), "mouse_select.png", Commands.MOUSEMODE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
fxButtons.getTopButtons().getItems().add(sep);
if (includeExtraMenus && commonValues.getModeOfOperation() != Values.RUNNING_PLUGIN) {
fxButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.help"), "help.png", Commands.HELP, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
}
//addButton(GUIFactory.BUTTONBAR,Messages.getMessage("PdfViewerToolbarTooltip.buy"),iconLocation+"buy.png",Commands.BUY);
//add cursor location
initMultiBox();
//navigation toolbar for moving between pages
createNavbar();
if (searchFrame != null && searchFrame.getViewStyle() == GUISearchWindow.SEARCH_MENU_BAR) {
searchInMenu(searchFrame);
}
//status object on toolbar showing 0 -100 % completion
initStatus();
/*
* Ensure all gui sections are displayed correctly
* Issues found when removing some sections
*/
if (GUI.debugFX) {
System.out.println("Swing specific invalidate(), validate(), repaint() not implemented for JavaFX in JavaFxGUI");
}
/*
* set display to occupy half screen size and display, add listener and
* make sure appears in centre
*/
if (commonValues.getModeOfOperation() != Values.RUNNING_APPLET) {
//Load width and height from properties file
int width = Integer.parseInt(properties.getValue("startViewerWidth"));
int height = Integer.parseInt(properties.getValue("startViewerHeight"));
//Used to prevent infinite scroll issue as a preferred size has been set
//Used to prevent infinite scroll issue as a preferred size has been set
final Rectangle2D d = Screen.getPrimary().getVisualBounds();
if (width < 0) {
width = ((int) d.getWidth()) / 2;
if (width < minimumScreenWidth) {
width = minimumScreenWidth;
}
properties.setValue("startViewerWidth", String.valueOf(width));
}
if (height < 0) {
height = ((int) d.getHeight()) / 2;
properties.setValue("startViewerHeight", String.valueOf(height));
}
//allow user to alter size
final String customWindowSize = System.getProperty("org.jpedal.startWindowSize");
if (customWindowSize != null) {
final StringTokenizer values = new StringTokenizer(customWindowSize, "x");
System.out.println(values.countTokens());
if (values.countTokens() != 2) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300");
}
try {
width = Integer.parseInt(values.nextToken().trim());
height = Integer.parseInt(values.nextToken().trim());
} catch (final Exception ee) {
throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300 " + ee);
}
}
setupPDFDisplayPane();
// add the pdf display left and right panes
setupBorderPanes();
createMainViewerWindow(width, height);
}
//Add Background color to the JavaFX panel to help break up view
setupCenterPanelBackground();
setupPDFBorder();
//Set side tab bar state at start up
if (sideTabBarOpenByDefault) {
setSplitDividerLocation(expandedSize);
tabsExpanded = true;
} else {
setSplitDividerLocation(collapsedSize);
tabsExpanded = false;
}
//Load properties
try {
GUIModifier.load(properties, this);
} catch (final Exception e) {
e.printStackTrace();
}
//DELETE This code block once all items are implemented.
//This code is here so the loading of properties does not override
//the disabling of unimplemented items in the FXViewer.
final int ALL = -10;
((JavaFXMenuItems) menuItems).disableUnimplementedItems(ALL, false);
fxButtons.disableUnimplementedItems(ALL);
}
private void nameElements() {
((JavaFXMenuItems) menuItems).getCurrentMenuFX().setId("menuBar");
pageCounter2.setId("pageCounter");
rotationBox.setName("rotationBox");
scalingBox.setName("scalingBox");
}
/**
* method being called from within init to create other tool bars to add to
* display
*/
@Override
protected void createOtherToolBars() {
if (GUI.debugFX) {
System.out.println("createOtherToolBars almost finished for JavaFX");
}
//This is where we setup the top most menu
menuItems.createMainMenu(true, currentCommandListener, true, commonValues, currentCommands, fxButtons);
topPane.getChildren().add(((JavaFXMenuItems) menuItems).getCurrentMenuFX());
//This is where we add the Buttons for the top ToolBar
topPane.getChildren().add(fxButtons.getTopButtons());
}
private void handleTabbedPanes() {
if (tabsNotInitialised) {
return;
}
if (debugFX) {
System.out.println("handleTabbedPanes");
}
final int tabSelected;
tabSelected = navOptionsPanel.getSelectionModel().getSelectedIndex();
if (tabSelected == -1) {
return;
}
if (!tabsExpanded) {
//workout selected tab
final String tabName = navOptionsPanel.getTabs().get(tabSelected).getText();
if (tabName != null && tabName.equals(pageTitle)) {
thumbnails.setIsDisplayedOnscreen(true);
} else {
thumbnails.setIsDisplayedOnscreen(false);
}
// Don't expand on dummy tab
if (!navOptionsPanel.getSelectionModel().getSelectedItem().isDisable()) {
setSplitDividerLocation(expandedSize);
tabsExpanded = true;
}
} else if (lastTabSelected == tabSelected && !hasPageChanged) {
setSplitDividerLocation(collapsedSize);
tabsExpanded = false;
thumbnails.setIsDisplayedOnscreen(false);
}
lastTabSelected = tabSelected;
hasPageChanged = false;
}
private void initMultiBox() {
multiboxfx = new HBox();
initCoordBox();
initMemoryBar();
initDownloadBar();
}
/**
* Not part of API - used internally
*
* Set the state and value for the multi box at the bottom left of the user interface.
*
* @param flags an int[] used to control multi box display
*/
@Override
public void setMultibox(final int[] flags) {
//debug code for formclicktests
if (GUI.alwaysShowMouse) {
multiboxfx.getChildren().clear();
multiboxfx.getChildren().add(coordsFX);
return;
}
//deal with flags
if (flags.length > 1 && flags[0] == CURSOR) {
//if no change, return
if (cursorOverPage != (flags[1] == 1)) {
cursorOverPage = flags[1] == 1;
} else {
return;
}
}
//LOAD_PROGRESS:
// if (statusBar.isEnabled() && statusBar.isVisible() && !statusBar.isDone()) {
// multibox.removeAll();
// statusBar.getStatusObject().setSize(multibox.getSize());
// multibox.add(statusBar.getStatusObject(), BorderLayout.CENTER);
//
// multibox.repaint();
// return;
// }
//CURSOR:
if (cursorOverPage && decode_pdf.isOpen()) {
multiboxfx.getChildren().clear();
multiboxfx.getChildren().add(coordsFX);
return;
}
//DOWNLOAD_PROGRESS:
if (!downloadBar.isDisable() && downloadBar.isVisible() && !downloadBar.isDone() && (decode_pdf.isLoadingLinearizedPDF() || !decode_pdf.isOpen())) {
multiboxfx.getChildren().clear();
multiboxfx.getChildren().add(downloadBar.getStatusObject());
return;
}
//MEMORY:
if (memoryBarFX.isVisible()) {
multiboxfx.getChildren().clear();
multiboxfx.getChildren().add(memoryBarFX);
}
}
private void initDownloadBar() {
downloadBar = new StatusBarFX(new Color((185.0d / 255.0d), (209.0d / 255.0d), 0, 1));
downloadBar.getStatusObject().prefHeightProperty().bind(multiboxfx.heightProperty());
downloadBar.getStatusObject().prefWidthProperty().bind(multiboxfx.widthProperty());
downloadBar.setVisible(false);
}
private void initMemoryBar() {
memoryBarFX = new FXProgressBarWithText();
memoryBarFX.prefHeightProperty().bind(multiboxfx.heightProperty());
memoryBarFX.prefWidthProperty().bind(multiboxfx.widthProperty());
if (memoryMonitor == null) { //ensure only 1 instance
memoryMonitor = new Timeline(new KeyFrame(Duration.seconds(0.5), new EventHandler() {
@Override
public void handle(final ActionEvent event) {
final int free = (int) (Runtime.getRuntime().freeMemory() / (1024 * 1024));
final int total = (int) (Runtime.getRuntime().totalMemory() / (1024 * 1024));
final double used = (total - free) / total;
//this broke the image saving when it was run every time
if (finishedDecoding) {
finishedDecoding = false;
}
if (Platform.isFxApplicationThread()) {
memoryBarFX.setProgress(used);
memoryBarFX.setText((total - free) + "M of " + total + 'M');
} else {
// Needs to be done on the FX Thread
Platform.runLater(new Runnable() {
@Override
public void run() {
memoryBarFX.setProgress(used);
memoryBarFX.setText((total - free) + "M of " + total + 'M');
}
});
}
}
}));
memoryMonitor.setCycleCount(Timeline.INDEFINITE);
memoryMonitor.play();
}
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
@Override
protected void setViewerIcon() {
//Check if file location provided
final URL path = guiCursor.getURLForImage("icon.png");
if (stage != null && path != null) {
try {
//Converting Swing BufferedImage to FX WritableImage
final BufferedImage bi = ImageIO.read(path);
WritableImage fontIcon = new WritableImage(bi.getWidth(), bi.getHeight());
fontIcon = SwingFXUtils.toFXImage(bi, fontIcon);
stage.getIcons().add(fontIcon);
} catch (final Exception e) {
LogWriter.writeLog("Exception attempting to set Icon " + e);
}
}
}
private boolean setDisplayView2(final int displayView, final int orientation) {
final DecoderOptions options = decode_pdf.getDecoderOptions();
Display pages = decode_pdf.getPages();
final int lastDisplayView = decode_pdf.getDisplayView();
final FileAccess fileAccess = (FileAccess) decode_pdf.getExternalHandler(Options.FileAccess);
final int pageNumber = decode_pdf.getPageNumber();
final ExternalHandlers externalHandlers = decode_pdf.getExternalHandler();
final PdfDecoderFX comp = (PdfDecoderFX) decode_pdf;
final Pane highlightsPane = comp.highlightsPane;
options.setPageAlignment(orientation);
if (pages != null) {
pages.stopGeneratingPage();
}
if (Platform.isFxApplicationThread()) {
if (highlightsPane != null && highlightsPane.getParent() != null) {
((Group) highlightsPane.getParent()).getChildren().remove(highlightsPane);
}
} else {
final Runnable doPaintComponent = new Runnable() {
@Override
public void run() {
if (highlightsPane != null && highlightsPane.getParent() != null) {
((Group) highlightsPane.getParent()).getChildren().remove(highlightsPane);
}
}
};
Platform.runLater(doPaintComponent);
}
final boolean hasChanged = displayView != lastDisplayView;
options.setDisplayView(displayView);
if (lastDisplayView != displayView && lastDisplayView == Display.PAGEFLOW) {
pages.dispose();
}
final Object customFXHandle = externalHandlers.getExternalHandler(Options.MultiPageUpdate);
switch (displayView) {
case Display.SINGLE_PAGE:
if (pages == null || hasChanged) {
final DynamicVectorRenderer currentDisplay = decode_pdf.getDynamicRenderer();
pages = new SingleDisplayFX(pageNumber, currentDisplay, comp, options);
}
break;
case Display.PAGEFLOW:
if (pages instanceof PageFlowDisplayFX) {
return hasChanged;
}
if (lastDisplayView != Display.SINGLE_PAGE) {
setDisplayView(Display.SINGLE_PAGE, 0);
setDisplayView(Display.PAGEFLOW, 0);
return hasChanged;
}
pages = new PageFlowDisplayFX((GUIFactory) customFXHandle, comp);
break;
}
/*
* setup once per page getting all page sizes and working out settings
* for views
*/
if (fileAccess.getOffset() == null) {
fileAccess.setOffset(new PageOffsets(decode_pdf.getPageCount(), decode_pdf.getPdfPageData()));
}
pages.setup(options.useHardwareAcceleration(), fileAccess.getOffset());
final DynamicVectorRenderer currentDisplay = decode_pdf.getDynamicRenderer();
if (decode_pdf.isOpen()) {
pages.init(scaling, decode_pdf.getDisplayRotation(), pageNumber, currentDisplay, true);
}
// force redraw
pages.forceRedraw();
pages.refreshDisplay();
//needs to be realigned (in longer term refactored out)
comp.pages = pages;
return hasChanged;
}
/**
* set view mode used in panel and redraw in new mode
* SINGLE_PAGE,CONTINUOUS,FACING,CONTINUOUS_FACING delay is the time in
* milli-seconds which scrolling can stop before background page drawing
* starts Multipage views not in OS releases
*/
@Override
public void setDisplayView(final int displayView, final int orientation) {
// remove listener if setup
if (viewListener != null) {
removeComponentListener(viewListener);
viewListener.dispose();
viewListener = null;
}
final boolean hasChanged = setDisplayView2(displayView, orientation);
//move to correct page
final int pageNumber = decode_pdf.getPageNumber();
if (pageNumber > 0) {
if (hasChanged && displayView == Display.SINGLE_PAGE && decode_pdf.isOpen()) {
try {
decode_pdf.getPages().getYCordForPage(pageNumber, scaling);
decode_pdf.setPageParameters(scaling, pageNumber, decode_pdf.getDisplayRotation());
//@swing
// invalidate();
// updateUI();
decode_pdf.decodePage(pageNumber);
} catch (final Exception e) {
LogWriter.writeLog("Exception: " + e.getMessage());
}
} else if (displayView == Display.CONTINUOUS || displayView == Display.CONTINUOUS_FACING) {
try {
decode_pdf.getPages().getYCordForPage(pageNumber, scaling);
decode_pdf.setPageParameters(scaling, pageNumber, decode_pdf.getDisplayRotation());
decode_pdf.decodePage(pageNumber);
scrollToPage(pageNumber);
} catch (final Exception ex) {
ex.printStackTrace();
}
}
}
//Only all search in certain modes
if (displayView != Display.SINGLE_PAGE
&& displayView != Display.CONTINUOUS
&& displayView != Display.CONTINUOUS_FACING) {
enableSearchItems(false);
} else {
enableSearchItems(true);
}
// add listener if one not already there
if (viewListener == null) {
viewListener = new RefreshLayout(decode_pdf);
addComponentListener(viewListener);
}
}
/**
* Overrides method from GUI.java, see GUI.java for DOCS.
*/
@Override
protected void setTitle(final String title) {
if (stage != null) {
stage.setTitle(title);
}
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#resetComboBoxes(boolean)
*/
@Override
public void resetComboBoxes(final boolean value) {
if (debugFX) {
System.out.println("resetComboBoxes");
}
scalingBox.setEnabled(value);
rotationBox.setEnabled(value);
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#getCombo(int)
*/
@Override
public GUICombo getCombo(final int ID) {
if (debugFX) {
System.out.println("getCombo");
}
switch (ID) {
case Commands.SCALING:
return scalingBox;
case Commands.ROTATION:
return rotationBox;
}
return null;
}
/**
* all scaling and rotation should go through this.
*/
@Override
public void scaleAndRotate() {
if (decode_pdf.getDisplayView() == Display.PAGEFLOW) {
decode_pdf.setPageParameters(scaling, commonValues.getCurrentPage(), rotation);
return;
}
//ignore if called too early
if (!decode_pdf.isOpen() && OpenFile.isPDf) {
return;
}
final double width = pageContainer.getViewportBounds().getWidth() * 0.95;
final double height = pageContainer.getViewportBounds().getHeight() * 0.95;
float tempScaling = 1.5f;
// if(sudaDebug){
// System.out.println("scaleAndRotate");
// System.out.println("\tScaling "+scaling);
// System.out.println("\tbar: "+pageContainer.getViewportBounds());
// System.out.println("\tGL: "+group.getBoundsInLocal());
// System.out.println("\tGP: "+group.getBoundsInParent());
// }
//update value and GUI
if (decode_pdf != null) {
for (int i = 0; i < group.getChildren().size(); i++) {
if (!group.getChildren().get(i).equals(decode_pdf)) {
group.getChildren().remove(group.getChildren().get(i));
}
}
int index = getSelectedComboIndex(Commands.SCALING);
if (decode_pdf.getDisplayView() == Display.PAGEFLOW) {
//Ensure we only display in window mode
setSelectedComboIndex(Commands.SCALING, 0);
index = 0;
//Disable scaling option
scalingBox.setEnabled(false);
} else if (decode_pdf.getDisplayView() != Display.PAGEFLOW) {
//No long pageFlow. enable scaling option
scalingBox.setEnabled(true);
}
int page = commonValues.getCurrentPage();
//Multipage tiff should be treated as a single page
if (commonValues.isMultiTiff()) {
page = 1;
}
if (index != -1) {
//always check in facing mode with turnover on
int tw = 0, th = 0; //temp width and temp hegiht;
final double sw;
final double sh;
final PdfPageData pData = decode_pdf.getPdfPageData();
final int curPW = pData.getCropBoxWidth(page); //current page width
final int curPH = pData.getCropBoxHeight(page); //current page height
switch (rotation) {
case 0:
tw = curPW;
th = curPH;
break;
case 90:
tw = curPH;
th = curPW;
break;
case 180:
tw = curPW;
th = curPH;
break;
case 270:
tw = curPH;
th = curPW;
break;
}
switch (decode_pdf.getDisplayView()) {
case Display.SINGLE_PAGE:
switch (index) {
case 0://fit page
tempScaling = (float) getScalingRatio(tw, th, width, height);
break;
case 1://fit height;
tempScaling = (float) (height / th);
break;
case 2://fit width;
tempScaling = (float) (width / tw);
break;
default://other percentages;
tempScaling = decode_pdf.getDPIFactory().adjustScaling(scalingFloatValues[index]);
break;
}
sw = (int) (tempScaling * tw);
sh = (int) (tempScaling * th);
if (sw < width) {
group.setTranslateX((width - sw) / 2.0);
} else {
group.setTranslateX(0);
}
//##we need to hide the scrollbar and show the scrollpane if content does not fit
if (sh < height && sw < width) {
// setScrollBarPolicy(GUI.ScrollPolicy.VERTICAL_NEVER);
// setScrollBarPolicy(GUI.ScrollPolicy.HORIZONTAL_NEVER);
// setThumbnailScrollBarVisibility(true);
// group.setTranslateY((height - sh) / 2.0);
} else {
// setScrollBarPolicy(GUI.ScrollPolicy.VERTICAL_AS_NEEDED);
// setScrollBarPolicy(GUI.ScrollPolicy.HORIZONTAL_AS_NEEDED);
// setThumbnailScrollBarVisibility(false);
// group.setTranslateY(0);
}
group.setTranslateY(0);
break;
case Display.CONTINUOUS:
switch (index) {
case 0://fit page
tempScaling = (float) getScalingRatio(tw, th, width, height);
break;
case 1://fit height;
tempScaling = (float) (height / th);
break;
case 2://fit width;
tempScaling = (float) (width / tw);
break;
default://other percentages;
tempScaling = decode_pdf.getDPIFactory().adjustScaling(scalingFloatValues[index]);
break;
}
sw = (int) (tempScaling * tw);
if (sw < width) {
group.setTranslateX((width - sw) / 2.0);
} else {
group.setTranslateX(0);
}
group.setTranslateY(0);
break;
case Display.CONTINUOUS_FACING:
tw *= 2;
switch (index) {
case 0://fit page
tempScaling = (float) getScalingRatio(tw, th, width, height);
break;
case 1://fit height;
tempScaling = (float) (height / th);
break;
case 2://fit width;
tempScaling = (float) (width / tw);
break;
default://other percentages;
tempScaling = decode_pdf.getDPIFactory().adjustScaling(scalingFloatValues[index]);
break;
}
sw = (int) (tempScaling * tw);
if (sw < width) {
group.setTranslateX((width - sw) / 2.0);
} else {
group.setTranslateX(0);
}
group.setTranslateY(0);
break;
case Display.FACING:
break;
case Display.PAGEFLOW:
break;
default:
System.err.println("unsupported page display ");
break;
}
}
scaling = tempScaling;
// Avoid infinty
if (Float.isInfinite(scaling)) {
scaling = 1f;
}
decode_pdf.setPageParameters(scaling, page, rotation);
//Ensure the page is displayed in the correct rotation
// setRotation();
}
// double h = pageContainer.getContent().getBoundsInLocal().getHeight();
// System.out.println("scrolling " + pageContainer.getVvalue() + " height of container: " + h);
// adjustGroupToCenter();
if (LogWriter.isRunningFromIDE) {
System.out.println("Memory usage after zoom=" + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000);
}
}
/**
* Get the scaling ratio required to fit one dimension to another
*
* @param actualW double value representing actual width
* @param actualH double value representing actual height
* @param maxW double value representing max width
* @param maxH double value representing max height
* @return double value representing the scaling ration to convert actual values to max values
*/
public static double getScalingRatio(final double actualW, final double actualH, final double maxW, final double maxH) {
return Math.min((maxW / actualW), (maxH / actualH));
}
/**
* Set scaling to nearest of the viewer default values.
*
* @param newScaling The scaling value to snap to viewer default values
*/
@Override
public void snapScalingToDefaults(float newScaling) {
if (debugFX) {
System.out.println("snapScalingToDefaults");
}
newScaling = decode_pdf.getDPIFactory().adjustScaling(newScaling / 100);
final float width;
final float height;
//if(isSingle){
width = (float) pageContainer.getWidth() * 0.95f;
height = (float) pageContainer.getHeight() * 0.95f;
//}else{
// width=desktopPane.getWidth();
// height=desktopPane.getHeight();
//}
final PdfPageData pageData = decode_pdf.getPdfPageData();
int cw, ch, raw_rotation = 0;
if (decode_pdf.getDisplayView() == Display.FACING) {
raw_rotation = pageData.getRotation(commonValues.getCurrentPage());
}
final boolean isRotated = (rotation + raw_rotation) % 180 == 90;
final PageOffsets offsets = (PageOffsets) decode_pdf.getExternalHandler(Options.CurrentOffset);
switch (decode_pdf.getDisplayView()) {
case Display.CONTINUOUS_FACING:
if (isRotated) {
cw = offsets.getMaxH() * 2;
ch = offsets.getMaxW();
} else {
cw = offsets.getMaxW() * 2;
ch = offsets.getMaxH();
}
break;
case Display.CONTINUOUS:
if (isRotated) {
cw = offsets.getMaxH();
ch = offsets.getMaxW();
} else {
cw = offsets.getMaxW();
ch = offsets.getMaxH();
}
break;
case Display.FACING:
int leftPage;
if (decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER)) {
leftPage = (commonValues.getCurrentPage() / 2) * 2;
if (commonValues.getPageCount() == 2) {
leftPage = 1;
}
} else {
leftPage = commonValues.getCurrentPage();
if ((leftPage & 1) == 0) {
leftPage--;
}
}
if (isRotated) {
cw = pageData.getCropBoxHeight(leftPage);
//if first or last page double the width, otherwise add other page width
if (leftPage + 1 > commonValues.getPageCount() || leftPage == 1) {
cw *= 2;
} else {
cw += pageData.getCropBoxHeight(leftPage + 1);
}
ch = pageData.getCropBoxWidth(leftPage);
if (leftPage + 1 <= commonValues.getPageCount() && ch < pageData.getCropBoxWidth(leftPage + 1)) {
ch = pageData.getCropBoxWidth(leftPage + 1);
}
} else {
cw = pageData.getCropBoxWidth(leftPage);
//if first or last page double the width, otherwise add other page width
if (leftPage + 1 > commonValues.getPageCount()) {
cw *= 2;
} else {
cw += pageData.getCropBoxWidth(leftPage + 1);
}
ch = pageData.getCropBoxHeight(leftPage);
if (leftPage + 1 <= commonValues.getPageCount() && ch < pageData.getCropBoxHeight(leftPage + 1)) {
ch = pageData.getCropBoxHeight(leftPage + 1);
}
}
break;
default:
if (isRotated) {
cw = pageData.getCropBoxHeight(commonValues.getCurrentPage());
ch = pageData.getCropBoxWidth(commonValues.getCurrentPage());
} else {
cw = pageData.getCropBoxWidth(commonValues.getCurrentPage());
ch = pageData.getCropBoxHeight(commonValues.getCurrentPage());
}
}
float x_factor;
float y_factor;
final float window_factor;
x_factor = width / cw;
y_factor = height / ch;
if (x_factor < y_factor) {
window_factor = x_factor;
x_factor = -1;
} else {
window_factor = y_factor;
y_factor = -1;
}
if (getSelectedComboIndex(Commands.SCALING) != 0
&& ((newScaling < window_factor * 1.1 && newScaling > window_factor * 0.91)
|| ((window_factor > scaling && window_factor < newScaling) || (window_factor < scaling && window_factor > newScaling)))) {
setSelectedComboIndex(Commands.SCALING, 0);
scaling = window_factor;
} else if (y_factor != -1
&& getSelectedComboIndex(Commands.SCALING) != 1
&& ((newScaling < y_factor * 1.1 && newScaling > y_factor * 0.91)
|| ((y_factor > scaling && y_factor < newScaling) || (y_factor < scaling && y_factor > newScaling)))) {
setSelectedComboIndex(Commands.SCALING, 1);
scaling = y_factor;
} else if (x_factor != -1
&& getSelectedComboIndex(Commands.SCALING) != 2
&& ((newScaling < x_factor * 1.1 && newScaling > x_factor * 0.91)
|| ((x_factor > scaling && x_factor < newScaling) || (x_factor < scaling && x_factor > newScaling)))) {
setSelectedComboIndex(Commands.SCALING, 2);
scaling = x_factor;
} else {
setSelectedComboItem(Commands.SCALING, String.valueOf((int) decode_pdf.getDPIFactory().removeScaling(newScaling * 100)));
scaling = newScaling;
}
}
/* (non-Javadoc)
* @see org.jpedal.examples.viewer.gui.swing.GUIFactory#rotate()
*/
@Override
public void rotate() {
rotation = Integer.parseInt((String) getSelectedComboItem(Commands.ROTATION));
scaleAndRotate();
}
/**
* Scrolls the view to the specified page.
*
* @param page Page to scroll to.
*/
@Override
public void scrollToPage(final int page) {
if (debugFX) {
System.out.println("scrollToPage");
}
commonValues.setCurrentPage(page);
if (commonValues.getCurrentPage() > 0) {
//int xCord = 0;
final int pageCount = decode_pdf.getPageCount();
double yCord; // = decode_pdf.getPages().getYCordForPage(page, scaling);
//$$$$$$$$$$$$$ call it and ignore please dont delete as it has affect in continuous mode
decode_pdf.getPages().getYCordForPage(page, scaling);
// if (decode_pdf.getDisplayView() != Display.SINGLE_PAGE) {
// xCord = 0;
//}
//System.out.println("Before="+decode_pdf.getVisibleRect()+" "+decode_pdf.getPreferredSize());
final PdfPageData pageData = decode_pdf.getPdfPageData();
//final int ch = (int) (pageData.getCropBoxHeight(page) * scaling);
//final int cw = (int) (pageData.getCropBoxWidth(page) * scaling);
double totalHeight = 0;
//int pw = pageData.getScaledCropBoxWidth(page);
//int ph = pageData.getScaledCropBoxHeight(page);
//double localH = pageContainer.getContent().getBoundsInLocal().getHeight();
//double localW = pageContainer.getContent().getBoundsInLocal().getWidth();
//double viewH = pageContainer.getViewportBounds().getHeight();
//double viewW = pageContainer.getViewportBounds().getWidth();
final double vv;
switch (decode_pdf.getDisplayView()) {
case Display.SINGLE_PAGE:
break;
case Display.CONTINUOUS:
yCord = 0;
for (int i = 1; i < pageCount; i++) {
totalHeight += pageData.getScaledCropBoxHeight(i);
}
for (int i = 1; i < page; i++) {
yCord += pageData.getScaledCropBoxHeight(i);
}
vv = yCord / totalHeight;
pageContainer.setVvalue(vv);
break;
case Display.CONTINUOUS_FACING:
yCord = 0;
for (int i = 1; i < pageCount; i += 2) {
totalHeight += pageData.getScaledCropBoxHeight(i);
}
for (int i = 1; i < page; i += 2) {
yCord += pageData.getScaledCropBoxHeight(i);
}
vv = yCord / totalHeight;
pageContainer.setVvalue(vv);
break;
}
}
if (decode_pdf.getPageCount() > 1) {
fxButtons.setPageLayoutButtonsEnabled(true);
}
}
/**
* Set the thumbnail panel ready for display.
*/
@Override
public void setupThumbnailPanel() {
if (debugFX) {
System.out.println("setupThumbnailPanel");
}
decode_pdf.addExternalHandler(thumbnails, Options.ThumbnailHandler);
if (isSetup) {
return;
}
isSetup = true;
if (thumbnails.isShownOnscreen()) {
//setup and add to display
thumbnails.setupThumbnails(decode_pdf.getPageCount(), null, decode_pdf.getPdfPageData());
//add listener so clicking on button changes to page - has to be in Viewer so it can update it
final Button[] buttons = (Button[]) thumbnails.getButtons();
for (int i = 0; i < commonValues.getPageCount(); i++) {
buttons[i].setOnAction(new JavaFXPageChanger(this, commonValues, i));
}
//add global listener
thumbnails.addComponentListener();
}
}
/**
* Set the bookmarks for the outline panel
*
* @param alwaysGenerate true we will generate the bookmarks, false we only generate bookmarks if not already generated
*/
@Override
public void setBookmarks(final boolean alwaysGenerate) {
if (debugFX) {
System.out.println("setBookmarks");
//ignore if not opened
System.out.println("currentSize in setBookmarks() in JavaFXGUI requires JavaFX implementation");
}
// int currentSize=center.getDividerPosition();
//
// if((currentSize==startSize)&& !alwaysGenerate)
// return;
//ignore if already done and flag
if (bookmarksGenerated) {
return;
}
bookmarksGenerated = true;
final org.w3c.dom.Document doc = decode_pdf.getOutlineAsXML();
Node rootNode = null;
if (doc != null) {
rootNode = doc.getFirstChild();
}
if (rootNode != null) {
tree.reset(rootNode);
// Allows an already selected node to be clicked again
final EventHandler reselectionListener = new EventHandler() {
@Override
public void handle(final MouseEvent event) {
final String ref = ((JavaFXOutline.OutlineNode) ((javafx.scene.Node) event.getSource()).getUserData()).getObjectRef();
gotoPageByRef(ref);
}
};
((TreeView