/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* 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.esa.snap.ui.assistant;
import org.esa.snap.ui.AbstractDialog;
import org.esa.snap.ui.UIUtils;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Shows a sequence of {@link AssistantPage assitant pages} with an dialog.
*/
public class AssistantPane implements AssistantPageContext {
private AssistantPage currentPage;
private Deque<AssistantPage> pageStack;
private JDialog dialog;
private Action prevAction;
private Action nextAction;
private Action finishAction;
private JLabel titleLabel;
private JPanel pagePanel;
private HelpAction helpAction;
private AssistantPane.CancelAction cancelAction;
/**
* Creates a new {@code AssistantPane}.
*
* @param parent The parent window.
* @param title The title of the dialog.
*/
public AssistantPane(Window parent, String title) {
pageStack = new ArrayDeque<AssistantPage>();
prevAction = new PrevAction();
nextAction = new NextAction();
finishAction = new FinishAction();
cancelAction = new CancelAction();
helpAction = new HelpAction();
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 2, 2));
buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
buttonPanel.add(new JButton(prevAction));
final JButton nextButton = new JButton(nextAction);
buttonPanel.add(nextButton);
buttonPanel.add(new JButton(finishAction));
buttonPanel.add(new JButton(cancelAction));
buttonPanel.add(new JButton(helpAction));
titleLabel = new JLabel();
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 14.0f));
titleLabel.setHorizontalAlignment(JLabel.RIGHT);
titleLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
titleLabel.setForeground(Color.WHITE);
JPanel titlePanel = new JPanel(new BorderLayout());
titlePanel.setBackground(titlePanel.getBackground().darker());
titlePanel.add(titleLabel, BorderLayout.CENTER);
pagePanel = new JPanel(new BorderLayout());
pagePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
dialog = new JDialog(parent, title, Dialog.ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(titlePanel, BorderLayout.NORTH);
dialog.getContentPane().add(pagePanel, BorderLayout.CENTER);
dialog.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.getRootPane().setDefaultButton(nextButton);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
cancelAction.cancel();
}
});
}
@Override
public Window getWindow() {
return dialog;
}
@Override
public AssistantPage getCurrentPage() {
return currentPage;
}
@Override
public void setCurrentPage(AssistantPage currentPage) {
this.currentPage = currentPage;
pagePanel.removeAll();
titleLabel.setText(currentPage.getPageTitle());
pagePanel.add(currentPage.getPageComponent(), BorderLayout.CENTER);
updateState();
dialog.invalidate();
dialog.validate();
dialog.repaint();
}
@Override
public void updateState() {
final AssistantPage page = getCurrentPage();
if (page != null) {
final boolean pageValid = page.validatePage();
prevAction.setEnabled(!pageStack.isEmpty());
nextAction.setEnabled(pageValid && page.hasNextPage());
finishAction.setEnabled(pageValid && page.canFinish());
helpAction.setEnabled(page.canHelp());
}
}
@Override
public void showErrorDialog(String message) {
final String dialogTitle;
final AssistantPage currentPage = getCurrentPage();
if (currentPage != null) {
dialogTitle = currentPage.getPageTitle();
} else {
dialogTitle = "Unexpected Error";
}
AbstractDialog.showErrorDialog(dialog, message, dialogTitle);
}
/**
* Displays the dialog if this {@code AssistantPane} with
* the given {@link AssistantPage page} as first page.
*
* @param firstPage The first page which is displayed in the dialog.
*/
public void show(AssistantPage firstPage) {
show(firstPage, null);
}
/**
* Displays the dialog if this {@code AssistantPane} with
* the given {@link AssistantPage page} as first page.
*
* @param firstPage The first page which is displayed in the dialog.
* @param bounds The screen bounds of the window, may be {@code null}.
*/
public void show(AssistantPage firstPage, Rectangle bounds) {
initPage(firstPage);
setCurrentPage(firstPage);
if (bounds == null) {
dialog.setSize(480, 320);
UIUtils.centerComponent(dialog, dialog.getParent());
} else {
dialog.setBounds(bounds);
}
dialog.setVisible(true);
}
private void initPage(AssistantPage currentPage) {
currentPage.setContext(this);
}
private void close() {
dialog.dispose();
pageStack.clear();
currentPage = null;
}
private class PrevAction extends AbstractAction {
private PrevAction() {
super("< Previous");
putValue(ACTION_COMMAND_KEY, "Previous");
putValue(MNEMONIC_KEY, (int) 'P');
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
}
@Override
public void actionPerformed(ActionEvent e) {
setCurrentPage(pageStack.pop());
}
}
private class NextAction extends AbstractAction {
private NextAction() {
super("Next >");
putValue(ACTION_COMMAND_KEY, "Next");
putValue(MNEMONIC_KEY, (int) 'N');
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
}
@Override
public void actionPerformed(ActionEvent e) {
AssistantPage nextPage = currentPage.getNextPage();
if (nextPage != null) {
pageStack.push(currentPage);
initPage(nextPage);
setCurrentPage(nextPage);
}
}
}
private class FinishAction extends AbstractAction {
private FinishAction() {
super("Finish");
putValue(ACTION_COMMAND_KEY, "Finish");
putValue(MNEMONIC_KEY, (int) 'F');
}
@Override
public void actionPerformed(ActionEvent e) {
if (getCurrentPage().performFinish()) {
close();
}
}
}
private class CancelAction extends AbstractAction {
private CancelAction() {
super("Cancel");
putValue(ACTION_COMMAND_KEY, "Cancel");
putValue(MNEMONIC_KEY, (int) 'C');
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
}
@Override
public void actionPerformed(ActionEvent e) {
cancel();
}
public void cancel() {
getCurrentPage().performCancel();
close();
}
}
private class HelpAction extends AbstractAction {
private HelpAction() {
super("Help");
putValue(ACTION_COMMAND_KEY, "Help");
putValue(MNEMONIC_KEY, (int) 'H');
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_HELP, 0));
}
@Override
public void actionPerformed(ActionEvent e) {
getCurrentPage().performHelp();
}
}
}