/*
 * Copyright (c) 1997-2018 IDRsolutions (https://www.idrsolutions.com)
 */
package org.jpedal.examples.viewer.gui;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.border.AbstractBorder;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;

import org.jpedal.FileAccess;
import org.jpedal.PdfDecoder;
import org.jpedal.PdfDecoderInt;
import org.jpedal.constants.JPedalSettings;
import org.jpedal.display.*;
import org.jpedal.display.swing.MultiDisplay;
import org.jpedal.display.swing.SingleDisplay;
import org.jpedal.examples.viewer.Commands;
import org.jpedal.examples.viewer.RecentDocuments;
import org.jpedal.examples.viewer.RecentDocumentsFactory;
import org.jpedal.examples.viewer.Values;
import org.jpedal.examples.viewer.commands.OpenFile;
import org.jpedal.examples.viewer.commands.PageNavigator;
import org.jpedal.examples.viewer.gui.generic.*;
import org.jpedal.examples.viewer.gui.popups.PrintPanel;
import org.jpedal.examples.viewer.gui.swing.*;
import org.jpedal.examples.viewer.paper.PaperSizes;
import org.jpedal.examples.viewer.utils.CSSToJavaValues;
import org.jpedal.examples.viewer.utils.PropertiesFile;
import org.jpedal.exception.PdfException;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.external.OffsetOptions;
import org.jpedal.external.Options;
import org.jpedal.external.RenderChangeListener;
import org.jpedal.fonts.tt.TTGlyph;
import org.jpedal.gui.GUIFactory;
import org.jpedal.io.PageLabels;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.io.StatusBar;
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;


/**
 <br>Description: Swing GUI functions in Viewer
 */
public class SwingGUI extends GUI {

    private RefreshLayout viewListener;

    private final Buttons swButtons = new Buttons();

    //GUICursor object that holds everything todo with Cursor for SwingGUI
    private final SwingCursor guiCursor = new SwingCursor();

    //all mouse actions
    private GUIMouseHandler mouseHandler;

    private Timer memoryMonitor;

    private SwingScrollListener scrollListener;

    //This scroll bar allows for page navigation via the scroll bar/wheel when the page
    //fits within the dimensions of the viewable area
    private JScrollBar thumbscroll;

    //Creates the top toolbar
    private final JPanel top;

    private boolean sideTabBarOpenByDefault;
    private String startSelectedTab = "";

    //use new GUI layout
    private boolean hasListener;
    private boolean isSetup;
    private int lastTabSelected = -1;
    private boolean tabsExpanded;

    private PaperSizes paperSizes;

    //Multibox for new GUI Layout to contain memory, cursor and loading bars
    private final JPanel multibox;

    //Track whether both pages are properly displayed
    private boolean pageTurnScalingAppropriate = true;

    //holds back/forward buttons at bottom of page
    private JToolBar navButtons;

    //hold the thumbnails for display panes
    private final JPanel containerForThumbnails;

    // visual display of current cursor co-ords on page
    private JLabel coords;

    //root element to hold display
    private Container frame;

    //element to add portfolio display to
    private Container portfolioParent;

    // alternative internal JFrame
    private JDesktopPane desktopPane;

    //displayed on left to hold thumbnails, bookmarks
    private JTabbedPane navOptionsPanel;

    //split display between PDF and thumbnails/bookmarks
    private JSplitPane displayPane;


    //Scrollpane for pdf panel
    private JScrollPane scrollPane;

    //Interactive display object - needs to be added to PdfDecoder
    private StatusBar statusBar = new StatusBar(new Color(2351540));
    private StatusBar downloadBar = new StatusBar(new Color(1852090));

    private JLabel pageCounter1;

    //allow user to control messages in Viewer
//    private CustomMessageHandler customMessageHandler;

    private JTextField pageCounter2;

    private JLabel pageCounter3;

    private SwingSignaturesPanel signaturesTree;

    private SwingLayersPanel layersPanel;

    private SwingAnnotationPanel annotationsPanel;

    private SwingPortfolioDetail detailView;

    private SwingPortfolioTile tileView;

    private SwingAttachmentsPanel attachmentsPanel;

    //stop user forcing open tab before any pages loaded
    private boolean tabsNotInitialised = true;
    private JToolBar navToolBar;
    private JToolBar pagesToolBar;

    //Progress bar on nav bar
    private final JProgressBar memoryBar;

    //Component to display cursor position on page
    private final JToolBar cursor;

    private PrintPanel printPanel;

    private JPanel glassPane;

    private boolean searchInMenu;
    private JTextField searchText;

    private JToggleButton options;
    private JPopupMenu menu;

    private boolean cursorOverPage;

    private final JLayeredPane lpane;

    /**
     * Create the user interface for the Viewer example.
     *
     @param decode_pdf
     @param commonValues
     @param thumbnails
     @param properties
     */
    public SwingGUI(final PdfDecoderInt decode_pdf, final Values commonValues, final GUIThumbnailPanel thumbnails, final PropertiesFile properties) {
        super(decode_pdf, commonValues, thumbnails, properties);

        // Make sure this is called before initialising the components
        final String lafOption = System.getProperty("org.jpedal.userControledLAF");
        if (lafOption == null || !lafOption.equalsIgnoreCase("true")) {
            setLookAndFeel();
        }

        //Initialise the java components
        top = new JPanel();
        multibox = new JPanel();
        navButtons = new JToolBar();
        containerForThumbnails = new JPanel();
        coords = new JLabel();
        frame = new JFrame();
        portfolioParent = ((RootPaneContainerframe).getContentPane();
        desktopPane = new JDesktopPane();
        navOptionsPanel = new JTabbedPane();
        pageCounter2 = new JTextField(4);
        pageCounter3 = new JLabel();
        memoryBar = new JProgressBar();
        cursor = new JToolBar();
        navToolBar = new JToolBar();
        pagesToolBar = new JToolBar();
        signaturesTree = new SwingSignaturesPanel();
        layersPanel = new SwingLayersPanel();
        scrollPane = new JScrollPane();
        tree = new SwingOutline();
        lpane = new JLayeredPane() {
            @Override
            public void doLayout() {
                synchronized (getTreeLock()) {
                    final int w = getWidth();
                    final int h = getHeight();
                    for (final Component c : getComponents()) {
                        c.setBounds(00, w, h);
                    }
                }
            }
        };
        setupDisplay();
    }

    /**
     * set the look and feel for the GUI components to be the
     * default for the system it is running on
     */
    private static void setLookAndFeel() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        catch (final ClassNotFoundException | IllegalAccessException | InstantiationException | UnsupportedLookAndFeelException e) {
            LogWriter.writeLog("Exception " + e + " setting look and feel");
        }
    }

