/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.util.wizard; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.Image; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.MouseAdapter; import java.awt.event.MouseMotionAdapter; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Enumeration; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.UIManager; import javax.swing.WindowConstants; import javax.swing.border.BevelBorder; import javax.swing.border.Border; import com.servoy.j2db.Messages; import com.servoy.j2db.smart.J2DBClient; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.SwingHelper; import com.servoy.j2db.util.gui.FixedCardLayout; import com.servoy.j2db.util.gui.JDK131ProgressBar; import com.servoy.j2db.util.gui.JEscapeDialog; /** * Wizard swing display window * * @author jblok */ public abstract class WizardWindow implements IWizard { private static final String DIALOG_NAME = "WizardWindowDialog"; private int INITIAL_WIDTH = 800; private int INITIAL_HEIGHT = 600; public static final Font smallFont = new Font("SansSerif", Font.PLAIN, 10); //SansSerif //$NON-NLS-1$ private JLabel statusLabel; private JDK131ProgressBar statusProgessBar; private String title; // The GUI fields private HighlightJButton prevButton; // The previous button private HighlightJButton nextButton; // The next button private HighlightJButton quitButton; // The quit button private JPanel panelsContainer; private FixedCardLayout rolodex; protected IWizardState state; //needed for use in dialog and frame protected Window window; protected JRootPane rootPane; protected Container contentPane; public WizardWindow() { this(new Dimension(800, 600)); } public WizardWindow(Dimension size) { INITIAL_WIDTH = size.width; INITIAL_HEIGHT = size.height; createState(); } // Shows the frame public void showFrame(String title, Image windowIcon) throws Exception { this.title = title; window = new JFrame(); ((JFrame)window).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); if (windowIcon != null) ((JFrame)window).setIconImage(windowIcon); ((JFrame)window).setTitle(title); rootPane = ((JFrame)window).getRootPane(); contentPane = ((JFrame)window).getContentPane(); init(); SwingHelper.centerFrame(window); // ((JFrame)window).setResizable(false); window.setVisible(true); } // Shows the frame public void showDialog(String title, Dialog owner) throws Exception { window = new JEscapeDialog(owner, title, true) { @Override protected void cancel() { exit(); } }; window.setName(DIALOG_NAME); showDialogEx(owner); } // Shows the frame public void showDialog(String title, Frame owner) throws Exception { window = new JEscapeDialog(owner, title, true) { @Override protected void cancel() { exit(); } }; window.setName(DIALOG_NAME); showDialogEx(owner); } private void showDialogEx(Window owner) throws Exception { ((JDialog)window).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); rootPane = ((JDialog)window).getRootPane(); contentPane = ((JDialog)window).getContentPane(); init(); ((JDialog)window).setLocationRelativeTo(owner); // ((JDialog)window).setResizable(false); window.setVisible(true); } private void init() throws Exception { // Builds the GUI createPanels(); // Prepares the glass pane to block gui interaction when needed Component glassPane = rootPane.getGlassPane(); glassPane.addMouseListener(new MouseAdapter() { }); glassPane.addMouseMotionListener(new MouseMotionAdapter() { }); glassPane.addKeyListener(new KeyAdapter() { }); // We set the layout & prepare the constraint object contentPane.setLayout(new BorderLayout()); // We add the panels container panelsContainer = new JPanel(); rolodex = new FixedCardLayout(); panelsContainer.setLayout(rolodex); Enumeration e = state.getAllPanels(); while (e.hasMoreElements()) { JPanel panel = (JPanel)e.nextElement(); panelsContainer.add(panel, panel.getName()); //rolodex.addLayoutComponent(panel,panel.getName());//mag niet? //System.out.println("added "+panel.getName()); } // JScrollPane scroller = new JScrollPane(panelsContainer, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); // scroller.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); contentPane.add(panelsContainer, BorderLayout.CENTER); //scroller // We add the navigation buttons & labels NavigationHandler navHandler = new NavigationHandler(); prevButton = new HighlightJButton(Messages.getString("servoy.button.prev"), //$NON-NLS-1$ getImageIcon("stepback.gif"), //$NON-NLS-1$ Color.white); prevButton.addActionListener(navHandler); nextButton = new HighlightJButton(Messages.getString("servoy.button.next"), //$NON-NLS-1$ getImageIcon("stepforward.gif"), //$NON-NLS-1$ Color.white); nextButton.addActionListener(navHandler); quitButton = new HighlightJButton(Messages.getString("servoy.button.quit"), //$NON-NLS-1$ getImageIcon("stop.gif"), //$NON-NLS-1$ Color.white); quitButton.addActionListener(navHandler); JPanel down = new JPanel(); down.setLayout(new BorderLayout()); JPanel buttonPane = new JPanel(); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); buttonPane.add(prevButton); buttonPane.add(Box.createHorizontalGlue()); buttonPane.add(nextButton); buttonPane.add(Box.createRigidArea(new Dimension(J2DBClient.BUTTON_SPACING, 0))); buttonPane.add(quitButton); down.add(buttonPane, BorderLayout.CENTER); down.add(createStatusPanel(), BorderLayout.SOUTH); contentPane.add(down, BorderLayout.SOUTH); //show first switchPanel(true); // String panelName = state.getNextPanel().getName(); // rolodex.show(panelsContainer,panelName); // state.handleButtons(); rootPane.setDefaultButton(nextButton); window.pack(); window.setSize(INITIAL_WIDTH, INITIAL_HEIGHT); // Sets the window events handler window.addWindowListener(new WindowHandler(this)); } /** * The first panel must be called 'start' */ protected abstract void createPanels() throws Exception; /** * creates the defaultWizardState */ protected void createState() { if (state == null) { state = new WizardState(this); } } public IWizardState getState() { return state; } protected void addPanel(IWizardPanel panel) { state.addNewPanel(panel); } public abstract ImageIcon getImageIcon(String name); public Window getMainApplicationWindow() { return window; } // Switches the current panel public void switchPanel(boolean next) { if (next && !state.canProgress()) { Toolkit.getDefaultToolkit().beep(); return; } panelsContainer.setVisible(false); IWizardPanel panel; if (next) { panel = state.getNextPanel(); } else { panel = state.getPreviousPanel(); } rolodex.show(panelsContainer, panel.getName()); if (showPanelNameInTitle) { String name = panel.getName().toLowerCase(); ((JFrame)window).setTitle(title + " - (" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } state.handleButtons(); panelsContainer.setVisible(true); if (panel != null) { Runnable runnable = panel.needsToRunFirst(next); if (runnable != null) { //TODO: make thread pool? Thread th = new Thread(runnable, "runner"); //$NON-NLS-1$ th.setPriority(3);//below normal, UI is more important here. th.start(); } } } public boolean showPanelNameInTitle = false; public void showPanelNameInTitle(boolean b)//use full for debugging { showPanelNameInTitle = b; } // Makes a clean closing private void exit() { if (state.isFinished()) { window.setVisible(false); realExit(); window.dispose(); } else { int res = showCancelDialog(); if (res == JOptionPane.YES_OPTION) { window.setVisible(false); realExit(); window.dispose(); } } } /** * return of JOptionPane.YES_OPTION will couse call to realExit and delete window * * @return int */ protected int showCancelDialog() { int res = JOptionPane.showConfirmDialog(window, Messages.getString("servoy.wizardwindow.quiting.message"), //$NON-NLS-1$ Messages.getString("servoy.wizardwindow.quiting.title"), //$NON-NLS-1$ JOptionPane.YES_NO_OPTION); return res; } protected abstract void realExit(); // Blocks GUI interaction // always call this method with a finally block on releaseGUI! public void blockGUI(String reason) { semiBlockGUI(reason); setGlassPaneEnable(); } private void setGlassPaneEnable() { rootPane.getGlassPane().setVisible(true); rootPane.getGlassPane().setEnabled(true); } private void setGlassPaneDisable() { rootPane.getGlassPane().setEnabled(false); rootPane.getGlassPane().setVisible(false); } /** * Always call this method with a finally block in setInRelease it set the cursors on wait and sets the indeterminate property of progres bar on true; The * difference from blockGUI is that it doesnt set the glasspane on the window; */ public void semiBlockGUI(String reason) { statusLabel.setText(reason); // "Your report has been assigned an internal review ID of 1079568, which is NOT visible on the Sun Developer Network (SDN)." // NullPointerException in Sun VM - the synchronized block is a workaround synchronized (statusProgessBar.getTreeLock()) { statusProgessBar.setIndeterminate(true); } window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } /** * it set the cursors on normal and sets the indeterminate property of progres bar on false; */ public void semiReleaseGUI() { window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); // "Your report has been assigned an internal review ID of 1079568, which is NOT visible on the Sun Developer Network (SDN)." // NullPointerException in Sun VM - the synchronized block is a workaround synchronized (statusProgessBar.getTreeLock()) { statusProgessBar.setIndeterminate(false); } statusLabel.setText(Messages.getString("servoy.general.status.ready")); //$NON-NLS-1$ } // Releases GUI interaction public void releaseGUI() { setGlassPaneDisable(); semiReleaseGUI(); } // Locks the 'previous' button public void lockPrevButton() { prevButton.setEnabled(false); } // Locks the 'next' button public void lockNextButton() { nextButton.setEnabled(false); } // Unlocks the 'previous' button public void unlockPrevButton() { prevButton.setEnabled(true); } // Unlocks the 'next' button public void unlockNextButton() { nextButton.setEnabled(true); } public void lockFinishButton() { quitButton.setText(Messages.getString("servoy.button.cancel")); //$NON-NLS-1$ } public void unlockFinishButton() { quitButton.setText(Messages.getString("servoy.button.finish")); //$NON-NLS-1$ } //..................................................................... // Some event handler classes // Handles the events from the navigation bar elements class NavigationHandler implements ActionListener { public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == prevButton) { switchPanel(false); } else if (source == nextButton) { switchPanel(true); } else if (source == quitButton) { exit(); } } } public void doNext() { switchPanel(true); } // The window events handler private static class WindowHandler extends WindowAdapter { private final WizardWindow ww; public WindowHandler(WizardWindow ww) { this.ww = ww; } @Override public void windowClosing(WindowEvent e) { ww.exit(); } } protected JPanel createStatusPanel() { Color darkShadow = UIManager.getColor("controlShadow"); //$NON-NLS-1$ Color lightShadow = UIManager.getColor("controlLtHighlight"); //$NON-NLS-1$ JPanel status = new JPanel(); Border border = BorderFactory.createBevelBorder(BevelBorder.LOWERED, lightShadow, status.getBackground(), darkShadow, status.getBackground()); //set the status statusLabel = new JLabel(); // statusLabel.setFont(smallFont); statusLabel.setText(Messages.getString("servoy.general.status.ready")); //$NON-NLS-1$ statusLabel.setAlignmentX(Component.RIGHT_ALIGNMENT); statusLabel.setAlignmentY(Component.BOTTOM_ALIGNMENT); statusLabel.setBorder(BorderFactory.createCompoundBorder(border, BorderFactory.createEmptyBorder(0, 2, 0, 0)));//BorderFactory.createEtchedBorder()); statusLabel.setMinimumSize(new Dimension(100, 18)); statusLabel.setPreferredSize(new Dimension(4000, 18)); statusProgessBar = new JDK131ProgressBar(); statusProgessBar.setMaximumSize(new Dimension(100, 18)); statusProgessBar.setPreferredSize(new Dimension(100, 18)); statusProgessBar.setMinimumSize(new Dimension(100, 18)); statusProgessBar.setBorder(border);//BorderFactory.createEtchedBorder()); statusProgessBar.setStringPainted(false); statusProgessBar.setAlignmentX(Component.RIGHT_ALIGNMENT); statusProgessBar.setAlignmentY(Component.BOTTOM_ALIGNMENT); status.setLayout(new BoxLayout(status, BoxLayout.X_AXIS)); status.add(statusLabel); status.add(statusProgessBar); status.setBorder(BorderFactory.createEmptyBorder()); return status; } public void reportError(Component parentComponent, String msg, Exception ex) { Debug.error(msg); Debug.error(ex); } public void reportError(String msg, Exception ex) { Debug.error(msg); Debug.error(ex); } /** * @param string * @param currentWindow * @throws Exception */ public void showWindow(String title, Window w) throws Exception { if (w instanceof Dialog) { showDialog(title, (Dialog)w); } showDialog(title, (Frame)w); } }