package org.docear.plugin.core.ui.wizard; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.awt.Point; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import javax.swing.AbstractButton; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.JSeparator; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import org.freeplane.core.ui.components.UITools; import org.freeplane.core.util.TextUtils; import com.jgoodies.forms.layout.ColumnSpec; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.RowSpec; /*** * * @author genzmehr@docear.org * * @see http://www.oracle.com/technetwork/articles/javase/wizard-136789.html <br>http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html */ public class Wizard { public static final WizardPageDescriptor FINISH_PAGE; static { FINISH_PAGE = new WizardPageDescriptor("_WIZARD_FINISH_WIZARD_", null); } private static final int NOT_DEFINED = -1; public static final int CANCEL_OPTION = 0; public static final int OK_OPTION = 1; public static final int SKIP_OPTION = 2; private WizardModel wizardModel; private WizardController wizardController; private JDialog wizard; private JPanel cardPanel; private JPanel buttonPanel; private CardLayout cardLayout; private JButton backButton; private JButton skipButton; private JButton nextButton; private JButton cancelButton; private JButton closeButton; private volatile int returnCode = NOT_DEFINED; private Thread returnCodeObserver; private WizardSession context; private boolean cancelEnabled = true; private boolean cancelButtonEnabled = false; private boolean skipEnabled = false; private boolean drawButtonBarSeparator = false; private JEditorPane titleComponent; private WizardPageDescriptor startPageIdentifier; private boolean isResizable; private IPageKeyBindingProcessor pageKeyBindingProcessor; /*********************************************************************************** * CONSTRUCTORS **********************************************************************************/ public Wizard(Window owner) { wizardModel = new WizardModel(); wizard = new JDialog(owner); wizardController = new WizardController(this); wizard.setModal(true); wizard.setUndecorated(true); wizard.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG); initReturnCodeObserver(); initComponents(); } /*********************************************************************************** * METHODS **********************************************************************************/ public void registerWizardPanel(WizardPageDescriptor page) { cardPanel.add(page.getPage(), page.getIdentifier()); wizardModel.registerPage(page.getIdentifier(), page); } public void setCurrentPage(Object id) { if(id == null) { throw new IllegalArgumentException("NULL"); } if(FINISH_PAGE.getIdentifier().equals(id)) { finish(); return; } resetControls(); WizardPageDescriptor oldPageDescriptor = wizardModel.getCurrentPageDescriptor(); if (oldPageDescriptor != null) { oldPageDescriptor.aboutToHidePage(getSession()); } wizardModel.setCurrentPage(id); wizardModel.getCurrentPageDescriptor().aboutToDisplayPage(getSession()); if(wizardModel.getCurrentPageDescriptor().getPage().isPageDisplayable()) { this.pageKeyBindingProcessor = wizardModel.getCurrentPageDescriptor().getKeyBindingProcessor(); cardLayout.show(cardPanel, id.toString()); wizardModel.getCurrentPageDescriptor().displayingPage(getSession()); if(wizardModel.getCurrentPageDescriptor().resizeWizard()) { wizard.pack(); } } else { nextButton.doClick(); } } public void setCancelEnabled(boolean enabled) { this.cancelEnabled = enabled; } public boolean isCancelEnabled() { return cancelEnabled; } public void setSkipEnabled(boolean enabled) { this.skipEnabled = enabled; } public boolean isSkipEnabled() { return skipEnabled; } public void setCancelButtonEnabled(boolean enabled) { this.cancelButtonEnabled = enabled; } public boolean isCancelButtonEnabled() { return cancelButtonEnabled; } public boolean isCancelControl(Object source) { if((closeButton != null && closeButton.equals(source)) || (cancelButton != null && cancelButton.equals(source))) { return true; } return false; } public void setEnableButtonBarSeparator(boolean enabled) { drawButtonBarSeparator = enabled; } public boolean isButtonBarSeparatorEnabled() { return drawButtonBarSeparator; } public WizardSession getSession() { if(context == null) { context = new WizardSession() { @Override public WizardPageDescriptor getCurrentDescriptor() { return wizardModel.getCurrentPageDescriptor(); } @Override public WizardModel getModel() { return wizardModel; } @Override public AbstractButton getNextButton() { return nextButton; } @Override public AbstractButton getBackButton() { return backButton; } @Override public AbstractButton getSkipButton() { return skipButton; } @Override public void setWizardTitle(String title) { setTitle(title); } @Override public void gotoPage(String identifier) { Wizard.this.setCurrentPage(identifier); } @Override public void finish() { Wizard.this.finish(); } @Override public void cancel() { Wizard.this.cancel(); } }; } return context; } public void setStartPage(Object identifier) { this.startPageIdentifier = wizardModel.getPage(identifier); } public void setResizable(boolean b) { this.isResizable = b; } public boolean isResizable() { return this.isResizable; } public WizardPageDescriptor getStartPage() { if(this.startPageIdentifier == null) { return wizardModel.getFirstPage(); } return this.startPageIdentifier; } public synchronized int show() { returnCode = NOT_DEFINED; returnCodeObserver.start(); wizard.setMinimumSize(new Dimension(150, 150)); wizard.setSize(640, 480); resetControls(); if(getStartPage() != null) { setCurrentPage(getStartPage().getIdentifier()); } SwingUtilities.updateComponentTreeUI(wizard); wizard.pack(); centerOnOwner(wizard); wizard.toFront(); wizard.setVisible(true); Window.getWindows(); wizard.toFront(); try { returnCodeObserver.join(); } catch (InterruptedException e) { } wizard.setVisible(false); wizard.dispose(); return returnCode; } public void setTitle(String title) { titleComponent.setText(title); } public String getTitle() { return titleComponent.getText(); } public void cancel() { if(NOT_DEFINED == returnCode) { returnCode = CANCEL_OPTION; wizard.dispatchEvent(new WindowEvent(wizard, WindowEvent.WINDOW_CLOSING)); } } public void finish() { if(NOT_DEFINED == returnCode) { returnCode = OK_OPTION; wizard.dispatchEvent(new WindowEvent(wizard, WindowEvent.WINDOW_CLOSING)); } } public void skipAll() { if(NOT_DEFINED == returnCode) { returnCode = SKIP_OPTION; wizard.dispatchEvent(new WindowEvent(wizard, WindowEvent.WINDOW_CLOSING)); } } private boolean processPageKeyBindings(KeyStroke ks, KeyEvent e, boolean pressed) { if(this.pageKeyBindingProcessor != null) { return pageKeyBindingProcessor.processKeyEvent(e); } return false; } private void initComponents() { WizardMouseAdapter mAdapter = new WizardMouseAdapter(this); final JPanel mainPanel = new JPanel(true) { private static final long serialVersionUID = 1L; @Override protected boolean processKeyBinding(final KeyStroke ks, final KeyEvent e, final int condition, final boolean pressed) { if(!processPageKeyBindings(ks, e, pressed)) { return super.processKeyBinding(ks, e, condition, pressed); } return true; } }; JPanel contentPanel = new JPanel(); final JPanel headPanel = new JPanel(); JPanel headControls = new JPanel(); final JPanel titlePanel = new JPanel(); titleComponent = new JEditorPane(); titleComponent.setBackground(Color.WHITE); final LineBorder lineBorder = new LineBorder(new Color(0,0,0,196), 1); buttonPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); mainPanel.setBackground(Color.WHITE); //mainPanel.setBorder(lineBorder); mainPanel.setBorder(new CompoundBorder( new CompoundBorder( new CompoundBorder( new CompoundBorder(new LineBorder(new Color(0x10000000, true), 1),new LineBorder(new Color(0x20000000, true), 1)),new LineBorder(new Color(0x30000000, true), 1)),new LineBorder(new Color(0x40000000, true), 1)) , lineBorder)); headPanel.setLayout(new BorderLayout()); headPanel.setBackground(Color.WHITE); headPanel.setPreferredSize(new Dimension(0, 60)); headPanel.setBorder(new EmptyBorder(0, 10, 5, 10)); headPanel.addMouseMotionListener(mAdapter); headPanel.addMouseListener(mAdapter); closeButton = new JButton(new ImageIcon(Wizard.class.getResource("/images/window-close.png"))); closeButton.setPreferredSize(new Dimension(35, 25)); closeButton.setMargin(new Insets(10, 10, 7, 10)); headControls.setLayout(new BorderLayout()); headControls.setBorder(new EmptyBorder(-6, 0, 0, 0)); headControls.setBackground(Color.WHITE); headControls.add(closeButton, BorderLayout.NORTH); titlePanel.setBackground(Color.WHITE); titlePanel.setBorder(null); titlePanel.addMouseMotionListener(mAdapter); titlePanel.addMouseListener(mAdapter); titlePanel.setLayout(new FormLayout(new ColumnSpec[] { ColumnSpec.decode("388px:grow"),}, new RowSpec[] { RowSpec.decode("50px:grow"),})); titleComponent.setEditable(false); titleComponent.setFont(titleComponent.getFont().deriveFont(Font.BOLD, 14f)); titleComponent.addMouseMotionListener(mAdapter); titleComponent.addMouseListener(mAdapter); titlePanel.add(titleComponent, "1, 1, fill, center"); mAdapter.addComponentDragListener(new ComponentDragListener() { @Override public void componentDragged(ComponentDragEvent event) { if(event.getComponent() == titleComponent || event.getComponent() == headPanel || event.getComponent() == titlePanel ) { Point nuPoint = wizard.getLocation(); nuPoint.x += event.deltaX; nuPoint.y += event.deltaY; wizard.setLocation(nuPoint); event.consume(); } } public void componentAdjustResizeCursor(AdjustResizeCursorEvent event) { } }); headPanel.add(headControls, BorderLayout.EAST); headPanel.add(titlePanel, BorderLayout.CENTER); contentPanel.setLayout(new BorderLayout()); contentPanel.setBackground(Color.WHITE); contentPanel.setBorder(new CompoundBorder(new EmptyBorder(new Insets(0, 10, 10, 10)), lineBorder)); buttonPanel.setLayout(new BorderLayout()); buttonPanel.setBackground(Color.WHITE); cardPanel = new JPanel(); cardPanel.setBorder(new EmptyBorder(new Insets(5, 10, 5, 10))); cardPanel.setBackground(Color.WHITE); cardLayout = new CardLayout(); cardPanel.setLayout(cardLayout); backButton = new JButton("back"); backButton.setBackground(Color.WHITE); nextButton = new JButton("next"); nextButton.setBackground(Color.WHITE); skipButton = new JButton("skip"); skipButton.setBackground(Color.WHITE); cancelButton = new JButton("cancel"); cancelButton.setBackground(Color.WHITE); backButton.addActionListener(wizardController); nextButton.addActionListener(wizardController); skipButton.addActionListener(wizardController); cancelButton.addActionListener(wizardController); closeButton.addActionListener(wizardController); buildButtonBar(); wizard.getContentPane().add(mainPanel, BorderLayout.CENTER); mainPanel.add(headPanel, BorderLayout.NORTH); mainPanel.add(contentPanel, BorderLayout.CENTER); contentPanel.add(cardPanel, BorderLayout.CENTER); contentPanel.add(buttonPanel, BorderLayout.SOUTH); mainPanel.addMouseListener(mAdapter); mainPanel.addMouseMotionListener(mAdapter); mAdapter.addComponentDragListener(new ComponentDragListener() { @Override public void componentDragged(ComponentDragEvent event) { if(event.getComponent() == mainPanel) { if(isResizable() && event.isResizeEvent()) { Dimension pageDim = wizardModel.getCurrentPageDescriptor().getPage().getPreferredSize(); Dimension cardDim = cardPanel.getPreferredSize(); Dimension wizardDim = wizard.getPreferredSize(); if(event.resizeDirection(ComponentDragEvent.DIRECTION_HORIZONTAL)) { pageDim.width += event.deltaX; cardDim.width += event.deltaX; wizardDim.width += event.deltaX; } if(event.resizeDirection(ComponentDragEvent.DIRECTION_VERTICAL)) { pageDim.height += event.deltaY; cardDim.height += event.deltaY; wizardDim.height += event.deltaY; } wizardModel.getCurrentPageDescriptor().getPage().setPreferredSize(pageDim); cardPanel.setPreferredSize(cardDim); wizard.setPreferredSize(wizardDim); wizard.pack(); event.consume(); } } } @Override public void componentAdjustResizeCursor(AdjustResizeCursorEvent event) { if(event.getComponent() == mainPanel) { adjustCursor(mainPanel, event.getResizeSensor()); } } }); } private void adjustCursor(Component component, int resizeSensor) { if((resizeSensor & WizardMouseAdapter.BORDER_LEFT) > 0) { if((resizeSensor & WizardMouseAdapter.BORDER_TOP) > 0) { component.setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)); } else if((resizeSensor & WizardMouseAdapter.BORDER_BOTTOM) > 0) { component.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)); } else { component.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); } } else if((resizeSensor & WizardMouseAdapter.BORDER_RIGHT) > 0) { if((resizeSensor & WizardMouseAdapter.BORDER_TOP) > 0) { component.setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)); } else if((resizeSensor & WizardMouseAdapter.BORDER_BOTTOM) > 0) { component.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)); } else { component.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); } } else if((resizeSensor & WizardMouseAdapter.BORDER_TOP) > 0) { component.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); } else if((resizeSensor & WizardMouseAdapter.BORDER_BOTTOM) > 0) { component.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); } else { component.setCursor(Cursor.getDefaultCursor()); } } private void buildButtonBar() { buttonPanel.removeAll(); if(isButtonBarSeparatorEnabled()) { buttonPanel.add(new JSeparator(), BorderLayout.NORTH); } Box buttonBox = new Box(BoxLayout.X_AXIS); buttonBox.setBorder(new EmptyBorder(new Insets(5, 10, 5, 10))); buttonBox.add(skipButton); buttonBox.add(Box.createHorizontalStrut(10)); buttonBox.add(backButton); buttonBox.add(Box.createHorizontalStrut(10)); buttonBox.add(nextButton); if(isCancelButtonEnabled()) { buttonBox.add(Box.createHorizontalStrut(30)); buttonBox.add(cancelButton); } buttonPanel.add(buttonBox, java.awt.BorderLayout.EAST); } private void centerOnOwner(JDialog dialog) { Dimension dim; Point loc; if(dialog.getOwner() == null) { dim = Toolkit.getDefaultToolkit().getScreenSize(); loc = new Point(0, 0); } else { dim = dialog.getOwner().getSize(); loc = dialog.getOwner().getLocation(); } int x = loc.x + ((dim.width/2)-(dialog.getWidth()/2)); int y = loc.y + ((dim.height/2)-(dialog.getHeight()/2)); dialog.setLocation(x, y); } private void initReturnCodeObserver() { if(returnCodeObserver == null) { Runnable observer = new Runnable() { @Override public void run() { try { while(returnCode == NOT_DEFINED) { Thread.sleep(50); Thread.yield(); } } catch (InterruptedException e) { returnCode = CANCEL_OPTION; } } }; returnCodeObserver = new Thread(observer); } } public void resetControls() { if(nextButton != null) { nextButton.setVisible(true); nextButton.setEnabled(true); nextButton.setText(TextUtils.getText("docear.setup.wizard.controls.next")); nextButton.setDefaultCapable(true); wizard.getRootPane().setDefaultButton(nextButton); } if(backButton != null) { backButton.setVisible(wizardModel.getPageCount() > 1); backButton.setEnabled(true); backButton.setText(TextUtils.getText("docear.setup.wizard.controls.back")); } if(skipButton != null) { skipButton.setVisible(isSkipEnabled()); skipButton.setEnabled(true); skipButton.setText(TextUtils.getText("docear.setup.wizard.controls.skip")); } closeButton.setVisible(isCancelEnabled()); } public static int showConfirmDialog(String message) { Wizard wiz = new Wizard(UITools.getFrame()); try { wiz.setResizable(true); wiz.registerWizardPanel(new ConfirmDialogPanel(message)); wiz.setCancelEnabled(true); return wiz.show(); } catch (Exception ignore) { } return CANCEL_OPTION; } static class ConfirmDialogPanel extends WizardPageDescriptor { //*********************************************************************************** // CONSTRUCTORS //*********************************************************************************** public ConfirmDialogPanel(final String message) { super("confirm_page", new AWizardPage() { private static final long serialVersionUID = 1L; private boolean initialized = false; @Override public void preparePage(WizardSession session) { if(!initialized) { this.setLayout(new BorderLayout()); this.setBackground(Color.WHITE); this.add(new JLabel(message), BorderLayout.CENTER); } session.setWizardTitle(getTitle()); session.getBackButton().setEnabled(true); session.getBackButton().setVisible(true); session.getNextButton().setEnabled(true); session.getBackButton().setText(TextUtils.getText("wizard.dialog.default.confirm.back.text")); session.getNextButton().setText(TextUtils.getText("wizard.dialog.default.confirm.next.text")); } @Override public String getTitle() { return TextUtils.getText("wizard.dialog.default.confirm.title"); } }); } @Override public WizardPageDescriptor getNextPageDescriptor(WizardSession context) { context.finish(); return Wizard.FINISH_PAGE; } @Override public WizardPageDescriptor getBackPageDescriptor(WizardSession context) { context.cancel(); return Wizard.FINISH_PAGE; } //*********************************************************************************** // METHODS //*********************************************************************************** //*********************************************************************************** // REQUIRED METHODS FOR INTERFACES //*********************************************************************************** } }