    /**
     * setup display
     */
    private void setupDisplay() {
        if (SwingUtilities.isEventDispatchThread()) {

            setDisplayView(Display.SINGLE_PAGE, Display.DISPLAY_CENTERED);

        else {
            final Runnable doPaintComponent = () -> setDisplayView(Display.SINGLE_PAGE, Display.DISPLAY_CENTERED);
            SwingUtilities.invokeLater(doPaintComponent);
        }

        //pass in SwingGUI so we can call via callback
        decode_pdf.addExternalHandler(this, Options.GUIContainer);

        //pass properties into Swing Menu items
        menuItems = new SwingMenuItems(properties);

        //setup display multiview display just in case
        desktopPane.setBackground(frame.getBackground());
        desktopPane.setVisible(true);
        if (frame instanceof JFrame) {
            ((RootPaneContainerframe).getContentPane().add(desktopPane, BorderLayout.CENTER);
        else {
            frame.add(desktopPane, BorderLayout.CENTER);
        }
    }

    /**
     * Returns the split pane used in the display area of the viewer.
     *
     @return JSplitPane used to hold the page display and the side tab bar
     */
    @Override
    public JSplitPane getDisplayPane() {
        return displayPane;
    }

    /**
     * Returns the scroll bar used in single page mode that shows page thumbnails as you scroll
     *
     @return JScrollBar used for the thumbnail scroll in single page mode
     */
    @Override
    public JScrollBar getThumbnailScrollBar() {
        return thumbscroll;
    }

    /**
     * Control thumbnail scroll bars visibility
     *
     @param isVisible boolean value to control visibility
     */
    @Override
    public void setThumbnailScrollBarVisibility(final boolean isVisible) {
        thumbscroll.setVisible(isVisible);
    }

    /**
     * Set the position of the scroll bar based on desired page number
     *
     @param pageNum int value for the page
     */
    @Override
    public void setThumbnailScrollBarValue(final int pageNum) {
        thumbscroll.setValue(pageNum);
    }

    /**
     * Get the pane used in Multiviewer example to hold the internal frames
     *
     @return Object for the desktopPane used
     */
    @Override
    public Object getMultiViewerFrames() {
        return desktopPane;
    }

    /**
     * Gets the file path for the properties file used in the viewer.
     *
     @return String containing the properties file name
     */
    @Override
    public String getPropertiesFileLocation() {
        return properties.getConfigFile();
    }

    /**
     * Gets the page number of the given bookmark
     *
     @param bookmark String value of the bookmark
     @return String value of the page number
     */
    @Override
    public String getBookmark(final String bookmark) {
        return tree.getPage(bookmark);
    }

    /**
     * Set the side tab bar state and set any values required for that state.
     *
     @param showVisible true to expand the side tab bar, false to collapse
     */
    @Override
    public void reinitialiseTabs(final boolean showVisible) {

        if (properties.getValue("ShowSidetabbar").equalsIgnoreCase("true")) {

            if (!showVisible && !properties.getValue("consistentTabBar").equalsIgnoreCase("true")) {
                if (sideTabBarOpenByDefault) {
                    displayPane.setDividerLocation(expandedSize);
                    tabsExpanded = true;
                else {
                    displayPane.setDividerLocation(collapsedSize);
                    tabsExpanded = false;
                    navOptionsPanel.setSelectedIndex(-1);
                }
            }
            lastTabSelected = -1;

            if (commonValues.isPDF()) {

                //add/remove optional tabs
                if (!decode_pdf.hasOutline()) {

                    final int outlineTab = getTabIndex(bookmarksTitle);

                    if (outlineTab != -1) {
                        navOptionsPanel.remove(outlineTab);
                    }

                else if (properties.getValue("Bookmarkstab").equalsIgnoreCase("true")) {
                    final int outlineTab = getTabIndex(bookmarksTitle);
                    if (outlineTab == -1) {
                        if (DecoderOptions.isRunningOnMac) {
                            navOptionsPanel.addTab(bookmarksTitle, (Componenttree);
                        else {
                            final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, bookmarksTitle);
                            navOptionsPanel.addTab(null, textIcon2, (Componenttree);
                        }
                    }
                }

                //handle signatures pane
                final AcroRenderer currentFormRenderer = decode_pdf.getFormRenderer();

                Iterator<FormObject> signatureObjects = null;

                if (currentFormRenderer != null) {
                    signatureObjects = currentFormRenderer.getSignatureObjects();
                }

                if (signatureObjects != null) {
                    signaturesTree.reinitialise(decode_pdf, signatureObjects);
                    checkTabShown(signaturesTitle);
                else {
                    removeTab(signaturesTitle);
                }

                                 //add a control Panel to enable/disable layers
                layersObject = (PdfLayerListdecode_pdf.getJPedalObject(PdfDictionary.Layer);

                if (layersObject != null && layersObject.getLayersCount() 0) { //some files have empty Layers objects

                    checkTabShown(layersTitle);
                    layersPanel.reinitialise(layersObject, decode_pdf, scrollPane, commonValues.getCurrentPage());

                else {
                    removeTab(layersTitle);
                }


                final PdfObjectReader reader = decode_pdf.getIO();
                Object[] embeddedFiles = null;
                if (reader != null) {
                    if (reader.getNamesLookup() != null) {
                        embeddedFiles = reader.getNamesLookup().getEmbeddedFiles();
                    }
                    if (attachmentsPanel == null) {
                        attachmentsPanel = new SwingAttachmentsPanel(this);
                    }

                    //Always load values even when null as this method also loads values stored in annotations
                    if (attachmentsPanel.loadEmbeddedFileData(decode_pdf, embeddedFiles)) {
                        checkTabShown(attachmentsTitle);
                    else {
                        removeTab(attachmentsTitle);
                    }

                }

                if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE && !decode_pdf.isEncrypted()) {
                    checkTabShown(annotationTitle);
                else {
                    removeTab(annotationTitle);
                }

                setBookmarks(false);
            }

            if (tabsNotInitialised) {
                navOptionsPanel.setSelectedIndex(-1);
                for (int i = 0; i != navOptionsPanel.getTabCount(); i++) {
                    if (DecoderOptions.isRunningOnMac) {
                        if (navOptionsPanel.getTitleAt(i).equals(startSelectedTab)) {
                            navOptionsPanel.setSelectedIndex(i);
                            break;
                        }
                    else {
                        if (navOptionsPanel.getIconAt(i).toString().equals(startSelectedTab)) {
                            navOptionsPanel.setSelectedIndex(i);
                            break;
                        }
                    }
                }
            }
        }
    }

    private int getTabIndex(final String title) {
        int tabIndex = -1;
        if (DecoderOptions.isRunningOnMac) {
            //see if there is an outlines tab
            for (int jj = 0; jj < navOptionsPanel.getTabCount(); jj++) {
                if (navOptionsPanel.getTitleAt(jj).equals(title)) {
                    tabIndex = jj;
                }
            }
        else {
            //see if there is an outlines tab
            for (int jj = 0; jj < navOptionsPanel.getTabCount(); jj++) {
                if (navOptionsPanel.getIconAt(jj).toString().equals(title)) {
                    tabIndex = jj;
                }
            }
        }
        return tabIndex;
    }

    private void checkTabShown(final String title) {
        final int outlineTab = getTabIndex(title);

        if (outlineTab == -1) {
            if (DecoderOptions.isRunningOnMac) {

                if (title.equals(signaturesTitle&& properties.getValue("Signaturestab").equalsIgnoreCase("true")) {
                    navOptionsPanel.addTab(signaturesTitle, signaturesTree);
                    navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() 1, signaturesTitle);

                else if (title.equals(layersTitle&& properties.getValue("Layerstab").equalsIgnoreCase("true")) {

                    final JScrollPane layerScrollPane = new JScrollPane();
                    layerScrollPane.getViewport().add(layersPanel);
                    layerScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                    layerScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

                    navOptionsPanel.addTab(layersTitle, layerScrollPane);
                    navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() 1, layersTitle);

                else if (title.equals(annotationTitle&& properties.getValue("AnnotationTab").equalsIgnoreCase("true"&& SwingAnnotationPanel.addPanel()) {
                    navOptionsPanel.addTab(annotationTitle, (ComponentannotationsPanel.getDisplayPanel());
                    navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() 1, annotationTitle);

                else if (title.equals(attachmentsTitle&& properties.getValue("AttachmentsTab").equalsIgnoreCase("true")) {
                    navOptionsPanel.addTab(attachmentsTitle, attachmentsPanel);
                    navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() 1, attachmentsTitle);

                }


            else {

                if (title.equals(signaturesTitle&& properties.getValue("Signaturestab").equalsIgnoreCase("true")) {  //stop spurious display of Sig tab
                    final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, signaturesTitle);
                    navOptionsPanel.addTab(null, textIcon2, signaturesTree);
                else if (title.equals(layersTitle&& properties.getValue("Layerstab").equalsIgnoreCase("true")) {
                    final VTextIcon textIcon = new VTextIcon(navOptionsPanel, layersTitle);

                    final JScrollPane scrollPane = new JScrollPane();
                    scrollPane.getViewport().add(layersPanel);
                    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

                    navOptionsPanel.addTab(null, textIcon, scrollPane);
                else if (title.equals(annotationTitle&& properties.getValue("AnnotationTab").equalsIgnoreCase("true"&& SwingAnnotationPanel.addPanel()) {

                    final VTextIcon textIcon = new VTextIcon(navOptionsPanel, annotationTitle);
                    navOptionsPanel.addTab(null, textIcon, (ComponentannotationsPanel.getDisplayPanel());

                else if (title.equals(attachmentsTitle&& properties.getValue("AttachmentsTab").equalsIgnoreCase("true")) {

                    final VTextIcon textIcon = new VTextIcon(navOptionsPanel, attachmentsTitle);
                    navOptionsPanel.addTab(null, textIcon, attachmentsPanel);

                }

            }
        }
    }

    private void removeTab(final String title) {

        final int outlineTab = getTabIndex(title);

        if (outlineTab != -1) {
            navOptionsPanel.remove(outlineTab);
        }

    }

    /**
     * Stop thumbnails from being generated for the side tab bar
     */
    @Override
    public void stopThumbnails() {

        if (thumbnails.isShownOnscreen()) {
            //if running terminate first
            thumbnails.terminateDrawing();

            thumbnails.removeAllListeners();

        }
    }

    /**
     * Flag the thumbnails tab as requires reinitialisation
     */
    @Override
    public void reinitThumbnails() {

        isSetup = false;

    }

    //reset so appears closed

    /**
     * Reset the nav bar and collapse side tab bar
     */
    @Override
    public void resetNavBar() {

        if (!properties.getValue("consistentTabBar").equalsIgnoreCase("true")) {
            displayPane.setDividerLocation(collapsedSize);
            navOptionsPanel.setSelectedIndex(-1);
            tabsNotInitialised = true;
        }

        //also reset layers
        layersPanel.resetLayers();

        //disable page view buttons until we know we have multiple pages
        swButtons.setPageLayoutButtonsEnabled(false);

    }

    /* (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() {


        bookmarksGenerated = false;

        resetNavBar();

        //Ensure preview from last file doesn't appear
        if (scrollListener != null) {
            scrollListener.lastImage = null;
        }

    }

    /**
     * Gets the object used for the thumbnail panel.
     *
     @return an Object that extends GUIThumbnailPanel
     */
    @Override
    public Object getThumbnailPanel() {
        return thumbnails;
    }

    /**
     * Gets the object used for the outline panel
     *
     @return an Object that extends GUIOutline
     */
    @Override
    public Object getOutlinePanel() {
        return tree;
    }

    /**
     * Gets the current vertical scroll bar. This will be the thumbnail scroll bar
     * if it is currently present, otherwise it will be the scrollpanes scroll bar.
     *
     @return a Object representing the scroll bar
     */
    @Override
    public Object getVerticalScrollBar() {
        if (scrollPane.getVerticalScrollBar().isVisible()) {
            return scrollPane.getVerticalScrollBar();
        else {
            return thumbscroll;
        }
    }

    /**
     * Sets the scroll bar policy for the display areas scroll pane
     *
     @param pol ScrollPolicy to be applied to the scroll pane
     */
    @Override
    public void setScrollBarPolicy(final ScrollPolicy pol) {
        switch (pol) {
            case VERTICAL_NEVER:
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                break;
            case VERTICAL_AS_NEEDED:
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                break;
            case HORIZONTAL_NEVER:
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                break;
            case HORIZONTAL_AS_NEEDED:
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                break;

        }
    }

    /**
     * Specify a Container for the viewers interface to be added to.
     *
     @param rawValue an Object that extends container to add the user interface to.
     */
    @Override
    public void setRootContainer(final Object rawValue) {

        if (rawValue == null) {
            throw new RuntimeException("Null containers not allowed.");
        }

        final Container rootContainer = (ContainerrawValue;

        Container c = rootContainer;

        if ((rootContainer instanceof JTabbedPane)) {
            final JPanel temp = new JPanel(new BorderLayout());
            rootContainer.add(temp);
            c = temp;
        else if (rootContainer instanceof JScrollPane) {
            final JPanel temp = new JPanel(new BorderLayout());
            ((JScrollPanerootContainer).getViewport().add(temp);
            c = temp;

        else if (rootContainer instanceof JSplitPane) {
            throw new RuntimeException("To add the viewer to a split pane please pass through either JSplitPane.getLeftComponent() or JSplitPane.getRightComponent()");
        }

        if (rootContainer instanceof JFrame) {
            portfolioParent = ((RootPaneContainerrootContainer).getContentPane();
        else {
            c.setLayout(new BorderLayout());
            portfolioParent = c;
        }

        //Load width and height from properties file
        int width = Integer.parseInt(properties.getValue("startViewerWidth"));
        int height = Integer.parseInt(properties.getValue("startViewerHeight"));

        //Used to prevent infinite scroll issue as a preferred size has been set
        final Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        if (width < 0) {
            width = d.width / 2;
            if (width < 700) {
                width = 700;
            }
            properties.setValue("startViewerWidth", String.valueOf(width));
        }

        if (height < 0) {
            height = d.height / 2;
            properties.setValue("startViewerHeight", String.valueOf(height));
        }

        //allow user to alter size
        final String customWindowSize = System.getProperty("org.jpedal.startWindowSize");
        if (customWindowSize != null) {

            final StringTokenizer values = new StringTokenizer(customWindowSize, "x");

            if (values.countTokens() != 2) {
                throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300");
            }

            try {
                width = Integer.parseInt(values.nextToken().trim());
                height = Integer.parseInt(values.nextToken().trim());

            catch (final NumberFormatException ee) {
                throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300 " + ee);
            }
        }

        c.setPreferredSize(new Dimension(width, height));

        frame = c;

    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#resetRotationBox()
     */
    @Override
    public void resetRotationBox() {

        final PdfPageData currentPageData = decode_pdf.getPdfPageData();

        if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
            rotation = currentPageData.getRotation(commonValues.getCurrentPage());
        }
        if (getSelectedComboIndex(Commands.ROTATION!= (rotation / 90)) {
            setSelectedComboIndex(Commands.ROTATION, (rotation / 90));
        else if (!Values.isProcessing()) {
            decode_pdf.repaint();
        }
    }

    /* (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
     *
     @param searchFrame the search window that will be add to the side tab bar
     */
    @Override
    public void searchInTab(final GUISearchWindow searchFrame) {
        this.searchFrame = searchFrame;

        this.searchFrame.init(decode_pdf, commonValues);

        if (DecoderOptions.isRunningOnMac) {
            if (thumbnails.isShownOnscreen()) {
                navOptionsPanel.addTab("Search"((RootPaneContainersearchFrame).getContentPane());
            }
        else {
            final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, "Search");
            navOptionsPanel.addTab(null, textIcon2, ((RootPaneContainersearchFrame).getContentPane());
        }

        //Create menu bar text field to trigger side tab bar
        final JTextField searchTextLocal = new JTextField();
        searchTextLocal.setColumns(searchText.getColumns());
        searchTextLocal.setText(searchText.getText());

        //Get last listener as all listeners added to the end of the array
        searchTextLocal.addKeyListener(searchText.getKeyListeners()[searchText.getKeyListeners().length - 1]);
        searchTextLocal.addFocusListener(searchText.getFocusListeners()[searchText.getFocusListeners().length - 1]);
        searchTextLocal.addActionListener(e -> {
            navOptionsPanel.setSelectedComponent(((RootPaneContainersearchFrame).getContentPane());
            if (!tabsExpanded) {
                displayPane.setDividerLocation(expandedSize);
                tabsExpanded = true;
                thumbnails.setIsDisplayedOnscreen(false);
            }
            searchText.setText(searchTextLocal.getText());

        });
        searchText.addActionListener(e -> searchTextLocal.setText(searchText.getText()));
        swButtons.getTopButtons().add(searchTextLocal);
    }

    private JToggleButton createMenuBarSearchOptions() {
        if (options == null) {
            options = new JToggleButton(new ImageIcon(guiCursor.getURLForImage("menuSearchOptions.png")));
            menu = new JPopupMenu();
            options.setBorder(null);

            options.addItemListener(e -> {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    menu.show(((Componente.getSource())0((Componente.getSource()).getHeight());
                }
            });
            options.setFocusable(false);
            options.setToolTipText(Messages.getMessage("PdfViewerSearch.Options"));

            final JCheckBoxMenuItem wholeWords = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.WholeWords"));
            wholeWords.setToolTipText(Messages.getMessage("PdfViewerSearch.WholeWordsTooltip"));
            wholeWords.addActionListener(e -> {
                searchFrame.setWholeWords(((AbstractButtone.getSource()).isSelected());
                enableSearchItems(true);
            });

            final JCheckBoxMenuItem caseSense = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.CaseSense"));
            caseSense.setToolTipText(Messages.getMessage("PdfViewerSearch.CaseSenseTooltip"));
            caseSense.addActionListener(e -> {
                searchFrame.setCaseSensitive(((AbstractButtone.getSource()).isSelected());
                enableSearchItems(true);
            });

            final JCheckBoxMenuItem multiLine = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.MultiLine"));
            multiLine.setToolTipText(Messages.getMessage("PdfViewerSearch.MultiLineTooltip"));
            multiLine.addActionListener(e -> {
                searchFrame.setMultiLine(((AbstractButtone.getSource()).isSelected());
                enableSearchItems(true);
            });

            final JCheckBoxMenuItem ignoreSpaces = new JCheckBoxMenuItem(Messages.getMessage("PdfViewerSearch.IgnoreSpaces"));
            ignoreSpaces.setToolTipText(Messages.getMessage("PdfViewerSearch.IgnoreSpacesTooltip"));
            ignoreSpaces.addActionListener(e -> {
                searchFrame.setIgnoreSpaces(((AbstractButtone.getSource()).isSelected());
                enableSearchItems(true);
            });

            menu.add(wholeWords);
            menu.add(caseSense);
            menu.add(multiLine);
            menu.add(ignoreSpaces);

            menu.addPopupMenuListener(new PopupMenuListener() {
                @Override
                public void popupMenuWillBecomeVisible(final PopupMenuEvent e) {
                }

                @Override
                public void popupMenuWillBecomeInvisible(final PopupMenuEvent e) {
                    options.setSelected(false);
                }

                @Override
                public void popupMenuCanceled(final PopupMenuEvent e) {
                    options.setSelected(false);
                }
            });
        }

        return options;
    }

    /*
     * Set Search Bar to be in the Top Button Bar
     */
    private void searchInMenu(final GUISearchWindow searchFrame) {
        this.searchFrame = searchFrame;
        searchInMenu = true;
        searchFrame.find(decode_pdf, commonValues);
        swButtons.getTopButtons().add(searchText);
        swButtons.getTopButtons().add(createMenuBarSearchOptions());
        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerSearch.Previous")"search_previous.gif", Commands.PREVIOUSRESULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerSearch.Next")"search_next.gif", Commands.NEXTRESULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.getButton(Commands.NEXTRESULT).setEnabled(false);
        swButtons.getButton(Commands.PREVIOUSRESULT).setEnabled(false);

        swButtons.getButton(Commands.NEXTRESULT).setVisible(true);
        swButtons.getButton(Commands.PREVIOUSRESULT).setVisible(true);
    }

    /**
     * Sets the properties file to be used
     *
     @param file String file name for the properties file to be used
     */
    @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;
    }

    /**
     * Gets the annotation tabs panel if one is present
     *
     @return an implementation of GUIAnnotationPanel
     */
    @Override
    public GUIAnnotationPanel getAnnotationPanel() {
        return annotationsPanel;
    }

    /* (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) {

        annotationsPanel = new SwingAnnotationPanel(this);

        //single listener to execute all commands
        currentCommandListener = new CommandListenerSwing(currentCommands);

        super.init(currentCommands);

        initProperties();

        final boolean separateCoverOn = properties.getValue("separateCoverOn").equalsIgnoreCase("true");
        decode_pdf.getPages().setBoolean(Display.BoolValue.SEPARATE_COVER, separateCoverOn);

        final boolean showFormFieldHighlights = properties.getValue("highlightFormFields").equalsIgnoreCase("true");
        final int formFieldHighlightColor = Integer.parseInt(properties.getValue("formFieldsHighlightColor"));
        final boolean useOffScreenRendering = properties.getValue("useOffScreenRendering").equalsIgnoreCase("true");
        final Map<Integer, Object> map = new HashMap<>();
        map.put(JPedalSettings.HIGHLIGHT_FORM_FIELDS, showFormFieldHighlights);
        map.put(JPedalSettings.HIGHLIGHT_FORM_FIELDS_COLOR, formFieldHighlightColor);
        map.put(JPedalSettings.OFF_SCREEN_RENDERING, useOffScreenRendering);
        try {
            decode_pdf.modifyNonstaticJPedalParameters(map);
        catch (final PdfException e) {
            LogWriter.writeLog("Error setting values from properties " + e);
        }

        //Add Background color to the panel to help break up view.
        setupCenterPanelBackground();

        //setup combo boxes.
        setupComboBoxes();

        if (LogWriter.isRunningFromIDE) {
            nameElements();
        }

        //add the pdf display to show page.
        setupPDFDisplayPane();

        //add the pdf display left and right panes.
        setupBorderPanes();

        //Initialise the Swing Buttons
        swButtons.init(true);

        //create a menu bar and add to display
        createTopMenuBar();


        //set colours on display boxes and add listener to page number
        setupBottomToolBarItems();

        //create other tool bars and add to display
        createOtherToolBars();

        initButtonsAndMenu();

        //navigation toolbar for moving between pages
        createNavbar();

        //add cursor location
        initCoordBox();

        
        /*
         * external/itext button option example adding new option to Export menu
         * an icon is set wtih location on classpath
         * "/org/jpedal/examples/viewer/res/newfunction.gif"
         * Make sure it exists at location and is copied into jar if recompiled
         *
         * external/itext menu option example adding new option to Export menu
         * Tooltip text can be externalised in Messages.getMessage("PdfViewerTooltip.NEWFUNCTION")
         * and text added into files in res package
         */
        //currentGUI.addButton(currentGUI.BUTTONBAR,tooltip,"/org/jpedal/examples/viewer/res/newfunction.gif",Commands.NEWFUNCTION);

        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
        frame.invalidate();
        frame.validate();
        frame.repaint();

        //Load properties
        GUIModifier.load(properties, this);

        if (commonValues.getModeOfOperation() != Values.RUNNING_APPLET) {
            initViewerWindow();
        }

        redrawDocumentOnResize();

        setupPDFBorder();

        //Set side tab bar state at start up
        if (sideTabBarOpenByDefault) {
            displayPane.setDividerLocation(expandedSize);
            tabsExpanded = true;
        else {
            displayPane.setDividerLocation(collapsedSize);
            tabsExpanded = false;
            navOptionsPanel.setSelectedIndex(-1);
        }

        applyStyle();

        mouseHandler = new SwingMouseListener((PdfDecoderdecode_pdf, this, commonValues, currentCommands);
        mouseHandler.setupMouse();

        final long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;

        //Add universal listener to catch coords updating regardless of form component
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            //Required to prevent recursive calling of listener
            boolean listenerCalled;

            @Override
            public void eventDispatched(final AWTEvent e) {

                if (decode_pdf != null) {
                    //ID 503 == Mouse Moved event (506 == Mouse Dragged)
                    if (!listenerCalled && e.getID() == MouseEvent.MOUSE_MOVED) {
                        listenerCalled = true;

                        Point mousePosition = ((Componentdecode_pdf).getMousePosition();

                        if ((annotationsPanel != null && SwingAnnotationPanel.addPanel()) && glassPane != null) {
                            mousePosition = glassPane.getMousePosition();
                        }

                        if (mousePosition != null) {
                            ((SwingMouseListenermouseHandler).allowMouseCoordsUpdate();
                            ((Componentdecode_pdf).dispatchEvent(new MouseEvent(((Componentdecode_pdf),
                                    e.getID(),
                                    System.currentTimeMillis(),
                                    0,
                                    mousePosition.x,
                                    mousePosition.y,
                                    0,
                                    false));
                        }

                        listenerCalled = false;
                    }
                }
            }
        }, eventMask);

    }

    private void initViewerWindow() {

        //Load width and height from properties file
        int width = Integer.parseInt(properties.getValue("startViewerWidth"));
        int height = Integer.parseInt(properties.getValue("startViewerHeight"));

        //Used to prevent infinite scroll issue as a preferred size has been set
        final Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        if (width < 0) {
            width = d.width / 2;
            if (width < minimumScreenWidth) {
                width = minimumScreenWidth;
            }
            properties.setValue("startViewerWidth", String.valueOf(width));
        }

        if (height < 0) {
            height = d.height / 2;
            properties.setValue("startViewerHeight", String.valueOf(height));
        }

        //allow user to alter size
        final String customWindowSize = System.getProperty("org.jpedal.startWindowSize");
        if (customWindowSize != null) {

            final StringTokenizer values = new StringTokenizer(customWindowSize, "x");

            if (values.countTokens() != 2) {
                throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300");
            }

            try {
                width = Integer.parseInt(values.nextToken().trim());
                height = Integer.parseInt(values.nextToken().trim());

            catch (final NumberFormatException ee) {
                throw new RuntimeException("Unable to use value for org.jpedal.startWindowSize=" + customWindowSize + "\nValue should be in format org.jpedal.startWindowSize=200x300 " + ee);
            }
        }

        createMainViewerWindow(width, height);
    }

    private void initButtonsAndMenu() {

        //Menu bar for using the majority of functions
        menuItems.createMainMenu(true, currentCommandListener,  currentCommands, swButtons);

        //sets up all the toolbar items
        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.openFile")"open.gif", Commands.OPENFILE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.saveFile")"save.gif", Commands.SAVE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.print")"print.gif", Commands.PRINT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        if (searchFrame != null && (searchFrame.getViewStyle() == GUISearchWindow.SEARCH_EXTERNAL_WINDOW)) {
            searchFrame.setViewStyle(GUISearchWindow.SEARCH_EXTERNAL_WINDOW);
            swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.search")"find.gif", Commands.FIND, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
        }

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.properties")"properties.gif", Commands.DOCINFO, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        //snapshot screen function
        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.snapshot")"snapshot.gif", Commands.SNAPSHOT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.minimise")"minimise.gif", Commands.ZOOMOUT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.zoom")"zoom.gif", Commands.ZOOMIN, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        final JSeparator sep = new JSeparator(SwingConstants.VERTICAL);
        sep.setPreferredSize(new Dimension(532));
        swButtons.getTopButtons().add(sep);

        //combo boxes on toolbar
        addCombo(Messages.getMessage("PdfViewerToolbarTooltip.zoomin"), Commands.SCALING);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.rotateLeft")"rotateLeft.gif", Commands.ROTATELEFT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);
        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.rotateRight")"rotateRight.gif", Commands.ROTATERIGHT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        addCombo(Messages.getMessage("PdfViewerToolbarTooltip.rotation"), Commands.ROTATION);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.mouseMode")"mouse_select.png", Commands.MOUSEMODE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        final JSeparator sep2 = new JSeparator(SwingConstants.VERTICAL);
        sep2.setPreferredSize(new Dimension(532));
        swButtons.getTopButtons().add(sep2);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.help")"help.png", Commands.HELP, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(GUIFactory.BUTTONBAR, Messages.getMessage("PdfViewerToolbarTooltip.openSystemDefault")"openSystem.png", Commands.OPENINSYSTEMDEFAULT, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

    }

    private void initProperties() {

        //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())) {
                JOptionPane.showMessageDialog(null, 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()) {
            guiCursor.setIconLocation(propValue);
        }
    }

    private void nameElements() {
        ((SwingMenuItemsmenuItems).getCurrentMenu().setName("menuBar");
        this.frame.setName("frame");
        this.pageCounter2.setName("pageCounter");

        this.rotationBox.setName("rotationBox");
        this.scalingBox.setName("scalingBox");
    }

    /**
     * method being called from within init to create other tool bars to add to
     * display
     */
    private void createOtherToolBars() {

        //setup top main menu toolbar and create options
        top.add(((SwingMenuItemsmenuItems).getCurrentMenu(), BorderLayout.NORTH);

        //This is where we add the Buttons for the top ToolBar
        top.add(swButtons.getTopButtons(), BorderLayout.CENTER);


        //This is where we add the Buttons for the bottom ToolBar
        if (frame instanceof JFrame) {
            ((RootPaneContainerframe).getContentPane().add(navButtons, BorderLayout.SOUTH);
        else {
            frame.add(navButtons, BorderLayout.SOUTH);
        }

        //This is where we add the display pane to the center of the viewer
        if (displayPane != null) { //null in MultiViewer
            if (frame instanceof JFrame) {
                ((RootPaneContainerframe).getContentPane().add(displayPane, BorderLayout.CENTER);
            else {
                frame.add(displayPane, BorderLayout.CENTER);
            }

        }

    }

    private void handleTabbedPanes() {

        if (tabsNotInitialised) {
            return;
        }

        //expand size if not already at size
        final int tabSelected = navOptionsPanel.getSelectedIndex();

        if (tabSelected == -1) {
            return;
        }

        if (!tabsExpanded) {
            //workout selected tab
            final String tabName;
            if (DecoderOptions.isRunningOnMac) {
                tabName = navOptionsPanel.getTitleAt(tabSelected);
            else {
                tabName = navOptionsPanel.getIconAt(tabSelected).toString();
            }

            if (tabName.equals(pageTitle)) {
                thumbnails.setIsDisplayedOnscreen(true);
            else {
                thumbnails.setIsDisplayedOnscreen(false);
            }

            if (tabName.equals(annotationTitle)) {
                if (decode_pdf.isEncrypted()) {
                    showMessageDialog((Messages.getMessage("PdfViewerMessage.NewAnnotInEncryptedFile")), Messages.getMessage("PdfViewerGeneral.Warning"), JOptionPane.WARNING_MESSAGE);
                }
                annotationsPanel.populateList(decode_pdf);
            }

            displayPane.setDividerLocation(expandedSize);
            tabsExpanded = true;
        else if (lastTabSelected == tabSelected) {
            displayPane.setDividerLocation(collapsedSize);
            tabsExpanded = false;
            thumbnails.setIsDisplayedOnscreen(false);
            navOptionsPanel.setSelectedIndex(-1);
        }
        lastTabSelected = tabSelected;
    }

    /**
     * Not part of API - used internally
     <p>
     * Set the state and value for the multi box at the bottom left of the user interface.
     *
     @param flags an int[] used to control multi box display
     */
    @Override
    public void setMultibox(final int[] flags) {

        //debug code for formclicktests
        if (GUI.alwaysShowMouse) {
            multibox.removeAll();
            multibox.add(coords, BorderLayout.CENTER);

            multibox.repaint();
            return;
        }

        //deal with flags
        if (flags.length > && flags[0== CURSOR) {
            //if no change, return
            if (cursorOverPage != (flags[1== 1)) {
                cursorOverPage = flags[1== 1;
            else {
                return;
            }
        }

        //LOAD_PROGRESS:
        if (statusBar.isEnabled() && statusBar.isVisible() && !statusBar.isDone()) {
            multibox.removeAll();
            statusBar.getStatusObject().setSize(multibox.getSize());
            multibox.add(statusBar.getStatusObject(), BorderLayout.CENTER);

            multibox.repaint();
            return;
        }

        //CURSOR:
        if (cursor.isEnabled() && cursor.isVisible() && cursorOverPage && decode_pdf.isOpen()) {
            multibox.removeAll();
            multibox.add(coords, BorderLayout.CENTER);

            multibox.repaint();
            return;
        }

        //DOWNLOAD_PROGRESS:
        if (downloadBar.isEnabled() && downloadBar.isVisible() && !downloadBar.isDone() && (decode_pdf.isLoadingLinearizedPDF() || !decode_pdf.isOpen())) {
            multibox.removeAll();
            downloadBar.getStatusObject().setSize(multibox.getSize());
            multibox.add(downloadBar.getStatusObject(), BorderLayout.CENTER);

            multibox.repaint();
            return;
        }

        //MEMORY:
        if (memoryBar.isEnabled() && memoryBar.isVisible()) {
            multibox.removeAll();
            memoryBar.setSize(multibox.getSize());
            memoryBar.setForeground(new Color(125145255));
            multibox.add(memoryBar, BorderLayout.CENTER);

            multibox.repaint();
        }

    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    @Override
    protected void setTitle(final String title) {
        if (frame instanceof JFrame) {
            ((Frameframe).setTitle(title);
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#resetComboBoxes(boolean)
     */
    @Override
    public void resetComboBoxes(final boolean value) {

        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) {

        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 != null) {
            if (decode_pdf.getDisplayView() == Display.PAGEFLOW) {
                decode_pdf.setPageParameters(scaling, commonValues.getCurrentPage(), rotation);
                return;
            }

            //ignore if called too early
            if (!decode_pdf.isOpen() && OpenFile.isPDf) {
                return;
            }
        }

        // [AWI]: Get the values of all of the border insets around the scrollpane
        Insets borderInsets = new Insets(0000);
        if (scrollPane.getBorder() != null && scrollPane.getBorder().getBorderInsets(scrollPane!= null) {
            borderInsets = scrollPane.getBorder().getBorderInsets(scrollPane);
        }
        float width = scrollPane.getWidth() - inset - inset - borderInsets.left - borderInsets.right;
        final float height = scrollPane.getHeight() - inset - inset - borderInsets.top - borderInsets.bottom;


        if (decode_pdf != null) {

            int index = getSelectedComboIndex(Commands.SCALING);

            if (decode_pdf.getDisplayView() == Display.PAGEFLOW) {

                //Ensure we only display in window mode
                setSelectedComboIndex(Commands.SCALING, 0);
                index = 0;

                //Disable scaling option
                scalingBox.setEnabled(false);
            else if (decode_pdf.getDisplayView() != Display.PAGEFLOW) {

                //No long pageFlow. enable scaling option
                scalingBox.setEnabled(true);
            }

            if (index == -1) {
                final float zoom = getScalingFromString((StringgetSelectedComboItem(Commands.SCALING));

                //if nothing off either attempt, use window value
                if (zoom == -1) {
                    //its not set so use To window value
                    index = defaultSelection;
                    setSelectedComboIndex(Commands.SCALING, index);
                else {
                    scaling = decode_pdf.getDPIFactory().adjustScaling(zoom / 100);

                    setSelectedComboItem(Commands.SCALING, String.valueOf(zoom));
                }
            }

            int page = commonValues.getCurrentPage();

            //Multipage tiff should be treated as a single page
            if (commonValues.isMultiTiff()) {
                page = 1;
            }

            //always check in facing mode with turnover on
            if (index != -|| decode_pdf.getDisplayView() == Display.SINGLE_PAGE || (decode_pdf.getDisplayView() == Display.FACING && decode_pdf.getPages().getBoolean(Display.BoolValue.TURNOVER_ON))) {

                final Dimension contentSize = getContentDimensions(page);

                if (displayPane != null) {
                    width -= displayPane.getDividerSize();
                }

                setupScalingValue(index, width, height, contentSize.width, contentSize.height);
            }

            //allow for clicking on it before page opened
            decode_pdf.setPageParameters(scaling, page, rotation);

            //Ensure the page is displayed in the correct rotation
            setRotation();

        }

        if (LogWriter.isRunningFromIDE) {
            System.out.println("Memory usage after zoom=" (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) 1_000);
        }

        //Update annotation selection position if required
        ((SwingMouseAnnotationsannotationsPanel.getAnnotationListener()).updateSelectionPosition();

    }

    private Dimension getContentDimensions(final int page) {
        final Dimension dimensions = new Dimension();
        final PdfPageData pageData = decode_pdf.getPdfPageData();
        final int raw_rotation;

        if (decode_pdf.getDisplayView() == Display.FACING) {
            raw_rotation = pageData.getRotation(page);
        else {
            raw_rotation = 0;
        }

        final boolean isRotated = (rotation + raw_rotation180 == 90;

        final PageOffsets offsets = (PageOffsetsdecode_pdf.getExternalHandler(Options.CurrentOffset);
        switch (decode_pdf.getDisplayView()) {
            case Display.CONTINUOUS_FACING:
                if (isRotated) {
                    dimensions.width = offsets.getMaxH() 2;
                    dimensions.height = offsets.getMaxW();
                else {
                    dimensions.width = offsets.getMaxW() 2;
                    dimensions.height = offsets.getMaxH();
                }
                break;
            case Display.CONTINUOUS:
                if (isRotated) {
                    dimensions.width = offsets.getMaxH();
                    dimensions.height = offsets.getMaxW();
                else {
                    dimensions.width = offsets.getMaxW();
                    dimensions.height = offsets.getMaxH();
                }
                break;
            case Display.FACING:
                int leftPage;

                if (decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER)) {
                    leftPage = (page / 22;
                    if (commonValues.getPageCount() == 2) {
                        leftPage = 1;
                    }
                else {
                    leftPage = (page);
                    if ((leftPage & 1== 0) {
                        leftPage--;
                    }
                }

                if (leftPage == 0) {
                    leftPage++;
                }

                if (isRotated) {
                    dimensions.width = pageData.getCropBoxHeight(leftPage);

                    //if first or last page double the width, otherwise add other page width
                    if (leftPage + > commonValues.getPageCount() || leftPage == 1) {
                        dimensions.width *= 2;
                    else {
                        dimensions.width += pageData.getCropBoxHeight(leftPage + 1);
                    }

                    dimensions.height = pageData.getCropBoxWidth(leftPage);
                    if (leftPage + <= commonValues.getPageCount() && dimensions.height < pageData.getCropBoxWidth(leftPage + 1)) {
                        dimensions.height = pageData.getCropBoxWidth(leftPage + 1);
                    }
                else {
                    dimensions.width = pageData.getCropBoxWidth(leftPage);

                    //if first or last page double the width, otherwise add other page width
                    if (leftPage + > commonValues.getPageCount()) {
                        dimensions.width *= 2;
                    else {
                        dimensions.width += pageData.getCropBoxWidth(leftPage + 1);
                    }

                    dimensions.height = pageData.getCropBoxHeight(leftPage);
                    if (leftPage + <= commonValues.getPageCount() && dimensions.height < pageData.getCropBoxHeight(leftPage + 1)) {
                        dimensions.height = pageData.getCropBoxHeight(leftPage + 1);
                    }
                }
                break;
            default:
                if (isRotated) {
                    dimensions.width = pageData.getCropBoxHeight(page);
                    dimensions.height = pageData.getCropBoxWidth(page);
                else {
                    dimensions.width = pageData.getCropBoxWidth(page);
                    dimensions.height = pageData.getCropBoxHeight(page);
                }
        }

        //Check if image with no size data stored and get values direct from image
        if (dimensions.width == && dimensions.height == && commonValues.getBufferedImg() != null) {
            if (isRotated) {
                dimensions.width = commonValues.getBufferedImg().getHeight();
                dimensions.height = commonValues.getBufferedImg().getWidth();
            else {
                dimensions.width = commonValues.getBufferedImg().getWidth();
                dimensions.height = commonValues.getBufferedImg().getHeight();
            }
        }

        return dimensions;
    }

    private static float getScalingFromString(String numberValue) {
        float zoom = -1;
        if ((numberValue != null&& (!numberValue.isEmpty())) {

            //Remove the % that may be present when setting value manually
            if (numberValue.endsWith("%")) {
                numberValue = numberValue.substring(0, numberValue.length() 1);
            }

            try {
                zoom = Float.parseFloat(numberValue);
            catch (final NumberFormatException e) {

                LogWriter.writeLog("Exception in getting zoom " + e);

                //its got characters in it so get first valid number string
                final int length = numberValue.length();
                int ii = 0;
                while (ii < length) {
                    final char c = numberValue.charAt(ii);
                    if ((c >= '0' && c <= '9'|| c == '.') {
                        ii++;
                    else {
                        break;
                    }
                }

                if (ii > 0) {
                    numberValue = numberValue.substring(0, ii);
                }

                //try again if we reset above
                try {
                    zoom = Float.parseFloat(numberValue);
                catch (final NumberFormatException e1) {
                    LogWriter.writeLog("Exception in getting zoom " + e1);

                    zoom = -1;
                }
            }
            if (zoom > 1_000) {
                zoom = 1_000;
            }
        }

        return zoom;
    }

    private void setupScalingValue(final int index, float viewWidth, float viewHeight, final float contentWidth, final float contentHeight) {

        // [AWI]: Get the default width of scrollbars from the UI Manager
        int scrollbarWidth = 0;
        final Object scrollbarWidthObj = UIManager.get("ScrollBar.width");
        if (scrollbarWidthObj instanceof Integer) {
            scrollbarWidth = ((IntegerscrollbarWidthObj);
            if (scrollbarWidth < 0) {
                scrollbarWidth = 0;
            }
        }

        float x_factor, y_factor, window_factor = 1.0f;

        // [AWI]: Iterate over the scaling algorithm to try and take the scrollbar size into account.
        // This logic was added to address an issue with 'Fit Width' and 'Fit Height' calculations where the
        // scrollbar appeared as a result of the scaling, but the scrollbar was not taken into account in the
        // scaling algorithm. When this occurred, both scrollbars could appear, even though only one should.
        //
        // The loopCount is configured such that the scaling routine should be run at least once, but not more
        // than enough to make room for the scrollbar, to prevent an infinite loop.
        float scaledWidth, scaledHeight;
        int loopCount = 0;
        while (loopCount++ <= (scrollbarWidth)) {
            x_factor = viewWidth / contentWidth;
            y_factor = viewHeight / contentHeight;

            if (x_factor < y_factor) {
                window_factor = x_factor;
            else {
                window_factor = y_factor;
            }

            if (index != -1) {
                if (index < 3) { //handle scroll to width/height/window
                    switch (index) {
                        case 0:
                            scaling = window_factor;
                            break;
                        case 1:
                            scaling = y_factor;
                            break;
                        case 2:
                            scaling = x_factor;
                            break;
                    }

                    // [AWI]: Determine if the horizontal scrollbar will appear when set to 'Fit Height'
                    // or if the vertical scrollbar will appear when set to 'Fit Width' and if so, add the
                    // scrollbar size into the scaling algorithm and recalculate once.
                    scaledWidth = scaling * contentWidth;
                    scaledHeight = scaling * contentHeight;

                    if (index == && scaledWidth > viewWidth) { // height
                        viewHeight--;
                    else if (index == && scaledHeight > viewHeight) { // width
                        viewWidth--;
                    else {
                        // Break out to prevent multiple passes since scrollbars should not be displayed
                        break;
                    }
                else {
                    scaling = decode_pdf.getDPIFactory().adjustScaling(scalingFloatValues[index]);
                    // Break out to prevent multiple passes since scrollbars should not be displayed
                    break;
                }
            }
        }
        if (decode_pdf.getDisplayView() == Display.FACING) { // Enable turnover if both pages properly displayed
            pageTurnScalingAppropriate = scaling <= window_factor;
        }

        if (thumbscroll != null) {
            if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE && scaling <= window_factor) {

                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

                thumbscroll.setVisible(commonValues.getFileType() == Values.FileType.PDF);
            else {

                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

                thumbscroll.setVisible(false);
            }
        }
    }

    /**
     * Set scaling to nearest of the viewer default values.
     *
     @param newScaling The scaling value to snap to viewer default values
     */
    @Override
    public void snapScalingToDefaults(float newScaling) {
        newScaling = decode_pdf.getDPIFactory().adjustScaling(newScaling / 100);

        float width = scrollPane.getViewport().getWidth() - inset - inset;
        final float height = scrollPane.getViewport().getHeight() - inset - inset;

        final Dimension contentSize = getContentDimensions(commonValues.getCurrentPage());

        if (displayPane != null) {
            width -= displayPane.getDividerSize();
        }

        float x_factor;
        float y_factor;
        final float window_factor;
        x_factor = width / contentSize.width;
        y_factor = height / contentSize.height;

        if (x_factor < y_factor) {
            window_factor = x_factor;
            x_factor = -1;
        else {
            window_factor = y_factor;
            y_factor = -1;
        }

        if (getSelectedComboIndex(Commands.SCALING!= 0
                && ((newScaling < window_factor * 1.1 && newScaling > window_factor * 0.91)
                || ((window_factor > scaling && window_factor < newScaling|| (window_factor < scaling && window_factor > newScaling)))) {
            setSelectedComboIndex(Commands.SCALING, 0);
            scaling = window_factor;
        else if (y_factor != -1
                && getSelectedComboIndex(Commands.SCALING!= 1
                && ((newScaling < y_factor * 1.1 && newScaling > y_factor * 0.91)
                || ((y_factor > scaling && y_factor < newScaling|| (y_factor < scaling && y_factor > newScaling)))) {
            setSelectedComboIndex(Commands.SCALING, 1);
            scaling = y_factor;
        else if (x_factor != -1
                && getSelectedComboIndex(Commands.SCALING!= 2
                && ((newScaling < x_factor * 1.1 && newScaling > x_factor * 0.91)
                || ((x_factor > scaling && x_factor < newScaling|| (x_factor < scaling && x_factor > newScaling)))) {
            setSelectedComboIndex(Commands.SCALING, 2);
            scaling = x_factor;
        else {
            setSelectedComboItem(Commands.SCALING, String.valueOf((intdecode_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((StringgetSelectedComboItem(Commands.ROTATION));
        scaleAndRotate();
        ((JComponentdecode_pdf).updateUI();

    }

    /**
     * Scrolls the view to the specified page.
     *
     @param page Page to scroll to.
     */
    @Override
    public void scrollToPage(final int page) {

        commonValues.setCurrentPage(page);

        if (commonValues.getCurrentPage() 0) {

            int yCord = 0;
            final int xCord = 0;

            if (decode_pdf.getDisplayView() != Display.SINGLE_PAGE) {
                yCord = decode_pdf.getPages().getYCordForPage(page);
            }

            final PdfPageData pageData = decode_pdf.getPdfPageData();

            final int ch = (int) (pageData.getCropBoxHeight(commonValues.getCurrentPage()) * scaling);
            final int cw = (int) (pageData.getCropBoxWidth(commonValues.getCurrentPage()) * scaling);

            final int centerH = xCord + cw + ((cw - scrollPane.getViewport().getWidth()) 2);
            final int centerV = yCord + (ch - scrollPane.getViewport().getHeight()) 2;

            scrollPane.getHorizontalScrollBar().setValue(centerH);
            scrollPane.getVerticalScrollBar().setValue(centerV);
        }

        if (decode_pdf.getPageCount() 1) {
            swButtons.setPageLayoutButtonsEnabled(true);
        }

    }

    /**
     * Set the thumbnail panel ready for display.
     */
    @Override
    public void setupThumbnailPanel() {

        if (isSetup) {
            return;
        }

        isSetup = true;

        if (thumbnails.isShownOnscreen()) {

            final int pages = decode_pdf.getPageCount();

            //setup and add to display
            thumbnails.setupThumbnails(pages, textFont, decode_pdf.getPdfPageData());

            //add listener so clicking on button changes to page - has to be in Viewer so it can update it
            final Object[] buttons = thumbnails.getButtons();
            for (int i = 0; i < pages; i++) {
                ((AbstractButtonbuttons[i]).addActionListener(new SwingPageChanger(this, commonValues, i));
            }

            //add global listener
            thumbnails.addComponentListener();

        }
    }

    /**
     * Set the bookmarks for the outline panel
     *
     @param alwaysGenerate true we will generate the bookmarks, false we only generate bookmarks if not already generated
     */
    @Override
    public void setBookmarks(final boolean alwaysGenerate) {

        //Ignore if multiViewer or done it
        if ((bookmarksGenerated && !alwaysGenerate|| decode_pdf.isLoadingLinearizedPDF()) {
            return;
        }

        bookmarksGenerated = true;

        final org.w3c.dom.Document doc = decode_pdf.getOutlineAsXML();

        Node rootNode = null;
        if (doc != null) {
            rootNode = doc.getFirstChild();
        }

        if (rootNode != null) {

            tree.reset(rootNode);

            /*
             * Use a mouse listener instead of a TreeSelectionListener for 2 reasons
             * 1. Tree selection only works on new selections, Mouse clicks work on
             *    every click of the mouse.
             * 2. Tree nodes are highlighted before the mouse event, the mouse event
             *    can check the node that was highlighted by the tree and trigger it
             *    allowing highlighted bookmarks to be triggered again.
             *    We can also check if the mouse is within the node so it doesn't trigger
             *    if clicked in an empty area.
             */
            ((Componenttree.getTree()).addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(final MouseEvent e) {
                    final DefaultMutableTreeNode node = tree.getLastSelectedPathComponent();

                    final int[] selected = ((JTreetree.getTree()).getSelectionRows();
                    if (selected != null && selected.length != 0) {
                        final Rectangle r = ((JTreetree.getTree()).getRowBounds(selected[0]);

                        if (node == null || !r.contains(e.getX(), e.getY())) {
                            return;
                        }
                    }
                    triggerBookmark(node);
                }
            });

            /*
             * Navigate bookmarks using arrow keys,
             * left and right go to parent / child nodes,
             * enter key will trigger the currently selected node
             */
            ((Componenttree.getTree()).addKeyListener(new KeyAdapter() {

                @Override
                public void keyReleased(final KeyEvent e) {
                    if (e.getKeyCode() == '\n') {

                        final DefaultMutableTreeNode node = tree.getLastSelectedPathComponent();
                        if (node != null) {
                            triggerBookmark(node);
                        }
                    }
                }
            });

        else {
            tree.reset(null);
        }
    }

    private void triggerBookmark(final DefaultMutableTreeNode node) {

        final JTree jtree = ((JTreetree.getTree());

        final DefaultTreeModel treeModel = (DefaultTreeModeljtree.getModel();

        final java.util.List<TreeNode> flattenedTree = new ArrayList<>();

        //flatten out the tree so we can find the index of the selected node
        getFlattenedTreeNodes((TreeNodetreeModel.getRoot(), flattenedTree);
        flattenedTree.remove(0)// remove the root node as we don't account for this

        final int index = flattenedTree.indexOf(node);

        final String ref = tree.convertNodeIDToRef(index);

        final PdfObject Aobj = decode_pdf.getOutlineData().getAobj(ref);

        //handle in our handler code
        if (Aobj != null) {
            if (SwingUtilities.isEventDispatchThread()) {
                decode_pdf.getFormRenderer().getActionHandler().gotoDest(Aobj, ActionHandler.MOUSECLICKED, PdfDictionary.Dest);
            else {
                SwingUtilities.invokeLater(() -> decode_pdf.getFormRenderer().getActionHandler().gotoDest(Aobj, ActionHandler.MOUSECLICKED, PdfDictionary.Dest));
            }
        }
    }

    private void initStatus() {
        decode_pdf.setStatusBarObject(statusBar);

        //and initialise the display
        setMultibox(new int[]{});

    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#setCoordText(java.lang.String)
     */
    @Override
    public void setCoordText(final String string) {
        coords.setText(string);
    }

    private void initCoordBox() {

        coords.setBackground(Color.white);
        coords.setOpaque(true);

        coords.setBorder(BorderFactory.createEtchedBorder());
        coords.setPreferredSize(multibox.getPreferredSize());
        //Need to ensure the coords appear correctly in facing mode
        //incase coords have not been displayed before entering facing mode
        coords.setSize(multibox.getPreferredSize());

        coords.setText("  X: " " Y: " ' ' ' ');

    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#setPageNumber()
     */
    @Override
    public void setPageNumber() {

        if (SwingUtilities.isEventDispatchThread()) {
            setPageNumberWorker();
            if (isSetup) {
                //Page changed so save this page as last viewed
                setThumbnails();
            }
        else {
            final Runnable r = () -> {
                setPageNumberWorker();
                if (isSetup) {
                    //Page changed so save this page as last viewed
                    setThumbnails();
                }
            };
            SwingUtilities.invokeLater(r);
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#setPageNumber()
     */
    private void setPageNumberWorker() {

        if (pageCounter2 == null) {
            return;
        }

        if (!decode_pdf.isOpen() && !commonValues.isMultiTiff()) {
            pageCounter2.setText("0");
            pageCounter3.setText(Messages.getMessage("PdfViewerOfLabel.text"" 0");
        else {

            if (previewOnSingleScroll && thumbscroll != null) {
                thumbscroll.setMaximum(decode_pdf.getPageCount());
                thumbscroll.setValue(commonValues.getCurrentPage() 1);
            }

            final int currentPage = commonValues.getCurrentPage();
            if (decode_pdf.getDisplayView() == Display.FACING || decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING) {
                if (decode_pdf.getPageCount() == 2) {
                    pageCounter2.setText(getPageLabel(1'/' + getPageLabel(2));
                else if (decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER|| decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING) {
                    final int base = currentPage & -2;
                    if (base != decode_pdf.getPageCount() && base != 0) {
                        pageCounter2.setText(getPageLabel(base'/' + getPageLabel(base + 1));
                    else {
                        pageCounter2.setText(getPageLabel(currentPage));
                    }
                else {
                    final int base = currentPage - ((currentPage & 1));
                    if (base != decode_pdf.getPageCount()) {
                        pageCounter2.setText(getPageLabel(base'/' + getPageLabel(base + 1));
                    else {
                        pageCounter2.setText(getPageLabel(currentPage));
                    }
                }

            else {
                pageCounter2.setText(getPageLabel(currentPage));
            }

            if (pageLabelDiffers(currentPage)) {
                pageCounter3.setText("(" + currentPage + ' ' + Messages.getMessage("PdfViewerOfLabel.text"' ' + commonValues.getPageCount() ')')//$NON-NLS-1$
            else {
                pageCounter3.setText(Messages.getMessage("PdfViewerOfLabel.text"' ' + commonValues.getPageCount())//$NON-NLS-1$
            }

            swButtons.hideRedundentNavButtons(this);
        }
    }

    /**
     * note - to plugin put all on single line so addButton values over-ridden
     */
    private void createNavbar() {

        if (memoryMonitor == null) { //ensure only 1 instance
            memoryMonitor = new Timer(500, event -> {
                final int free = (int) (Runtime.getRuntime().freeMemory() (1_024 * 1_024));
                final int total = (int) (Runtime.getRuntime().totalMemory() (1_024 * 1_024));

                //this broke the image saving when it was run every time
                if (finishedDecoding) {
                    finishedDecoding = false;
                }

                //System.out.println((Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())/1000);
                memoryBar.setMaximum(total);
                memoryBar.setValue(total - free);
                memoryBar.setStringPainted(true);
                memoryBar.setString((total - free"M of " + total + 'M');
            });
            memoryMonitor.start();
        }

        multibox.setLayout(new BorderLayout());

        navButtons.add(multibox, BorderLayout.WEST);

        navButtons.add(Box.createHorizontalGlue());

        navToolBar.add(Box.createHorizontalGlue());

        swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.RewindToStart")"start.gif", Commands.FIRSTPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Rewind10")"fback.gif", Commands.FBACKPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Rewind1")"back.gif", Commands.BACKPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        pageCounter1 = new JLabel(Messages.getMessage("PdfViewerPageLabel.text"));
        pageCounter1.setOpaque(false);
        navToolBar.add(pageCounter1);
        navToolBar.add(pageCounter2);
        navToolBar.add(pageCounter3);

        swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Forward1")"forward.gif", Commands.FORWARDPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.Forward10")"fforward.gif", Commands.FFORWARDPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(NAVBAR, Messages.getMessage("PdfViewerNavBar.ForwardLast")"end.gif", Commands.LASTPAGE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        navToolBar.add(Box.createHorizontalGlue());

        swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.SinglePage")"single.gif", Commands.SINGLE, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.Continuous")"continuous.gif", Commands.CONTINUOUS, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.ContinousFacing")"continuous_facing.gif", Commands.CONTINUOUS_FACING, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.Facing")"facing.gif", Commands.FACING, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        swButtons.addButton(PAGES, Messages.getMessage("PageLayoutButton.PageFlow")"pageflow.gif", Commands.PAGEFLOW, menuItems, this, currentCommandListener, pagesToolBar, navToolBar);

        final Dimension size;

        navButtons.add(pagesToolBar, BorderLayout.EAST);


        size = pagesToolBar.getPreferredSize();

        multibox.setPreferredSize(size);

        navButtons.add(navToolBar, BorderLayout.CENTER);

    }

    /**
     * Set the interfaces page counter to the page number
     * and alter any other interface options to match.
     *
     @param page page number as an int
     */
    @Override
    public void setPage(int page) {

        if (((decode_pdf.getDisplayView() == Display.FACING && decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER))
                || decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING)
                && (page & 1== && page != 1) {
            page--;
        else if (decode_pdf.getDisplayView() == Display.FACING && !decode_pdf.getPages().getBoolean(Display.BoolValue.SEPARATE_COVER)
                && (page & 1== 0) {
            page--;
        }

        commonValues.setCurrentPage(page);
        setPageNumber();

    }

    /**
     * Method to set the viewers rotation from external sources.
     *
     @param rot The rotation to use in the Viewer
     */
    @Override
    public void setRotationFromExternal(final int rot) {
        rotation = rot;
        rotationBox.setSelectedIndex(rotation / 90);
        if (!Values.isProcessing()) {
            decode_pdf.repaint();
        }
    }

    /**
     * Method to set the viewers scaling from external sources.
     *
     @param scale The scaling to use in the Viewer as a String
     */
    @Override
    public void setScalingFromExternal(final String scale) {

        if (scale.startsWith("Fit ")) { //allow for Fit Page, Fit Width, Fit Height
            scalingBox.setSelectedItem(scale);
        else {
            scalingBox.setSelectedItem(scale + '%');
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#getFrame()
     */
    @Override
    public Container getFrame() {
        return frame;
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showMessageDialog(java.lang.Object)
     */
    @Override
    public void showMessageDialog(final String message1) {

        boolean showMessage = true;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            showMessage = customMessageHandler.showMessage(message1);
        }

        if (showMessage) {
            JOptionPane.showMessageDialog(frame, message1);
        }

    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showMessageDialog(java.lang.Object, java.lang.String, int)
     */
    @Override
    public void showMessageDialog(final Object message, final String title, final int type) {

        boolean showMessage = true;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            showMessage = customMessageHandler.showMessage(message);
        }

        if (showMessage) {
            JOptionPane.showMessageDialog(frame, message, title, type);
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showInputDialog(java.lang.Object, java.lang.String, int)
     */
    @Override
    public String showInputDialog(final Object message, final String title, final int type) {

        String returnMessage = null;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            returnMessage = customMessageHandler.requestInput(new Object[]{message, title, title});
        }

        if (returnMessage == null) {
            return JOptionPane.showInputDialog(frame, message, title, type);
        else {
            return returnMessage;
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showInputDialog(java.lang.String)
     */
    @Override
    public String showInputDialog(final String message) {

        String returnMessage = null;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            returnMessage = customMessageHandler.requestInput(new String[]{message});
        }

        if (returnMessage == null) {
            return JOptionPane.showInputDialog(frame, message);
        else {
            return returnMessage;
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showConfirmDialog(java.lang.String, java.lang.String, int)
     */
    @Override
    public int showConfirmDialog(final String message, final String message2, final int option) {

        int returnMessage = -1;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            returnMessage = customMessageHandler.requestConfirm(new Object[]{message, message2, String.valueOf(option)});
        }

        if (returnMessage == -1) {
            return JOptionPane.showConfirmDialog(frame, message, message2, option);
        else {
            return returnMessage;
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showOverwriteDialog(String file,boolean yesToAllPresent)
     */
    @Override
    public int showOverwriteDialog(final String file, final boolean yesToAllPresent) {

        final int n;

        int returnMessage = -1;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            returnMessage = customMessageHandler.requestConfirm(new Object[]{file, String.valueOf(yesToAllPresent)});
        }

        if (returnMessage != -1) {
            return returnMessage;
        }

        if (yesToAllPresent) {

            final Object[] buttonRowObjects = {
                    Messages.getMessage("PdfViewerConfirmButton.Yes"),
                    Messages.getMessage("PdfViewerConfirmButton.YesToAll"),
                    Messages.getMessage("PdfViewerConfirmButton.No"),
                    Messages.getMessage("PdfViewerConfirmButton.Cancel")
            };

            n = JOptionPane.showOptionDialog(frame,
                    file + '\n' + Messages.getMessage("PdfViewerMessage.FileAlreadyExists")
                            '\n' + Messages.getMessage("PdfViewerMessage.ConfirmResave"),
                    Messages.getMessage("PdfViewerMessage.Overwrite"),
                    JOptionPane.DEFAULT_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null,
                    buttonRowObjects,
                    buttonRowObjects[0]);

        else {
            n = JOptionPane.showOptionDialog(frame,
                    file + '\n' + Messages.getMessage("PdfViewerMessage.FileAlreadyExists")
                            '\n' + Messages.getMessage("PdfViewerMessage.ConfirmResave"),
                    Messages.getMessage("PdfViewerMessage.Overwrite"),
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null, null, null);
        }

        return n;
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showMessageDialog(javax.swing.JTextArea)
     */
    @Override
    public void showMessageDialog(final Object info) {

        boolean showMessage = true;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            showMessage = customMessageHandler.showMessage(info);
        }

        if (showMessage) {
            JOptionPane.showMessageDialog(frame, info);
        }

    }

    /**
     * Method used to show popups that are displayed the first time the Viewer is opened
     */
    @Override
    public void showFirstTimePopup() {

        //allow user to disable
        final boolean showMessage = (customMessageHandler != null && customMessageHandler.showMessage("first time popup"))
                || customMessageHandler == null;

        if (!showMessage || commonValues.getModeOfOperation() == Values.RUNNING_APPLET) {
            return;
        }

        try {
            final JPanel a = new JPanel();
            a.setLayout(new BoxLayout(a, BoxLayout.Y_AXIS));

            final MouseAdapter supportListener = new MouseAdapter() {
                @Override
                public void mouseEntered(final MouseEvent e) {
                    if (GUIDisplay.allowChangeCursor) {
                        a.setCursor(new Cursor(Cursor.HAND_CURSOR));
                    }
                }

                @Override
                public void mouseExited(final MouseEvent e) {
                    if (GUIDisplay.allowChangeCursor) {
                        a.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                    }
                }

                @Override
                public void mouseClicked(final MouseEvent e) {
                    try {
                        BrowserLauncher.openURL(Messages.getMessage("PdfViewer.SupportLink.Link"));
                    catch (final Exception e1) {
                        showMessageDialog(e1.getMessage() ' ' + Messages.getMessage("PdfViewer.ErrorWebsite"));
                    }
                }
            };

            final JLabel img = new JLabel(new ImageIcon(getClass().getResource("/org/jpedal/examples/viewer/res/supportScreenshot.png")));
            img.setBorder(BorderFactory.createRaisedBevelBorder());
            img.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            img.addMouseListener(supportListener);
            a.add(img);

            final JLabel supportLink = new JLabel("<html><center><u>" + Messages.getMessage("PdfViewer.SupportLink.Text1"' ' + Messages.getMessage("PdfViewer.SupportLink.Text2""</u></html>");
            supportLink.setMaximumSize(new Dimension(24560));
            supportLink.setForeground(Color.BLUE);
            supportLink.addMouseListener(supportListener);
            supportLink.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            a.add(supportLink);
            a.add(Box.createRigidArea(new Dimension(1010)));

            JOptionPane.showMessageDialog(
                    frame,
                    a,
                    Messages.getMessage("PdfViewerTitle.RunningFirstTime"),
                    JOptionPane.PLAIN_MESSAGE);
        catch (final Exception | Error e) {
            System.err.println(Messages.getMessage("PdfViewerFirstRunDialog.Error"' ' + e);
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#showConfirmDialog(java.lang.Object, java.lang.String, int, int)
     */
    @Override
    public int showConfirmDialog(final Object message, final String title, final int optionType, final int messageType) {

        int returnMessage = -1;

        //check user has not setup message and if we still show message
        if (customMessageHandler != null) {
            returnMessage = customMessageHandler.requestConfirm(new Object[]{message, title, String.valueOf(optionType), String.valueOf(messageType)});
        }

        if (returnMessage == -1) {
            return JOptionPane.showConfirmDialog(frame, message, title, optionType, messageType);
        else {
            return returnMessage;
        }
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#updateStatusMessage(java.lang.String)
     */
    @Override
    public void setDownloadProgress(final String message, final int percentage) {
        downloadBar.setProgress(message, percentage);

        setMultibox(new int[]{});
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#updateStatusMessage(java.lang.String)
     */
    @Override
    public void updateStatusMessage(final String message) {
        statusBar.updateStatus(message, 0);
    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#resetStatusMessage(java.lang.String)
     */
    @Override
    public void resetStatusMessage(final String message) {
        statusBar.resetStatus(message);

    }

    /* (non-Javadoc)
     * @see org.jpedal.examples.viewer.gui.swing.GUIFactory#setStatusProgress(int)
     */
    @Override
    public void setStatusProgress(final int size) {
        statusBar.setProgress(size);

        setMultibox(new int[]{});
    }

    /**
     * Gets the current divider location for the split pane
     *
     @return int values representing the current divider location
     */
    @Override
    public int getSplitDividerLocation() {
        return displayPane.getDividerLocation();
    }

    /**
     * Get the print dialog.
     *
     @param printersList   String array of all available printers
     @param defaultPrinter String representing the default printer
     @return an Object for the print dialog.
     */
    @Override
    public Object printDialog(final String[] printersList, final String defaultPrinter) {

        final JDialog printDialog = new JDialog((Framenull, Messages.getMessage("PdfViewerLabel.Printer")true);
        printDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        //get default resolution
        String propValue = properties.getValue("defaultDPI");
        int defaultDPI = -1;
        if (propValue != null && !propValue.isEmpty()) {
            try {
                propValue = propValue.replaceAll("[^0-9]""");
                defaultDPI = Integer.parseInt(propValue);
            catch (final NumberFormatException e) {
                LogWriter.writeLog("Caught an Exception " + e);
            }
        }

        if (printPanel == null) {
            printPanel = new PrintPanel(printersList, defaultPrinter, getPaperSizes(), defaultDPI, commonValues.getCurrentPage(), decode_pdf);
        else {
            printPanel.resetDefaults(printersList, defaultPrinter, commonValues.getPageCount(), commonValues.getCurrentPage());
        }

        printDialog.getContentPane().add(printPanel);

        printDialog.setSize(670415);
        printDialog.setResizable(false);
        printDialog.setLocationRelativeTo(frame);
        printDialog.setName("printDialog");
        printDialog.setVisible(true);

        printDialog.remove(printPanel);

        return printPanel;
    }

    /**
     * Gets the paper sizes for use by the print dialog
     *
     @return a PaperSizes object holding all paper sizes
     */
    @Override
    public PaperSizes getPaperSizes() {
        if (paperSizes == null) {
            paperSizes = new PaperSizes(properties.getValue("defaultPagesize"));
        }
        return paperSizes;
    }

    private void setThumbnails() {
        final org.jpedal.utils.SwingWorker worker = new org.jpedal.utils.SwingWorker() {
            @Override
            public Object construct() {

                if (thumbnails.isShownOnscreen()) {
                    setupThumbnailPanel();

                    thumbnails.generateOtherVisibleThumbnails(commonValues.getCurrentPage());
                }

                return null;
            }
        };
        worker.start();
    }

    /**
     * Set the search text field to be used for the menu bar search input
     *
     @param searchText A JTextField to be used for search input
     */
    @Override
    public void setSearchText(final Object searchText) {
        this.searchText = (JTextFieldsearchText;
    }

    /**
     * Set the search list to be used to hold search results in menu bar search mode
     *
     @param results an implementation of GUISearchList
     */
    @Override
    public void setResults(final GUISearchList results) {

        if (searchInMenu && results.getResultCount() == 0) {
            showMessageDialog(Messages.getMessage("PdfViewerFileMenuFind.noResultText"" \"" + results.getSearchTerm() '"', Messages.getMessage("PdfViewerFileMenuFind.noResultTitle"), JOptionPane.INFORMATION_MESSAGE);
        }
    }

    /**
     * Get the JTabbedPane, as an Object, used for the side tab bar
     *
     @return JTabbedPane used for the side tab bar
     */
    @Override
    public Object getSideTabBar() {
        return navOptionsPanel;
    }

    private void enableSearchItems(final boolean enabled) {
        if (searchInMenu) { //Menu Bar search
            searchText.setEnabled(enabled);
            options.setEnabled(enabled);
            swButtons.getButton(Commands.NEXTRESULT).setEnabled(false);
            swButtons.getButton(Commands.PREVIOUSRESULT).setEnabled(false);
        else if (swButtons.getButton(Commands.FIND!= null) { //External Window search
            swButtons.getButton(Commands.FIND).setEnabled(enabled);
        }
    }

    /**
     * Removes the search window from view with option to clear search results
     *
     */
    private void removeSearchWindow() {
        searchFrame.removeSearchWindow(false);
    }

    /**
     * Alter property using properties files keys and values to alter the user interface
     *
     @param value String representation of the property key
     @param set   true to turn on option, false to turn off
     */
    @Override
    public void alterProperty(final String value, final boolean set) {
        GUIModifier.alterProperty(value, set, this);
    }

    /**
     * Method to dispose of objects used by the interface before closing.
     */
    @Override
    public void dispose() {

        for (final AWTEventListener listener : Toolkit.getDefaultToolkit().getAWTEventListeners()) {
            Toolkit.getDefaultToolkit().removeAWTEventListener(listener);
        }

        for (final ComponentListener listener : frame.getComponentListeners()) {
            frame.removeComponentListener(listener);
        }

        if (options != null) {
            for (final ItemListener listener : options.getItemListeners()) {
                options.removeItemListener(listener);
            }
        }
        if (menu != null) {
            for (final PopupMenuListener listener : menu.getPopupMenuListeners()) {
                menu.removePopupMenuListener(listener);
            }
            menu.removeAll();
        }

        thumbnails.removeAllListeners();
        thumbnails.dispose();

        if (scrollListener != null) {
            scrollListener.dispose();
        }

        mouseHandler.dispose();

        if (navButtons != null) {
            navButtons.removeAll();
        }

        menuItems.dispose();

        if (coords != null) {
            coords.removeAll();
        }

        if (desktopPane != null) {
            disposeDesktopPane(desktopPane);
        }

        if (navOptionsPanel != null) {
            disposeNavOptions(navOptionsPanel);
        }

        if (thumbscroll != null) {
            disposeThumbnailScroll(thumbscroll);
        }

        if (scrollPane != null) {
            disposeScrollPane(scrollPane);
        }

        if (signaturesTree != null) {
            signaturesTree.setCellRenderer(null);
            signaturesTree.removeAll();
        }

        if (layersPanel != null) {
            layersPanel.removeAll();
        }

        if (annotationsPanel != null) {
            annotationsPanel.dispose();
        }


        searchFrame.dispose();

        if (navToolBar != null) {
            disposeNavToolBar(navToolBar);
        }

        if (pagesToolBar != null) {
            disposePageToolBar(pagesToolBar);
        }

        //release memory at end
        if (memoryMonitor != null) {
            disposeMemoryMonitor();
        }

        //Ensure Timer is closed as does not use daemon thread
        if (viewListener != null) {
            viewListener.dispose();
        }

        //Below line causes a NullPointerException
        removeSearchWindow();

        swButtons.dispose();

        //display pane cleanup
        if (displayPane != null) {
            disposeDisplayPane();
        }

        if (attachmentsPanel != null) {
            attachmentsPanel.dispose();
            attachmentsPanel = null;
        }

        final JTree disposeTree = (JTreetree.getTree();
        if (disposeTree != null) {
            disposeTree(disposeTree);
        }
        removePageListener();

        removeGUIListeners((Componentdecode_pdf);

        if (glassPane != null) {
            removeGUIListeners(glassPane);
            glassPane.removeAll();
        }

        disposeFrame();

        if (lpane != null) {
            for (final PropertyChangeListener listener : lpane.getPropertyChangeListeners()) {
                lpane.removePropertyChangeListener(listener);
            }
            for (final ComponentListener listener : lpane.getComponentListeners()) {
                lpane.removeComponentListener(listener);
            }
            lpane.removeAll();
        }

        if (containerForThumbnails != null) {
            for (final PropertyChangeListener listener : containerForThumbnails.getPropertyChangeListeners()) {
                containerForThumbnails.removePropertyChangeListener(listener);
            }
            containerForThumbnails.removeAll();
        }

        if (frame != null) {
            frame.removeAll();
        }

        decode_pdf.closePdfFile();
        decode_pdf.dispose();
        ((Containerdecode_pdf).removeAll();

        setGlobalVariablesToNull();

        super.dispose();
    }

    private void setGlobalVariablesToNull() {
        options = null;
        menu = null;
        scrollListener = null;
        mouseHandler = null;
        pageTitle = null;
        bookmarksTitle = null;
        signaturesTitle = null;
        layersTitle = null;
        annotationTitle = null;
        attachmentsTitle = null;
        currentCommandListener = null;
        navButtons = null;
        coords = null;
        desktopPane = null;
        navOptionsPanel = null;
        thumbscroll = null;
        scrollPane = null;
        //headFont = null;
        textFont = null;
        statusBar = null;
        downloadBar = null;
        pageCounter2 = null;
        pageCounter3 = null;
        signaturesTree = null;
        layersPanel = null;
        annotationsPanel = null;
        searchFrame = null;
        navToolBar = null;
        pagesToolBar = null;
        layersObject = null;
        viewListener = null;
        glassPane = null;
        frame = null;
        portfolioParent = null;
        decode_pdf = null;
    }

    private static void disposePageToolBar(final JToolBar toolBar) {
        for (final MouseListener listener : toolBar.getMouseListeners()) {
            toolBar.removeMouseListener(listener);
        }
        for (final MouseMotionListener listener : toolBar.getMouseMotionListeners()) {
            toolBar.removeMouseMotionListener(listener);
        }
        toolBar.removeAll();
    }

    private static void disposeNavToolBar(final JToolBar navBar) {
        final Component[] comps = navBar.getComponents();
        for (final Component comp : comps) {
            for (final PropertyChangeListener listener : comp.getPropertyChangeListeners()) {
                comp.removePropertyChangeListener(listener);
            }
            for (final ComponentListener listener : comp.getComponentListeners()) {
                comp.removeComponentListener(listener);
            }
        }
        navBar.removeAll();
    }

    private static void disposeScrollPane(final JScrollPane scrollPane) {
        for (final PropertyChangeListener listener : scrollPane.getPropertyChangeListeners()) {
            scrollPane.removePropertyChangeListener(listener);
        }
        for (final MouseWheelListener listener : scrollPane.getMouseWheelListeners()) {
            scrollPane.removeMouseWheelListener(listener);
        }
        for (final MouseMotionListener listener : scrollPane.getMouseMotionListeners()) {
            scrollPane.removeMouseMotionListener(listener);
        }
        for (final FocusListener listener : scrollPane.getFocusListeners()) {
            scrollPane.removeFocusListener(listener);
        }
        scrollPane.removeAll();
    }

    private static void disposeNavOptions(final JTabbedPane navOptions) {
        for (final MouseListener listener : navOptions.getMouseListeners()) {
            navOptions.removeMouseListener(listener);
        }
        for (final ChangeListener listener : navOptions.getChangeListeners()) {
            navOptions.removeChangeListener(listener);
        }
        navOptions.removeAll();
    }

    private static void disposeThumbnailScroll(final JScrollBar thumbnailScroll) {
        for (final MouseListener listener : thumbnailScroll.getMouseListeners()) {
            thumbnailScroll.removeMouseListener(listener);
        }
        for (final PropertyChangeListener listener : thumbnailScroll.getPropertyChangeListeners()) {
            thumbnailScroll.removePropertyChangeListener(listener);
        }
        thumbnailScroll.removeAll();
    }

    private static void disposeDesktopPane(final JDesktopPane desktop) {
        for (final PropertyChangeListener listener : desktop.getPropertyChangeListeners()) {
            desktop.removePropertyChangeListener(listener);
        }
        for (final MouseListener listener : desktop.getMouseListeners()) {
            desktop.removeMouseListener(listener);
        }
        for (final ComponentListener listener : desktop.getComponentListeners()) {
            desktop.removeComponentListener(listener);
        }
        desktop.removeAll();
    }

    private void disposeMemoryMonitor() {
        memoryMonitor.stop();
        final ActionListener[] al = memoryMonitor.getActionListeners();
        for (int i = 0; i != al.length; i++) {
            memoryMonitor.removeActionListener(al[i]);
        }
    }

    private void disposeFrame() {
        if (frame instanceof JFrame) {
            final JFrame disposeFrame = (JFrameframe;
            for (final ComponentListener listener : disposeFrame.getComponentListeners()) {
                disposeFrame.removeComponentListener(listener);
            }
        else {
            frame.add(desktopPane, BorderLayout.CENTER);
            final Component disposeComp = frame;
            for (final ComponentListener listener : disposeComp.getComponentListeners()) {
                disposeComp.removeComponentListener(listener);
            }
        }
    }

    private static void removeGUIListeners(final Component comp) {
        for (final KeyListener listener : comp.getKeyListeners()) {
            comp.removeKeyListener(listener);
        }

        for (final MouseListener listener : comp.getMouseListeners()) {
            comp.removeMouseListener(listener);
        }

        for (final MouseWheelListener listener : comp.getMouseWheelListeners()) {
            comp.removeMouseWheelListener(listener);
        }

        for (final MouseMotionListener listener : comp.getMouseMotionListeners()) {
            comp.removeMouseMotionListener(listener);
        }
    }

    private static void disposeTree(final JTree disposeTree) {
        for (final MouseListener listener : disposeTree.getMouseListeners()) {
            disposeTree.removeMouseListener(listener);
        }
        for (final KeyListener listener : disposeTree.getKeyListeners()) {
            disposeTree.removeKeyListener(listener);
        }
        disposeTree.removeAll();
    }

    private void disposeDisplayPane() {
        for (final PropertyChangeListener listener : displayPane.getPropertyChangeListeners()) {
            displayPane.removePropertyChangeListener(listener);
        }
        for (final MouseListener listener : displayPane.getMouseListeners()) {
            displayPane.removeMouseListener(listener);
        }
        for (final ComponentListener listener : displayPane.getComponentListeners()) {
            displayPane.removeComponentListener(listener);
        }
        displayPane.removeAll();
    }

    /**
     * Not part of API - used internally
     */
    @Override
    public boolean getPageTurnScalingAppropriate() {
        return pageTurnScalingAppropriate;
    }

    /**
     * Not part of API - used internally
     */
    @Override
    public SwingCursor getGUICursor() {
        return guiCursor;
    }

    /**
     * Checks if title matches the title of any of the side tab bar tabs
     *
     @param title String title to check for.
     @return String title of tab found.
     */
    @Override
    public String getTitles(final String title) {
        if (title.equals(pageTitle)) {
            return pageTitle;
        else if (title.equals(bookmarksTitle)) {
            return bookmarksTitle;
        else if (title.equals(signaturesTitle)) {
            return signaturesTitle;
        else if (title.equals(layersTitle)) {
            return layersTitle;
        else if (title.equals(annotationTitle)) {
            return annotationTitle;
        else if (title.equals(attachmentsTitle)) {
            return attachmentsTitle;
        }
        return null;
    }

    /**
     * Get StatusBar used in the multi box
     *
     @return StatusBar object
     */
    @Override
    public StatusBar getStatusBar() {
        return statusBar;
    }

    /**
     * Get the GUIButtons object that holds all buttons used by the user interface
     *
     @return GUIButtons implementation used by the user interface
     */
    @Override
    public GUIButtons getButtons() {
        return swButtons;
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    @Override
    protected void setViewerIcon() {

        if (frame instanceof JFrame) {

            //Check if file location provided
            final URL path = guiCursor.getURLForImage("icon.png");
            if (path != null) {
                try {
                    final BufferedImage fontIcon = ImageIO.read(path);
                    ((Windowframe).setIconImage(fontIcon);
                catch (final IOException e) {
                    LogWriter.writeLog("Exception attempting to set icon " + e);
                }
            }
        }

    }

    /**
     * Get the GUIMenuItems object that holds all the menu items used by the user interface.
     *
     @return GUIMenuItems implementation used by the user interface
     */
    @Override
    public GUIMenuItems getMenuItems() {
        return menuItems;
    }

    /**
     * Set tabs not initialised flag to prevent use of tabs.
     *
     @param b true to mark the tabs as not initialised, false to mark as initialised
     */
    @Override
    public void setTabsNotInitialised(final boolean b) {
        tabsNotInitialised = b;
    }

    /**
     * Key method that calls decodePage from GUI.java
     */
    @Override
    public void decodePage() {

        if (SwingAnnotationPanel.addPanel()) {
            ((SwingMouseAnnotationsgetAnnotationPanel().getAnnotationListener()).setFormMode(GUIAnnotationPanel.FORMMODE.CREATION);
        }

        //Ensure thumbnail scroll bar is updated when page changed
        if (thumbscroll != null) {
            setThumbnailScrollBarValue(commonValues.getCurrentPage() 1);
        }
        decodeGUIPage(this);

    }

    /**
     * Get the PdfDecoder object used to display the PDF in the user interface
     *
     @return PdfDecoder object used for display
     */
    @Override
    public PdfDecoder getPdfDecoder() {
        return ((PdfDecoderdecode_pdf);
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    @Override
    protected void addComboListenerAndLabel(final GUICombo combo) {
        //add listener
        ((JComboBox<String>combo).addActionListener((ActionListenercurrentCommandListener.getCommandListener());
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    @Override
    protected void addGUIComboBoxes(final GUICombo combo) {
        swButtons.getTopButtons().add((Componentcombo);
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    private void setupCenterPanelBackground() {
        String propValue = properties.getValue("replacePdfDisplayBackground");
        Color background = new Color(190190190);
        if (!propValue.isEmpty()
                && propValue.equalsIgnoreCase("true")) {
            propValue = properties.getValue("pdfDisplayBackground");
            if (!propValue.isEmpty()) {
                currentCommands.executeCommand(Commands.SETDISPLAYBACKGROUND, new Object[]{Integer.parseInt(propValue)});
            }
            background = new Color(Integer.parseInt(propValue));

        else {
            if (decode_pdf.getDecoderOptions().getDisplayBackgroundColor() != null) {
                background = decode_pdf.getDecoderOptions().getDisplayBackgroundColor();
            else if (decode_pdf.useNewGraphicsMode()) {
                background = new Color(555565);
            }
        }

        ((Componentdecode_pdf).setBackground(background);
        frame.setBackground(background);
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    private void setupComboBoxes() {

        final String[] rotationValues = {"0""90""180""270"};

        final String[] scalingValues = {Messages.getMessage("PdfViewerScaleWindow.text"), Messages.getMessage("PdfViewerScaleHeight.text"),
                Messages.getMessage("PdfViewerScaleWidth.text"),
                "25%""50%""75%""100%""125%""150%""200%""250%""500%""750%""1000%"};

        //set new default if appropriate
        String choosenScaling = System.getProperty("org.jpedal.defaultViewerScaling");

        //Only use value from properties is VM arguement not set
        if (choosenScaling == null) {
            choosenScaling = properties.getValue("startScaling");
        }

        if (choosenScaling != null) {
            final int total = scalingValues.length;
            for (int aa = 0; aa < total; aa++) {
                if (scalingValues[aa].equals(choosenScaling)) {
                    defaultSelection = aa;
                    aa = total;
                }
            }
        }

        scalingBox = new SwingCombo(scalingValues);
        ((ComponentscalingBox).setBackground(Color.white);
        scalingBox.setEditable(true);
        scalingBox.setSelectedIndex(defaultSelection)//set default before we add a listener

        //if you enable, remember to change rotation and quality Comboboxes
        rotationBox = new SwingCombo(rotationValues);
        ((ComponentrotationBox).setBackground(Color.white);
        rotationBox.setSelectedIndex(0)//set default before we add a listener
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    private void setupKeyboardControl() {
        ((Componentdecode_pdf).addKeyListener(new KeyAdapter() {
            int count;
            int pageChange;
            java.util.Timer t2;

            @Override
            public void keyPressed(final KeyEvent e) {
                final JScrollBar scroll = scrollPane.getVerticalScrollBar();

                final int keyPressed = e.getKeyCode();

                if (keyPressed == KeyEvent.VK_LEFT || keyPressed == KeyEvent.VK_RIGHT) {

                    //Only use left and right arrows to change pages if page is smaller than display area
                    if (scrollPane.getWidth() ((Componentdecode_pdf).getWidth()) {
                        if (keyPressed == KeyEvent.VK_LEFT) { //change page
                            pageChange--;
                        else //change page
                            pageChange++;
                        }

                    }

                else if ((keyPressed == KeyEvent.VK_UP || keyPressed == KeyEvent.VK_DOWN&& (count == 0)) {
                    if (keyPressed == KeyEvent.VK_UP
                            && scroll.getValue() == scroll.getMinimum()
                            && commonValues.getCurrentPage() 1) {

                        //change page
                        pageChange--;

                    else if (keyPressed == KeyEvent.VK_DOWN
                            && (scroll.getValue() == scroll.getMaximum() - scroll.getHeight() || scroll.getHeight() == 0)
                            && commonValues.getCurrentPage() < decode_pdf.getPageCount()) {

                        //change page
                        pageChange++;

                    }
                }

                count++;

                if (pageChange != 0) {
                    if (t2 != null) {
                        t2.cancel();
                    }

                    final TimerTask t = new TimerTask() {

                        @Override
                        public void run() {

                            int p = (commonValues.getCurrentPage() + pageChange);

                            if (p < 1) {
                                p = 1;
                            else if (p > decode_pdf.getPageCount()) {
                                p = decode_pdf.getPageCount();
                            }

                            if (p != commonValues.getCurrentPage()) {
                                final String page = String.valueOf(p);

                                SwingUtilities.invokeLater(() -> {
                                    currentCommands.executeCommand(Commands.GOTO, new Object[]{page});

                                    if (scroll.getValue() == scroll.getMinimum()
                                            && commonValues.getCurrentPage() 1) {

                                        scroll.setValue(scroll.getMaximum());

                                    else if ((scroll.getValue() == scroll.getMaximum() - scroll.getHeight() || scroll.getHeight() == 0)
                                            && commonValues.getCurrentPage() < decode_pdf.getPageCount()) {

                                        scroll.setValue(scroll.getMinimum());
                                    }
                                });

                            }
                            pageChange = 0;

                            //Add cancel for the timer at the end of this task.
                            //This should ensure the timer is not kept active
                            if (t2 != null) {
                                t2.cancel();
                            }
                        }
                    };

                    //restart - if its not stopped it will trigger page update
                    t2 = new java.util.Timer();
                    t2.schedule(t, 500);
                }
            }

            @Override
            public void keyReleased(final KeyEvent e) {
                count = 0;
            }
        });
    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    private void setupPDFDisplayPane() {

        if (SwingAnnotationPanel.addPanel()) {
            glassPane = new JPanel();
            glassPane.setLayout(null);
            glassPane.setOpaque(false);

            lpane.add(scrollPane, 00);
            lpane.add(glassPane, 11);
        }

        previewOnSingleScroll = properties.getValue("previewOnSingleScroll").equalsIgnoreCase("true");
        if (previewOnSingleScroll) {
            thumbscroll = new JScrollBar(JScrollBar.VERTICAL, 0101);
            thumbscroll.setName("ThumbnailScroll");
            if (scrollListener == null) {
                scrollListener = new SwingScrollListener(this);
            }
            thumbscroll.addAdjustmentListener(scrollListener);
            thumbscroll.addMouseListener(scrollListener);

            containerForThumbnails.setLayout(new BorderLayout());
            containerForThumbnails.add(thumbscroll, BorderLayout.EAST);
            scrollPane.getViewport().add(((Componentdecode_pdf));
            if (SwingAnnotationPanel.addPanel()) {
                containerForThumbnails.add(lpane, BorderLayout.CENTER);
            else {
                containerForThumbnails.add(scrollPane, BorderLayout.CENTER);
            }

            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
            scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        else {
            scrollPane.getViewport().add(((Componentdecode_pdf));

            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
            scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        }

        scrollPane.getVerticalScrollBar().setUnitIncrement(80);
        scrollPane.getHorizontalScrollBar().setUnitIncrement(80);

        //Keyboard control of next/previous page
        setupKeyboardControl();

    }

    /**
     * Overrides method from GUI.java, see GUI.java for DOCS.
     */
    private void setupBorderPanes() {

        //Create a left-right split pane with tabs and add to main display
        navOptionsPanel.setTabPlacement(JTabbedPane.LEFT);
        navOptionsPanel.setOpaque(true);
        //Use start size as min width to keep divider from covering tabs
        navOptionsPanel.setMinimumSize(new Dimension(collapsedSize, 100));
        navOptionsPanel.setName("NavPanel");
        navOptionsPanel.setFocusable(false);

        setupSidebarTitles();

        if (previewOnSingleScroll) {
            displayPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, navOptionsPanel, containerForThumbnails);
        else {
            if (SwingAnnotationPanel.addPanel()) {
                displayPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, navOptionsPanel, lpane);
            else {
                displayPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, navOptionsPanel, scrollPane);
            }
        }

        displayPane.setOneTouchExpandable(false);

        //update scaling when divider moved
        displayPane.addPropertyChangeListener("dividerLocation", e -> {

            //hack to get it to use current values instead of old values
            scrollPane.getViewport().setSize((scrollPane.getViewport().getWidth() (Integere.getOldValue() (Integere.getNewValue()),
                    scrollPane.getViewport().getHeight());

            desktopPane.setSize((desktopPane.getWidth() (Integere.getOldValue() (Integere.getNewValue()),
                    desktopPane.getHeight());

            //Keep track of the current divider position
            final int dividerPos = (Integere.getNewValue();

            if (tabsExpanded && (dividerPos > collapsedSize)) {
                expandedSize = dividerPos;
            }

            scaleAndRotate();

        });

        if (DecoderOptions.isRunningOnMac) {
            navOptionsPanel.addTab(pageTitle, (Componentthumbnails);
            navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() 1, pageTitle);

            if (thumbnails.isShownOnscreen()) {
                navOptionsPanel.addTab(bookmarksTitle, (Componenttree);
                navOptionsPanel.setTitleAt(navOptionsPanel.getTabCount() 1, bookmarksTitle);
            }

        else {

            //Remove borders from thumbnail and bookmark tab in windows as looks better
            ((JComponenttree).setBorder(null);
            ((JComponentthumbnails).setBorder(null);

            if (thumbnails.isShownOnscreen()) {
                final VTextIcon textIcon1 = new VTextIcon(navOptionsPanel, pageTitle);
                navOptionsPanel.addTab(null, textIcon1, (Componentthumbnails);
            }

            final VTextIcon textIcon2 = new VTextIcon(navOptionsPanel, bookmarksTitle);
            navOptionsPanel.addTab(null, textIcon2, (Componenttree);

        }

        String propValue = properties.getValue("startSideTabOpen");
        if (!propValue.isEmpty()) {
            sideTabBarOpenByDefault = propValue.equalsIgnoreCase("true");
        }

        propValue = properties.getValue("startSelectedSideTab");
        if (!propValue.isEmpty()) {
            startSelectedTab = propValue;
        }

        if (!hasListener) {
            hasListener = true;
            navOptionsPanel.addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(final MouseEvent mouseEvent) {
                    handleTabbedPanes();
                }
            });
        }

    }

    /**
     * Sets up the position and visual style of the items on the bottom toolbar
     * (page navigation buttons etc).
     */
    private void setupBottomToolBarItems() {

        pageCounter2.setEditable(true);
        pageCounter2.setToolTipText(Messages.getMessage("PdfViewerTooltip.goto"));
        pageCounter2.setBorder(
                BorderFactory.createCompoundBorder(
                        BorderFactory.createEmptyBorder(1111),
                        pageCounter2.getBorder()));
        pageCounter2.setColumns(2);
        pageCounter2.setMaximumSize(pageCounter2.getPreferredSize());

        pageCounter2.addActionListener(arg0 -> {

            String value = pageCounter2.getText().trim();

            //Check if mapped and if so set the actual page number
            //This is updated later to the correct page label
            final PdfObjectReader reader = decode_pdf.getIO();
            if (reader != null) {
                final PageLabels pageLabels = reader.getPageLabels();
                if (pageLabels != null && pageLabels.containsValue(value)) {
                    final Set<Map.Entry<Integer, String>> entries = pageLabels.entrySet();
                    for (final Map.Entry<Integer, String> e : entries) {
                        if (e.getValue().equals(value)) {
                            value = e.getKey().toString();
                            break;
                        }
                    }
                }
            }
            currentCommands.executeCommand(Commands.GOTO, new Object[]{value});
        });
        pageCounter2.setHorizontalAlignment(JTextField.CENTER);
        pageCounter2.setForeground(Color.black);
        setPageNumber();

        pageCounter3 = new JLabel(Messages.getMessage("PdfViewerOfLabel.text"' ');
        pageCounter3.setOpaque(false);

        navToolBar.setLayout(new BoxLayout(navToolBar, BoxLayout.LINE_AXIS));
        navToolBar.setFloatable(false);

        pagesToolBar.setFloatable(false);

        navButtons.setBorder(BorderFactory.createEmptyBorder());
        navButtons.setLayout(new BorderLayout());
        navButtons.setFloatable(false);
        navButtons.setPreferredSize(new Dimension(524));
    }

    /**
     * Creates a glowing border around the PDFDisplayPane.
     */
    private void setupPDFBorder() {
        //add a border
        if (decode_pdf.useNewGraphicsMode()) {
            decode_pdf.setPDFBorder(new AbstractBorder() {

                @Override
                public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
                    final Graphics2D g2 = (Graphics2Dg;

                    final int cornerDepth = (glowThickness / 21;

                    //left
                    g2.setPaint(new GradientPaint(x, 0, glowOuterColor, x + glowThickness, 0, glowInnerColor));
                    g2.fillRect(x, y + glowThickness, glowThickness, height - (glowThickness * 2));

                    //bottom left corner
                    g2.setPaint(new GradientPaint(x - cornerDepth + glowThickness, y + height + cornerDepth - glowThickness, glowOuterColor, x + glowThickness, y + height - glowThickness, glowInnerColor));
                    g2.fillRect(x, y + height - glowThickness, glowThickness, glowThickness);

                    //below
                    g2.setPaint(new GradientPaint(0, y + height, glowOuterColor, 0, y + height - glowThickness, glowInnerColor));
                    g2.fillRect(x + glowThickness, y + height - glowThickness, width - (glowThickness * 2), glowThickness);

                    //bottom right corner
                    g2.setPaint(new GradientPaint(x + width + cornerDepth - glowThickness, y + height + cornerDepth - glowThickness, glowOuterColor, x + width - glowThickness, y + height - glowThickness, glowInnerColor));
                    g2.fillRect(x + width - glowThickness, y + height - glowThickness, glowThickness, glowThickness);

                    //right
                    g2.setPaint(new GradientPaint(x + width, 0, glowOuterColor, x + width - glowThickness, 0, glowInnerColor));
                    g2.fillRect(x + width - glowThickness, y + glowThickness, glowThickness, height - (glowThickness * 2));

                    //top right corner
                    g2.setPaint(new GradientPaint(x + width - glowThickness + cornerDepth, y + glowThickness - cornerDepth, glowOuterColor, x + width - glowThickness, y + glowThickness, glowInnerColor));
                    g2.fillRect(x + width - glowThickness, y, glowThickness, glowThickness);

                    //above
                    g2.setPaint(new GradientPaint(0, y, glowOuterColor, 0, y + glowThickness, glowInnerColor));
                    g2.fillRect(x + glowThickness, y, width - (glowThickness * 2), glowThickness);

                    //top left corner
                    g2.setPaint(new GradientPaint(x - cornerDepth + glowThickness, y - cornerDepth + glowThickness, glowOuterColor, x + glowThickness, y + glowThickness, glowInnerColor));
                    g2.fillRect(x, y, glowThickness, glowThickness);

                    //draw black over top
                    g2.setPaint(Color.black);
                    g2.drawRect(x + glowThickness, y + glowThickness, width - (glowThickness * 2), height - (glowThickness * 2));

                }

                @Override
                public Insets getBorderInsets(final Component c, final Insets insets) {
                    insets.set(glowThickness, glowThickness, glowThickness, glowThickness);
                    return insets;
                }
            });

        else {
            decode_pdf.setPDFBorder(BorderFactory.createLineBorder(Color.black, 1));
        }

    }

    /**
     * Creates the top two menu bars, the file loading and viewer properties one
     * and the PDF toolbar, the one which controls printing, searching etc.
     */
    private void createTopMenuBar() {
        top.setLayout(new BorderLayout());
        if (frame instanceof JFrame) {
            ((RootPaneContainerframe).getContentPane().add(top, BorderLayout.NORTH);
        else {
            frame.add(top, BorderLayout.NORTH);
        }
    }

    /**
     * Ensure Document is redrawn when frame is resized and scaling set to
     * width, height or window.
     */
    private void redrawDocumentOnResize() {
        frame.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(final ComponentEvent e) {
                if (((Componentdecode_pdf).getParent() != null
                        && (getSelectedComboIndex(Commands.SCALING|| decode_pdf.getDisplayView() == Display.FACING)) { //always rezoom in facing mode for turnover
                    scaleAndRotate();
                }
            }
        });
    }

    /**
     * Creates the Main Display Window for all of the Swing Content.
     *
     @param width  is of type int
     @param height is of type int
     */
    private void createMainViewerWindow(final int width, final int height) {
        if (frame instanceof JFrame) {
            frame.setSize(width, height);
            ((Windowframe).setLocationRelativeTo(null)//centre on screen
            ((JFrameframe).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
            ((Windowframe).addWindowListener(new FrameCloser(currentCommands, this, decode_pdf, thumbnails, commonValues, properties));
            frame.setVisible(true);
        }
    }

    /**
     * Returns the RecentDocumentFactory used to hand the recent document list
     *
     @return RecentDocumentFactory used by the user interface
     */
    @Override
    public RecentDocumentsFactory getRecentDocument() {
        if (recent != null) {
            return recent;
        else {
            return recent = new RecentDocuments(PropertiesFile.getNoRecentDocumentsToDisplay());
        }
    }

    /**
     * Create the RecentDocuments for the user interface
     */
    @Override
    public void setRecentDocument() {
        recent = new RecentDocuments(PropertiesFile.getNoRecentDocumentsToDisplay());
    }

    /**
     * Open a file in the Viewer
     *
     @param fileToOpen String filename for the file to be opened
     */
    @Override
    public void openFile(final String fileToOpen) {
        if (fileToOpen != null) {
            OpenFile.open(fileToOpen, commonValues, searchFrame, this, decode_pdf, properties, thumbnails);
        }
    }

    /**
     * Open a file in the Viewer
     *
     @param fileName String filename for the file to be opened
     */
    @Override
    public void open(final String fileName) {
        OpenFile.open(fileName, commonValues, searchFrame, this, decode_pdf, properties, thumbnails);
    }

    /**
     * Enable and make visible different parts of the page counter of all of it
     *
     @param value      PageCounter value for the different page counter elements
     @param enabled    true to enable the counter section, false to disable.
     @param visibility true to make visible the counter section, false to disable.
     */
    @Override
    public void enablePageCounter(final PageCounter value, final boolean enabled, final boolean visibility) {
        switch (value) {

            case PAGECOUNTER1:
                pageCounter1.setVisible(visibility);
                pageCounter1.setEnabled(enabled);
                break;

            case PAGECOUNTER2:
                pageCounter2.setVisible(visibility);
                pageCounter2.setEnabled(enabled);
                break;

            case PAGECOUNTER3:
                pageCounter3.setVisible(visibility);
                pageCounter3.setEnabled(enabled);
                break;

            case ALL:
                pageCounter1.setVisible(visibility);
                pageCounter1.setEnabled(enabled);
                pageCounter2.setVisible(visibility);
                pageCounter2.setEnabled(enabled);
                pageCounter3.setVisible(visibility);
                pageCounter3.setEnabled(enabled);
                break;

            default:
                System.out.println("No Value detected, please choose from Enum PageCounter in GUI.java");
                break;
        }
    }

    /**
     * Set the text content for a section of the page counter.
     *
     @param value PageCounter value for the different page counter elements
     @param text  String value to be place in the page counter
     */
    @Override
    public void setPageCounterText(final PageCounter value, final String text) {
        switch (value) {

            case PAGECOUNTER1:
                pageCounter1.setText(text);
                break;

            case PAGECOUNTER2:
                pageCounter2.setText(text);
                break;

            case PAGECOUNTER3:
                pageCounter3.setText(text);
                break;

            default:
                System.out.println("No Value detected, please choose from Enum PageCounter in GUI.java");
                break;
        }
    }

    /**
     * Get the page counter segments
     *
     @param value PageCounter value for the different page counter elements
     @return an Object containing the section of the page counter
     */
    @Override
    public Object getPageCounter(final PageCounter value) {
        switch (value) {

            case PAGECOUNTER1:
                return pageCounter1;

            case PAGECOUNTER2:
                return pageCounter2;

            case PAGECOUNTER3:
                return pageCounter3;

            default:
                System.out.println("No Value detected, please choose from Enum PageCounter in GUI.java");
                return 0;
        }
    }

    /**
     * Update the page counter input size to accommodate the contents
     */
    @Override
    public void updateTextBoxSize() {
        //Set textbox size
        int col = (String.valueOf(commonValues.getPageCount())).length();

        if (decode_pdf.getIO().getPageLabels() != null) {
            final Collection<String> values = decode_pdf.getIO().getPageLabels().values();
            for (final String value : values) {
                final int length = value.length();
                if (col < length) {
                    col = length;
                }
            }
        }
        if (decode_pdf.getDisplayView() == Display.FACING || decode_pdf.getDisplayView() == Display.CONTINUOUS_FACING) {
            col *= 2;
        }
        if (col < 2) {
            col = 2;
        }

        pageCounter2.setColumns(col);
        pageCounter2.setMaximumSize(pageCounter2.getPreferredSize());

        navToolBar.invalidate();
        navToolBar.doLayout();

    }

    /**
     * Enable and or set visibility for the cursor display for multi box
     *
     @param enabled true to enable, false to disable
     @param visible true to make visible, false to make invisible
     */
    @Override
    public void enableCursor(final boolean enabled, final boolean visible) {
        cursor.setEnabled(enabled);
        cursor.setVisible(visible);
    }

    /**
     * Enable and or set visibility for the memory bar display for multi box
     *
     @param enabled true to enable, false to disable
     @param visible true to make visible, false to make invisible
     */
    @Override
    public void enableMemoryBar(final boolean enabled, final boolean visible) {
        multibox.setEnabled(enabled);
        multibox.setVisible(visible);
    }

    /**
     * Enable and or set visibility for the navigation bar
     *
     @param enabled true to enable, false to disable
     @param visible true to make visible, false to make invisible
     */
    @Override
    public void enableNavigationBar(final boolean enabled, final boolean visible) {
        navButtons.setEnabled(enabled);
        navButtons.setVisible(visible);
    }

    /**
     * Enable and or set visibility for the download display for multi box
     *
     @param enabled true to enable, false to disable
     @param visible true to make visible, false to make invisible
     */
    @Override
    public void enableDownloadBar(final boolean enabled, final boolean visible) {
        downloadBar.setEnabled(enabled);
        downloadBar.setVisible(visible);
    }

    /**
     * Get the current count of tabs on the side tab bar
     *
     @return int value representing the number of tabs currently visible
     */
    @Override
    public int getSidebarTabCount() {
        return navOptionsPanel.getTabCount();
    }

    /**
     * Get the title of the tab at the given position
     *
     @param pos The position of the tab on the tabbed pane
     @return String title of the given tab or an empty String is tab not present.
     */
    @Override
    public String getSidebarTabTitleAt(final int pos) {
        if (navOptionsPanel.getIconAt(pos!= null) {
            return navOptionsPanel.getIconAt(pos).toString();
        else {
            return "";
        }
    }

    /**
     * Remove the tab at the specified position from the side tab bar
     *
     @param pos Tab index to removed.
     */
    @Override
    public void removeSidebarTabAt(final int pos) {
        navOptionsPanel.remove(pos);
    }

    /**
     * Get the divider location for the viewer, always returns 0 if in Multiviewer
     *
     @return double representation of the divider location
     */
    @Override
    public double getDividerLocation() {
        return displayPane.getDividerLocation();
    }

    /**
     * calculates the scalingToFit required to make the given area visible
     *
     @param left   float value representing the smallest value on the x axis
     @param right  float value representing the largest value on the x axis
     @param top    float value representing the largest value on the y axis
     @param bottom float value representing the smallest value on the y axis
     @return float value representing the scalingToFit value
     */
    @Override
    public float scaleToVisible(final float left, final float right, final float top, final float bottom) {

        float width = scrollPane.getViewport().getWidth() - inset - inset;
        final float height = scrollPane.getViewport().getHeight() - inset - inset;

        if (displayPane != null) {
            width -= displayPane.getDividerSize();
        }

        final float widthScaling = (right - left/ width;
        final float heightScaling = (top - bottom/ height;

        if (widthScaling > heightScaling) {
            return decode_pdf.getDPIFactory().adjustScaling(widthScaling);
        else {
            return decode_pdf.getDPIFactory().adjustScaling(heightScaling);
        }
    }

    /**
     * Get the thickness of the glow border
     *
     @return thickness of glow as an int
     */
    @Override
    public int getDropShadowDepth() {
        return glowThickness;
    }

    /**
     * Unused in Viewer, present for compatibility
     *
     @param pan unused
     */
    @Override
    public void setPannable(final boolean pan) {//stub
    }

    /**
     * Set up the split pane divider for use
     *
     @param size       size of the divider
     @param visibility true to set left side of divider visible and enabled, false to set disabled and invisible
     */
    @Override
    public void setupSplitPaneDivider(final int size, final boolean visibility) {
        displayPane.setDividerSize(size);
        displayPane.getLeftComponent().setEnabled(visibility);
        displayPane.getLeftComponent().setVisible(visibility);
    }

    /**
     * Get the start / collapsed position of the split pane divider
     *
     @return divider position as a double
     */
    @Override
    public double getStartSize() {
        return collapsedSize;
    }

    /**
     * Set the start / collapsed position of the split pane divider
     *
     @param size position as an int
     */
    @Override
    public void setStartSize(final int size) {
        collapsedSize = size;
    }

    /**
     * Get the page container for the PDF display area
     *
     @return JScrollPane containing the PdfDecoder
     */
    @Override
    public JScrollPane getPageContainer() {
        return scrollPane;
    }

    /**
     * Enable and or set visibility for the status bar for multi box
     *
     @param enabled true to enable, false to disable
     @param visible true to make visible, false to make invisible
     */
    @Override
    public void enableStatusBar(final boolean enabled, final boolean visible) {
        statusBar.setEnabled(enabled);
        statusBar.setVisible(visible);
    }

    /**
     * Converts mouse / components coords to pdf page coords
     *
     @param x    :: The x coordinate of the cursors location in display area coordinates
     @param y    :: The y coordinate of the cursors location in display area coordinates
     @param page :: The page we are currently on
     @return Point object of the cursor location in page coordinates
     */
    public Point convertComponentCoordsToPageCoords(final int x, final int y, final int page) {
        return SwingMouseUtils.getCoordsOnPage(x, y, page, decode_pdf, this, commonValues);
    }

    /**
     * Set the display view options to be used to display the PDF.
     *
     @param displayView int value for display view from Display
     @param orientation int value for display orientation from Display
     */
    @Override
    public void setDisplayView(final int displayView, final int orientation) {

        final int lastDisplayView = decode_pdf.getDisplayView();
        if (decode_pdf.isOpen() && lastDisplayView != displayView) {
            final PdfObject collectionObj = decode_pdf.getIO().getPDFObject(PdfDictionary.Collection);
            if (displayView == Display.PORTFOLIO_DETAIL || displayView == Display.PORTFOLIO_TILE) {
                if (collectionObj == null) {
                    //Incorrect mode for file type so cancel display view change
                    showMessageDialog(Messages.getMessage("PdfPortfolio.nonPortfolioIncorrectDisplay"));
                    return;
                else {

                    switch (displayView) {
                        case Display.PORTFOLIO_DETAIL:
                            setupDetailPortfolioView();
                            break;
                        case Display.PORTFOLIO_TILE:
                            setupTilePortfolioView();
                            break;
                    }
                }
            else {
                //Only set up pdf view if we were in a portfolio mode
                if ((lastDisplayView == Display.PORTFOLIO_DETAIL || lastDisplayView == Display.PORTFOLIO_TILE)) {
                    setupPdfView();
                }
            }
        }

        //Check for null as can be called before UI is set up
        if (annotationsPanel != null && SwingAnnotationPanel.addPanel()) {
            ((SwingMouseAnnotationsgetAnnotationPanel().getAnnotationListener()).setFormMode(GUIAnnotationPanel.FORMMODE.CREATION);
        }

        // remove listener if setup
        if (viewListener != null) {

            ((Componentdecode_pdf).removeComponentListener(viewListener);

            viewListener.dispose();
            viewListener = null;
        }

        final boolean hasChanged = setDisplayView2(displayView, orientation);
        //move to correct page
        final int pageNumber = decode_pdf.getPageNumber();
        if (pageNumber > && hasChanged) {
            try {
                decode_pdf.setPageParameters(scaling, pageNumber, decode_pdf.getDisplayRotation());
                ((Componentdecode_pdf).invalidate();
                ((JComponentdecode_pdf).updateUI();
                decode_pdf.decodePage(pageNumber);

                //Hide annotations tab if not needed
                if (decode_pdf.getDisplayView() == Display.SINGLE_PAGE) {
                    checkTabShown(annotationTitle);
                else {
                    removeTab(annotationTitle);
                }

            catch (final Exception e) {
                LogWriter.writeLog("Exception: " + e.getMessage());
            }
        }

        //Only all search in certain modes
        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);
            ((Componentdecode_pdf).addComponentListener(viewListener);
        }
    }

    /**
     * class to repaint multiple views
     */
    private class RefreshLayout extends ComponentAdapter {

        final PdfDecoderInt decode_pdf;

        final PageMoveTracker tracker = new PageMoveTracker();

        int delay = 500;

        RefreshLayout(final PdfDecoderInt pdf) {
            this.decode_pdf = pdf;
            final String value = properties.getValue("pageMoveDelay");
            if (value != null && !value.isEmpty()) {
                delay = Integer.parseInt(value);
            }
        }

        @Override
        public void componentMoved(final ComponentEvent e) {
            tracker.startTimer(decode_pdf.getPages(), decode_pdf.getPageNumber()(FileAccessdecode_pdf.getExternalHandler(Options.FileAccess), delay);
        }

        @Override
        public void componentResized(final ComponentEvent e) {

            final int displayView = decode_pdf.getDisplayView();

            final PdfPageData pageData = decode_pdf.getPdfPageData();

            final int page = decode_pdf.getPageNumber();

            if (displayView != Display.SINGLE_PAGE && displayView != Display.PAGEFLOW) {
                final Rectangle r = decode_pdf.getVisibleRect();

                if (!(pageData.getScaledCropBoxWidth(page> r.width
                        || pageData.getScaledCropBoxHeight(page> r.height)) {
                    scrollToPage(page);
                }
                tracker.startTimer(decode_pdf.getPages(), decode_pdf.getPageNumber()(FileAccessdecode_pdf.getExternalHandler(Options.FileAccess), delay);
            }
        }

        //fix submitted by Niklas Matthies
        void dispose() {
            tracker.dispose();
        }
    }

    /**
     * Remove the ComponentListener from the PdfDecoder and flush cached pages
     */
    @Override
    public void removePageListener() {

        // remove listener if not removed by close
        if (viewListener != null) {

            //flush any cached pages
            decode_pdf.getPages().flushPageCaches();

            ((Componentdecode_pdf).removeComponentListener(viewListener);

            viewListener.dispose();
            viewListener = null;

        }
    }

    /**
     * Trigger page turn in magazine mode. Not to be used in other display modes.
     *
     @param decode_pdf   PdfDecoder holder the PDF
     @param commonValues Values object holding PDF values
     @param updatedTotal New page total after page turn
     @param rightTurn    true if turning page right, false if turning left
     */
    @Override
    public void triggerPageTurnAnimation(final PdfDecoderInt decode_pdf, final Values commonValues, final int updatedTotal, final boolean rightTurn) {
        float pageW = decode_pdf.getPdfPageData().getCropBoxWidth(1);
        float pageH = decode_pdf.getPdfPageData().getCropBoxHeight(1);
        if (decode_pdf.getPdfPageData().getRotation(1180 == 90) {
            final float temp = pageW;
            pageW = pageH;
            pageH = temp;
        }

        final Point corner = new Point();
        corner.x = (int) ((decode_pdf.getVisibleRect().getWidth() 2));
        if (rightTurn) {
            corner.x -= pageW;
        else {
            corner.x += pageW;
        }
        corner.y = (int) (decode_pdf.getInsetH() + pageH);

        final Point cursor = new Point();
        cursor.x = (int) ((decode_pdf.getVisibleRect().getWidth() 2+ pageW);
        if (rightTurn) {
            cursor.x += pageW;
        else {
            cursor.x -= pageW;
        }
        cursor.y = (int) (decode_pdf.getInsetH() + pageH);

        final GUIFactory currentGUI = this;

        final Thread animation = new Thread(() -> {
            // Fall animation
            int velocity = 1;

            //ensure cursor is not outside expected range
            if ((rightTurn && cursor.x <= corner.x|| (!rightTurn && cursor.x >= corner.x)) {
                cursor.x = corner.x - 1;
            }

            //Calculate distance required
            final double distX = (corner.x - cursor.x);

            //Loop through animation
            while ((rightTurn && cursor.getX() >= corner.getX()) || (!rightTurn && cursor.getX() <= corner.getX())) {

                //amount to move this time
                double xMove = velocity * distX * 0.001;

                //make sure always moves at least 1 pixel in each direction
                if ((rightTurn && xMove > -1)) {
                    xMove = -1;
                else {
                    if ((!rightTurn && xMove < 1)) {
                        xMove = 1;
                    }
                }

                cursor.setLocation(cursor.getX() + xMove, cursor.getY());
                if (rightTurn) {
                    decode_pdf.setUserOffsets((intcursor.getX()(intcursor.getY(), OffsetOptions.INTERNAL_DRAG_CURSOR_BOTTOM_RIGHT);
                else {
                    decode_pdf.setUserOffsets((intcursor.getX()(intcursor.getY(), OffsetOptions.INTERNAL_DRAG_CURSOR_BOTTOM_LEFT);
                }
                //Double speed til moving 32/frame
                if (velocity < 32) {
                    velocity *= 2;
                }

                //sleep til next frame
                try {
                    Thread.sleep(50);
                catch (final InterruptedException e) {
                    e.printStackTrace();
                }

            }

            //change page
            commonValues.setCurrentPage(updatedTotal);
            setPageNumber();
            decode_pdf.setPageParameters(getScaling(), commonValues.getCurrentPage());
            decodePage();

            //unlock corner drag
            PageNavigator.setPageTurnAnimating(false, currentGUI);

            //hide turnover
            decode_pdf.setUserOffsets(00, OffsetOptions.INTERNAL_DRAG_BLANK);

        });

        animation.setDaemon(true);
        //lock corner drag
        PageNavigator.setPageTurnAnimating(true, this);

        animation.start();

    }

    @Override
    void setCursor(final int type) {

        if (type == 1) {
            ((Componentdecode_pdf).setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        else if (type == 2) {
            ((Componentdecode_pdf).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        }

    }

    /**
     * Not part of API - used internally
     * set view mode used in panel and redraw in new mode
     * SINGLE_PAGE,CONTINUOUS,FACING,CONTINUOUS_FACING delay is the time in
     * milli-seconds which scrolling can stop before background page drawing
     * starts Multipage views not in OS releases
     */
    private boolean setDisplayView2(final int displayView, final int orientation) {

        final DecoderOptions options = decode_pdf.getDecoderOptions();
        Display pages = decode_pdf.getPages();
        final FileAccess fileAccess = (FileAccessdecode_pdf.getExternalHandler(Options.FileAccess);
        final int pageNumber = decode_pdf.getPageNumber();
        final ExternalHandlers externalHandlers = decode_pdf.getExternalHandler();

        final PdfDecoder comp = (PdfDecoderdecode_pdf;
        final int lastDisplayView = decode_pdf.getDisplayView();

        options.setPageAlignment(orientation);

        if (pages != null) {
            pages.stopGeneratingPage();
        }

        final boolean hasChanged = displayView != lastDisplayView;

        options.setDisplayView(displayView);

        if (lastDisplayView != displayView && lastDisplayView == Display.PAGEFLOW && pages != null) {
            pages.dispose();
        }

        final Object customSwingHandle = externalHandlers.getExternalHandler(Options.MultiPageUpdate);

        switch (displayView) {
            case Display.SINGLE_PAGE:
                if (pages == null || hasChanged) {
                    final DynamicVectorRenderer currentDisplay = decode_pdf.getDynamicRenderer();

                    pages = new SingleDisplay(pageNumber, currentDisplay, comp, options)//abacus-del
                }
                break;

            case Display.PAGEFLOW:


                if (pages instanceof org.jpedal.display.swing.PageFlowDisplay) { //adode-del abacus-del
                    return hasChanged; //adode-del abacus-del
                //adode-del abacus-del

                if (lastDisplayView != Display.SINGLE_PAGE) {
                    setDisplayView(Display.SINGLE_PAGE, 0);
                    setDisplayView(Display.PAGEFLOW, 0);
                    return hasChanged;
                }

                ((JScrollPanecomp.getParent().getParent()).setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                ((JScrollPanecomp.getParent().getParent()).setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

                pages = new org.jpedal.display.swing.PageFlowDisplay((GUIFactorycustomSwingHandle, decode_pdf)//adode-del abacus-del

                break;

            default:

                pages = new MultiDisplay(pageNumber, null, displayView, comp, options, fileAccess)//adode-del abacus-del
                pages.setPageRotation(decode_pdf.getDisplayRotation())//force update //adode-del

                //pass in value if needed
                final RenderChangeListener customRenderChangeListener = (RenderChangeListenerexternalHandlers.getExternalHandler(Options.RenderChangeListener);
                if (customRenderChangeListener != null) {
                    pages.setObjectValue(Options.RenderChangeListener, customRenderChangeListener);
                }

                break;
        }

        //enable pageFlow mode and setup slightly different display configuration
        if (lastDisplayView == Display.PAGEFLOW) {
            comp.removeAll();

            //forms needs null layout manager
            comp.setLayout(null);

            ((JScrollPanecomp.getParent().getParent()).setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
            ((JScrollPanecomp.getParent().getParent()).setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

            final javax.swing.Timer t = new javax.swing.Timer(1_000, e -> comp.repaint());
            t.setRepeats(false);
            t.start();
        }

        //setup once per page getting all page sizes and working out settings for views
        if (fileAccess.getOffset() == null) {
            fileAccess.setOffset(new PageOffsets(decode_pdf.getPageCount(), decode_pdf.getPdfPageData()));
        }

        pages.setup(options.useHardwareAcceleration(), fileAccess.getOffset());
        final DynamicVectorRenderer currentDisplay = decode_pdf.getDynamicRenderer();
        pages.init(scaling, decode_pdf.getDisplayRotation(), decode_pdf.getPageNumber(), currentDisplay, true);

        pages.forceRedraw();

        pages.refreshDisplay();

        comp.pages = pages;

        return hasChanged;
    }

    private void applyStyle() {
        //String panels = properties.getStyleAttribute("panels", "background-color");
        final String background = properties.getStyleAttribute("panelback""background-color");

        if (background != null) {
            final Color backgroundColorValue = CSSToJavaValues.convertToColor(background);
            ((Componentdecode_pdf).setBackground(backgroundColorValue);
        }

    }

    /**
     * Get the glass panes used to allow annotations draw in the viewer for
     * adding to the PDF.
     *
     @return a JPanel to act as a glass pane.
     */
    @Override
    public Object getGlassPane() {
        return glassPane;
    }

    private void setupTilePortfolioView() {

        if (tileView == null) {
            tileView = new SwingPortfolioTile(this);
        }
        tileView.loadCollectionValues(decode_pdf);

        if (detailView != null) {
            portfolioParent.remove(detailView);
        }

        if (tileView != null) {
            portfolioParent.remove(tileView);
        }

        portfolioParent.remove(displayPane);
        portfolioParent.add(tileView, BorderLayout.CENTER);

        ((SwingMenuItemsmenuItems).getMenuItem(Commands.PORTFOLIO_TILES).setSelected(true);
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.PORTFOLIO_DETAIL).setSelected(false);

        portfolioParent.repaint();
        frame.validate();
    }

    private void setupDetailPortfolioView() {

        if (detailView == null) {
            detailView = new SwingPortfolioDetail(this);
        }

        detailView.loadCollectionValues(decode_pdf);

        if (detailView != null) {
            portfolioParent.remove(detailView);
        }

        if (tileView != null) {
            portfolioParent.remove(tileView);
        }

        portfolioParent.remove(displayPane);
        portfolioParent.add(detailView, BorderLayout.CENTER);

        ((SwingMenuItemsmenuItems).getMenuItem(Commands.PORTFOLIO_TILES).setSelected(false);
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.PORTFOLIO_DETAIL).setSelected(true);

        portfolioParent.repaint();
        frame.validate();
    }

    private void setupPdfView() {

        if (detailView != null) {
            portfolioParent.remove(detailView);
        }

        if (tileView != null) {
            portfolioParent.remove(tileView);
        }

        portfolioParent.remove(displayPane);

        portfolioParent.add(displayPane, BorderLayout.CENTER);
        portfolioParent.validate();

        //Ensure display pane is displayed correctly
        displayPane.repaint();

        scaleAndRotate();

    }

    @Override
    public void setupGUIElementsForFiletype(final Values.FileType type) {

        //Set Visibility of items (also check properties)
        swButtons.getButton(Commands.ROTATELEFT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("RotateLeftbutton").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.ROTATERIGHT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("RotateRightbutton").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.ZOOMIN).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("ZoomInbutton").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.ZOOMOUT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("ZoomOutbutton").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.MOUSEMODE).setVisible(type == Values.FileType.PDF
                && properties.getValue("MouseModeButton").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.FIRSTPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Firstbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.FBACKPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Back10bottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.BACKPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Backbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.FORWARDPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Forwardbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.FFORWARDPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Forward10bottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.LASTPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Lastbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.SINGLE).setVisible(type == Values.FileType.PDF
                && properties.getValue("Singlebottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.CONTINUOUS).setVisible(type == Values.FileType.PDF
                && properties.getValue("Continuousbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.FACING).setVisible(type == Values.FileType.PDF
                && properties.getValue("Facingbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.CONTINUOUS_FACING).setVisible(type == Values.FileType.PDF
                && properties.getValue("Continuousfacingbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.PAGEFLOW).setVisible(type == Values.FileType.PDF
                && properties.getValue("PageFlowbottom").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.PRINT).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("Printbutton").equalsIgnoreCase("true"));
        swButtons.getButton(Commands.SNAPSHOT).setVisible(type == Values.FileType.PDF
                && properties.getValue("Snapshotbutton").equalsIgnoreCase("true"));

        multibox.setVisible(type == Values.FileType.PDF
                && properties.getValue("Memorybottom").equalsIgnoreCase("true"));

        navButtons.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("NavigationBarMenu").equalsIgnoreCase("true"));

        //Handle Combo boxes
        getCombo(Commands.SCALING).setVisibility((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("Scalingdisplay").equalsIgnoreCase("true"));
        getCombo(Commands.ROTATION).setVisibility((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("Rotationdisplay").equalsIgnoreCase("true"));

        final boolean showPageCounter = properties.getValue("Gotobottom").equalsIgnoreCase("true");
        pageCounter1.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff())) && showPageCounter);
        pageCounter2.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff())) && showPageCounter);
        pageCounter3.setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff())) && showPageCounter);

        final boolean showMenubarSearch = properties.getValue("searchWindowType").equalsIgnoreCase("2");
        swButtons.getButton(Commands.NEXTRESULT).setVisible(type == Values.FileType.PDF && showMenubarSearch);
        swButtons.getButton(Commands.PREVIOUSRESULT).setVisible(type == Values.FileType.PDF && showMenubarSearch);
        searchText.setVisible(type == Values.FileType.PDF && showMenubarSearch);
        options.setVisible(type == Values.FileType.PDF && showMenubarSearch);

        navOptionsPanel.setVisible((type == Values.FileType.PDF)
                && properties.getValue("SideTabBarMenu").equalsIgnoreCase("true"));

        //No property for this value as always needed
        ((SwingMenuItemsmenuItems).getMenu(Commands.PORTFOLIOMENU).setVisible(type == Values.FileType.PORTFOLIO);

        //Set enabled for items
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.SAVE).setVisible(type == Values.FileType.PDF
                && properties.getValue("Save").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.SAVEFORM).setVisible(type == Values.FileType.PDF
                && properties.getValue("Resaveasforms").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.DOCINFO).setVisible(type == Values.FileType.PDF
                && properties.getValue("Documentproperties").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.FIND).setVisible((type == Values.FileType.PDF)
                && properties.getValue("Find").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.PRINT).setVisible((type == Values.FileType.PDF)
                && properties.getValue("Print").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.SEPARATECOVER).setVisible((type == Values.FileType.PDF)
                && properties.getValue("separateCover").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.PANMODE).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("panMode").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.TEXTSELECT).setVisible((type == Values.FileType.PDF)
                && properties.getValue("textSelect").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.FULLSCREEN).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("Fullscreen").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.FIRSTPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Firstpage").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.BACKPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Backpage").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.GOTO).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Goto").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.FORWARDPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Forwardpage").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.LASTPAGE).setVisible((type == Values.FileType.PDF || (type == Values.FileType.IMAGES && commonValues.isMultiTiff()))
                && properties.getValue("Lastpage").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenu(Commands.EDITMENU).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("EditMenu").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenu(Commands.PAGELAYOUTMENU).setVisible((type == Values.FileType.PDF || type == Values.FileType.IMAGES)
                && properties.getValue("PagelayoutMenu").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.COPY).setVisible(type == Values.FileType.PDF
                && properties.getValue("Copy").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.SELECTALL).setVisible(type == Values.FileType.PDF
                && properties.getValue("Selectall").equalsIgnoreCase("true"));
        ((SwingMenuItemsmenuItems).getMenuItem(Commands.DESELECTALL).setVisible(type == Values.FileType.PDF
                && properties.getValue("Deselectall").equalsIgnoreCase("true"));

        ((SwingMenuItemsmenuItems).getMenu(Commands.PORTFOLIOMENU).setVisible(type == Values.FileType.PORTFOLIO);

        if (type == Values.FileType.IMAGES) {
            currentCommands.executeCommand(Commands.PANMODE, null);
        else {
            currentCommands.executeCommand(Commands.TEXTSELECT, null);
        }

        //Check for double separaters and remove as needed
        swButtons.checkButtonSeparators();
        ((SwingMenuItemsmenuItems).checkMenuItemSeparators();

    }
}