org.pgptool.gui.ui.mainframe.MainFrameView.java Source code

Java tutorial

Introduction

Here is the source code for org.pgptool.gui.ui.mainframe.MainFrameView.java

Source

/*******************************************************************************
 * PGPTool is a desktop application for pgp encryption/decryption
 * Copyright (C) 2017 Sergey Karpushin
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *******************************************************************************/
package org.pgptool.gui.ui.mainframe;

import static org.pgptool.gui.app.Messages.text;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.concurrent.ScheduledExecutorService;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListSelectionModel;
import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

import org.pgptool.gui.app.EntryPoint;
import org.pgptool.gui.app.Messages;
import org.pgptool.gui.configpairs.api.ConfigPairs;
import org.pgptool.gui.decryptedlist.api.DecryptedFile;
import org.pgptool.gui.hintsforusage.ui.HintPm;
import org.pgptool.gui.hintsforusage.ui.HintView;
import org.pgptool.gui.ui.tools.UiUtils;
import org.pgptool.gui.ui.tools.WindowIcon;
import org.pgptool.gui.ui.tools.geometrymemory.TableColumnsGeometryPersisterImpl;
import org.pgptool.gui.ui.tools.geometrymemory.WindowGeometryPersister;
import org.pgptool.gui.ui.tools.geometrymemory.WindowGeometryPersisterImpl;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.base.Preconditions;

import ru.skarpushin.swingpm.base.HasWindow;
import ru.skarpushin.swingpm.base.ViewBase;
import ru.skarpushin.swingpm.bindings.TypedPropertyChangeListener;
import ru.skarpushin.swingpm.tools.SwingPmSettings;
import ru.skarpushin.swingpm.tools.sglayout.SgLayout;

public class MainFrameView extends ViewBase<MainFramePm> implements HasWindow {
    private static final String DELETE = "Delete";
    private static final String CHOOSE = "Choose";

    @Autowired
    private HintView hintView;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;
    @Autowired
    private ConfigPairs uiGeom;

    private JFrame frame;
    private WindowGeometryPersister windowGeometryPersister;

    private JPanel panelRoot;

    private JMenuBar menuBar;
    private JMenuItem miPgpCreateKey;
    private JMenuItem miPgpImportKey;
    private JMenuItem miShowKeyList;
    private JMenuItem miChangeTempFolderForDecrypted;
    private JMenuItem miBmc;
    private JMenuItem miFaq;
    private JMenuItem miHelp;
    private JMenuItem miAbout;
    private JMenuItem miCheckForUpdates;
    private JCheckBoxMenuItem miAutoCheckForUpdates;
    private JMenuItem miWriteFeedback;
    private JMenuItem miConfigExit;
    private JMenuItem miEncrypt;
    private JMenuItem miDecrypt;
    private JMenuItem miEncryptText;
    private JMenuItem miDecryptText;
    private JMenuItem miEncryptBackAll;

    private JPanel panelTablePlaceholder;
    private JTable table;
    private JScrollPane scrollPane;
    private DefaultListSelectionModel selectionModel;
    private JPopupMenu ctxMenu;
    private JLabel lblNoDataToDisplay;
    private TableColumnsGeometryPersisterImpl tableColumnsGeometryPersister;

    private JToolBar toolbar;

    private JPanel hintsPanel;

    @Override
    protected void internalInitComponents() {
        initMenuBar();
        initFormComponents();
        initToolBar();

        ctxMenu = new JPopupMenu();
    }

    private void initFormComponents() {
        lblNoDataToDisplay = new JLabel(Messages.get("phrase.noDecryptedFilesAreMonitoredAtTheMoment"));
        lblNoDataToDisplay.setHorizontalAlignment(JLabel.CENTER);

        SgLayout sgl = new SgLayout(1, 3, 0, 0);
        sgl.setColSize(0, 100, SgLayout.SIZE_TYPE_WEIGHTED);
        sgl.setRowSize(1, 100, SgLayout.SIZE_TYPE_WEIGHTED);
        panelRoot = new JPanel(sgl);
        panelRoot.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7));

        int row = 0;
        JLabel lblPrevDecryptedFiles = new JLabel(
                UiUtils.plainToBoldHtmlString(text("phrase.previouslyDecrpytedFiles")));
        panelRoot.add(lblPrevDecryptedFiles, sgl.cs(0, row));
        lblPrevDecryptedFiles.setBorder(BorderFactory.createEmptyBorder(14, 0, 0, 0));

        row++;
        panelTablePlaceholder = new JPanel(new BorderLayout());
        panelTablePlaceholder.add(initTableComponent(), BorderLayout.CENTER);
        panelRoot.add(panelTablePlaceholder, sgl.cs(0, row));

        // add message panel
        row++;
        hintsPanel = new JPanel(new BorderLayout());
        panelRoot.add(hintsPanel, sgl.cs(0, row));
        // hintView.renderTo(hintsPanel, BorderLayout.CENTER);
    }

    private TypedPropertyChangeListener<HintPm> onHintPmChanged = new TypedPropertyChangeListener<HintPm>() {
        @Override
        public void handlePropertyChanged(Object source, String propertyName, HintPm oldValue, HintPm newValue) {
            hintView.setPm(newValue);

            if (oldValue == null && newValue != null) {
                hintView.renderTo(hintsPanel, BorderLayout.CENTER);
            } else if (oldValue != null && newValue == null) {
                hintView.unrender();
            }
            panelRoot.validate();
        }
    };

    private void initToolBar() {
        toolbar = new JToolBar("Main actions");
        toolbar.setRollover(false);
        toolbar.add(new JButton(actionEncrypt));
        toolbar.add(new JButton(actionEncryptText));
        toolbar.addSeparator();
        toolbar.add(new JButton(actionDecrypt));
        toolbar.add(new JButton(actionDecryptText));
        toolbar.add(new JButton(actionHistory));
        toolbar.addSeparator();
        toolbar.add(new JButton(actionKeyring));
    }

    @SuppressWarnings("serial")
    private Action actionEncrypt = new ToolbarAction("action.encryptFile", "/icons/encrypt.png") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (pm != null) {
                pm.getActionEncrypt().actionPerformed(e);
            }
        }
    };

    @SuppressWarnings("serial")
    private Action actionEncryptText = new ToolbarAction("term.text", "/icons/encrypt.png") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (pm != null) {
                pm.getActionEncryptText().actionPerformed(e);
            }
        }
    };

    @SuppressWarnings("serial")
    private Action actionDecryptText = new ToolbarAction("term.text", "/icons/decrypt.png") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (pm != null) {
                pm.getActionDecryptText().actionPerformed(e);
            }
        }
    };

    @SuppressWarnings("serial")
    private Action actionDecrypt = new ToolbarAction("action.decryptFile", "/icons/decrypt.png") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (pm != null) {
                pm.getActionDecrypt().actionPerformed(e);
            }
        }
    };

    @SuppressWarnings("serial")
    private Action actionHistory = new ToolbarAction("term.history", "/icons/search-48.png") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (pm != null) {
                pm.actionHistoryQuickSearch.actionPerformed(e);
            }
        }
    };

    @SuppressWarnings("serial")
    private Action actionKeyring = new ToolbarAction("term.keyring", "/icons/keyring.png") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (pm != null) {
                pm.getActionShowKeysList().actionPerformed(e);
            }
        }
    };

    private JScrollPane initTableComponent() {
        table = new JTable();

        // Adjust some visual appearence
        table.setRowHeight(22);

        // Add listeners
        selectionModel = new DefaultListSelectionModel();
        selectionModel.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
        selectionModel.addListSelectionListener(rowSelectionListener);
        table.setSelectionModel(selectionModel);
        table.addMouseListener(listMouseListener);
        initTableKeyListener();

        // Envelope in scrollpane
        scrollPane = new JScrollPane();
        scrollPane.addMouseListener(listMouseListener);
        scrollPane.setViewportView(table);
        return scrollPane;
    }

    @SuppressWarnings("serial")
    private void initTableKeyListener() {
        InputMap inputMap = table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DELETE);
        table.getActionMap().put(DELETE, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (pm == null) {
                    return;
                }
                pm.actionDelete.actionPerformed(e);
            }
        });

        InputMap inputMap2 = table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        inputMap2.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), CHOOSE);
        table.getActionMap().put(CHOOSE, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (pm == null) {
                    return;
                }
                pm.actionOpen.actionPerformed(e);
            }
        });
    }

    MouseAdapter listMouseListener = new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger()) {
                myPopupEvent(e);
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (e.isPopupTrigger()) {
                myPopupEvent(e);
            }
        }

        private void myPopupEvent(MouseEvent e) {
            if (!isAttached()) {
                return;
            }

            if (e.getComponent() == table) {
                int r = table.rowAtPoint(e.getPoint());
                if (r >= 0 && r < table.getRowCount() && pm.getRows().findRowByIdx(r) != null) {
                    table.setRowSelectionInterval(r, r);
                } else {
                    table.clearSelection();
                }
            } else {
                table.clearSelection();
            }

            if (ctxMenu.getComponentCount() > 0) {
                ctxMenu.show(e.getComponent(), e.getX(), e.getY());
            }
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getComponent() == table && e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
                Action action = pm.actionOpen;
                if (action != null && action.isEnabled()) {
                    action.actionPerformed(null);
                }
            }
        }
    };

    protected ListSelectionListener rowSelectionListener = new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            if (e.getValueIsAdjusting() || !isAttached()) {
                return;
            }

            DecryptedFile selectedRow = getSelectedRow();
            if (selectedRow == null) {
                table.clearSelection();
            }
            pm.getSelectedRow().setValue(selectedRow);
        }
    };

    private DecryptedFile getSelectedRow() {
        int row = table.getSelectedRow();
        if (row < 0) {
            return null;
        }
        return pm.getRows().findRowByIdx(row);
    }

    private TypedPropertyChangeListener<DecryptedFile> rowPmSelectionListener = new TypedPropertyChangeListener<DecryptedFile>() {
        @Override
        public void handlePropertyChanged(Object source, String propertyName, DecryptedFile oldValue,
                DecryptedFile newValue) {
            if (newValue == getSelectedRow()) {
                return;
            }

            if (newValue == null) {
                table.clearSelection();
                return;
            }

            int idx = pm.getRows().indexOf(newValue);
            if (idx < 0) {
                log.warn("Asked to select nonexistent record " + newValue + ". Skipping selection request.");
                return;
            }
            table.setRowSelectionInterval(idx, idx);
        }
    };

    private void initMenuBar() {
        menuBar = new JMenuBar();

        JMenu menuFile = new JMenu(Messages.get("term.appTitle"));
        menuFile.add(miChangeTempFolderForDecrypted = new JMenuItem());
        menuFile.addSeparator();
        menuFile.add(miBmc = new JMenuItem());
        menuFile.add(miWriteFeedback = new JMenuItem());
        menuFile.add(miFaq = new JMenuItem());
        menuFile.add(miHelp = new JMenuItem());
        menuFile.addSeparator();
        menuFile.add(miAbout = new JMenuItem());
        menuFile.add(miCheckForUpdates = new JMenuItem());
        menuFile.add(miAutoCheckForUpdates = new JCheckBoxMenuItem());
        menuFile.addSeparator();
        menuFile.add(miConfigExit = new JMenuItem());

        JMenu menuKeyring = new JMenu(Messages.get("term.keyring"));
        menuKeyring.add(miShowKeyList = new JMenuItem());
        menuKeyring.addSeparator();
        menuKeyring.add(miPgpImportKey = new JMenuItem());
        menuKeyring.add(miPgpCreateKey = new JMenuItem());

        JMenu menuActions = new JMenu(Messages.get("term.actions"));
        menuActions.add(miEncrypt = new JMenuItem());
        menuActions.add(miEncryptText = new JMenuItem());
        menuActions.addSeparator();
        menuActions.add(miDecrypt = new JMenuItem());
        menuActions.add(miDecryptText = new JMenuItem());
        menuActions.addSeparator();
        menuActions.add(miEncryptBackAll = new JMenuItem());

        menuBar.add(menuFile);
        menuBar.add(menuKeyring);
        menuBar.add(menuActions);
    }

    @Override
    protected void internalBindToPm() {
        super.internalBindToPm();

        updateWindowTitle();
        bindToActions();
        bindTable();
        bindContextMenu();

        bindingContext.registerOnChangeHandler(pm.getHintPm(), onHintPmChanged);
        onHintPmChanged.handlePropertyChanged(pm, pm.getHintPm().getPropertyName(), null,
                pm.getHintPm().getValue());
    }

    @Override
    protected void internalUnbindFromPm() {
        super.internalUnbindFromPm();

        updateWindowTitle();

        table.setModel(new DefaultTableModel());
        ctxMenu.removeAll();
        hintView.setPm(null);
    }

    private void bindTable() {
        hasDataChangeHandler.handlePropertyChanged(this, pm.getHasData().getPropertyName(), false,
                pm.getHasData().getValue());
        bindingContext.registerOnChangeHandler(pm.getHasData(), hasDataChangeHandler);
        bindingContext.registerOnChangeHandler(pm.getSelectedRow(), rowPmSelectionListener);
    }

    private void bindContextMenu() {
        if (pm.contextMenuActions != null) {
            for (Action action : pm.contextMenuActions) {
                if (action == null) {
                    ctxMenu.addSeparator();
                } else {
                    ctxMenu.add(action);
                }
            }
        }
    }

    private TypedPropertyChangeListener<Boolean> hasDataChangeHandler = new TypedPropertyChangeListener<Boolean>() {
        @Override
        public void handlePropertyChanged(Object source, String propertyName, Boolean oldValue, Boolean newValue) {
            if (!newValue) {
                table.setModel(new DefaultTableModel());
                panelTablePlaceholder.removeAll();
                panelTablePlaceholder.add(lblNoDataToDisplay, BorderLayout.CENTER);
                panelTablePlaceholder.revalidate();
                panelTablePlaceholder.repaint();
                return;
            }

            if (tableColumnsGeometryPersister != null) {
                tableColumnsGeometryPersister.detach();
                tableColumnsGeometryPersister = null;
            }
            table.setModel(pm.getRows());
            adjustColumnsWidths();
            tableColumnsGeometryPersister = new TableColumnsGeometryPersisterImpl(table, "mfrmDecrMon", uiGeom,
                    scheduledExecutorService);
            tableColumnsGeometryPersister.restoreColumnsConfig();

            table.repaint();
            panelTablePlaceholder.removeAll();
            panelTablePlaceholder.add(scrollPane, BorderLayout.CENTER);
            panelTablePlaceholder.revalidate();
            panelTablePlaceholder.repaint();
        }
    };

    private void bindToActions() {
        bindingContext.setupBinding(pm.getActionConfigExit(), miConfigExit);

        bindingContext.setupBinding(pm.getActionBuyMeCoffee(), miBmc);
        bindingContext.setupBinding(pm.getActionFaq(), miFaq);
        bindingContext.setupBinding(pm.getActionHelp(), miHelp);

        bindingContext.setupBinding(pm.getActionAbout(), miAbout);
        bindingContext.setupBinding(pm.getActionCheckForUpdates(), miCheckForUpdates);
        bindingContext.setupBinding(pm.getActionAutoCheckForUpdates(), miAutoCheckForUpdates);
        bindingContext.setupBinding(pm.getActionShowFeedbackForm(), miWriteFeedback);
        bindingContext.registerPropertyValuePropagation(pm.getIsAutoUpdatesEnabled(), miAutoCheckForUpdates,
                "state");

        bindingContext.setupBinding(pm.getActionImportKey(), miPgpImportKey);
        bindingContext.setupBinding(pm.getActionCreateKey(), miPgpCreateKey);
        bindingContext.setupBinding(pm.getActionShowKeysList(), miShowKeyList);
        bindingContext.setupBinding(pm.getActionChangeFolderForDecrypted(), miChangeTempFolderForDecrypted);
        bindingContext.setupBinding(pm.getActionEncrypt(), miEncrypt);
        bindingContext.setupBinding(pm.getActionEncryptText(), miEncryptText);
        bindingContext.setupBinding(pm.getActionDecryptText(), miDecryptText);
        bindingContext.setupBinding(pm.actionEncryptBackAll, miEncryptBackAll);
        bindingContext.setupBinding(pm.getActionDecrypt(), miDecrypt);
    }

    private void updateWindowTitle() {
        if (frame != null) {
            frame.setTitle(Messages.get("term.appTitle"));
        }
    }

    private void adjustColumnsWidths() {
        DefaultTableCellRenderer leftRenderer = new DefaultTableCellRenderer();
        leftRenderer.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
        leftRenderer.setHorizontalAlignment(JLabel.LEFT);
        adjustColumn(leftRenderer, DecryptedFilesModel.COLUMN_ENCRYPTED_FILE, 50, leftRenderer);
        adjustColumn(leftRenderer, DecryptedFilesModel.COLUMN_DECRYPTED_FILE, 50, leftRenderer);
    }

    private void adjustColumn(DefaultTableCellRenderer leftRenderer, int columnIdx, int columnSize,
            DefaultTableCellRenderer cellRenderer) {
        table.getColumnModel().getColumn(columnIdx).setPreferredWidth(columnSize);
        table.getColumnModel().getColumn(columnIdx).setCellRenderer(cellRenderer);
    }

    @Override
    protected void internalRenderTo(Container owner, Object constraints) {
        Preconditions.checkArgument(owner == null || owner instanceof Window,
                "Target must not be specified or be sub-calss of Window");
        Preconditions.checkState(pm != null, "PM is required for this view");

        if (frame != null && frame.getOwner() != owner) {
            frame.remove(panelRoot);
            frame.dispose();
            frame = null;
        }

        if (frame == null) {
            frame = new JFrame();
            // frame.setSize(new Dimension(UiUtils.getFontRelativeSize(90),
            // UiUtils.getFontRelativeSize(50)));
            frame.setLayout(new BorderLayout());
            frame.setResizable(true);
            frame.setMinimumSize(
                    new Dimension((int) (toolbar.getPreferredSize().getWidth() + UiUtils.getFontRelativeSize(2)),
                            UiUtils.getFontRelativeSize(35)));
            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            updateWindowTitle();
            frame.add(panelRoot, BorderLayout.CENTER);
            frame.add(toolbar, BorderLayout.PAGE_START);
            frame.addWindowListener(windowAdapter);
            frame.setJMenuBar(menuBar);

            windowGeometryPersister = new WindowGeometryPersisterImpl(frame, "mainFrame", uiGeom,
                    scheduledExecutorService);
            windowGeometryPersister.restoreSize();
            // if (!windowGeometryPersister.restoreLocation()) {
            UiUtils.centerWindow(frame);
            // }

            WindowIcon.setWindowIcon(frame);
        }

        frame.setVisible(true);
    }

    protected WindowAdapter windowAdapter = new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            if (isAttached()) {
                pm.getActionConfigExit().actionPerformed(null);
            }
            super.windowClosing(e);
        };
    };

    @Override
    protected void internalUnrender() {
        windowGeometryPersister.detach();
        frame.setVisible(false);
    }

    @Override
    public Window getWindow() {
        return frame;
    }

    public void bringToFront() {
        frame.setVisible(true);
        frame.setState(JFrame.NORMAL);
        UiUtils.makeSureWindowBroughtToFront(frame);
    }

    private abstract class ToolbarAction extends AbstractAction {
        private static final long serialVersionUID = 5177364704498790332L;
        private final String actionNameMessageCode;
        private final String iconFilepathname;
        private Icon icon;

        public ToolbarAction(String actionNameMessageCode, String iconFilepathname) {
            this.actionNameMessageCode = actionNameMessageCode;
            this.iconFilepathname = iconFilepathname;
        }

        @Override
        public Object getValue(String key) {
            if (Action.NAME.equals(key)) {
                return SwingPmSettings.getMessages().get(actionNameMessageCode) + "   ";
            }
            if (Action.SMALL_ICON.equals(key)) {
                return getIcon();
            }
            return super.getValue(key);
        };

        public Icon getIcon() {
            if (icon == null) {
                icon = EntryPoint.loadImage(iconFilepathname);
            }
            return icon;
        }
    }

}