com.intellij.ide.wizard.AbstractWizard.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.ide.wizard.AbstractWizard.java

Source

/*
 * Copyright 2000-2011 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.ide.wizard;

import com.intellij.CommonBundle;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.components.panels.OpaquePanel;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.UiNotifyConnector;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public abstract class AbstractWizard<T extends Step> extends DialogWrapper {
    private static final Logger LOG = Logger.getInstance("#com.intellij.ide.wizard.AbstractWizard");

    protected int myCurrentStep;
    protected final ArrayList<T> mySteps;
    private JButton myPreviousButton;
    private JButton myNextButton;
    private JButton myCancelButton;
    private JButton myHelpButton;
    protected JPanel myContentPanel;
    protected TallImageComponent myIcon;
    private Component myCurrentStepComponent;
    private final Map<Component, String> myComponentToIdMap = new HashMap<Component, String>();
    private final StepListener myStepListener = new StepListener() {
        public void stateChanged() {
            updateStep();
        }
    };

    public AbstractWizard(final String title, final Component dialogParent) {
        super(dialogParent, true);
        mySteps = new ArrayList<T>();
        initWizard(title);
    }

    public AbstractWizard(final String title, @Nullable final Project project) {
        super(project, true);
        mySteps = new ArrayList<T>();
        initWizard(title);
    }

    private void initWizard(final String title) {
        setTitle(title);
        myCurrentStep = 0;
        myPreviousButton = new JButton(IdeBundle.message("button.wizard.previous"));
        myNextButton = new JButton(IdeBundle.message("button.wizard.next"));
        myCancelButton = new JButton(CommonBundle.getCancelButtonText());
        myHelpButton = new JButton(CommonBundle.getHelpButtonText());
        myContentPanel = new JPanel(new CardLayout());

        myIcon = new TallImageComponent(null);

        JRootPane rootPane = getRootPane();
        if (rootPane != null) { // it will be null in headless mode, i.e. tests
            rootPane.registerKeyboardAction(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    helpAction();
                }
            }, KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);

            rootPane.registerKeyboardAction(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    helpAction();
                }
            }, KeyStroke.getKeyStroke(KeyEvent.VK_HELP, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
        }
    }

    protected JComponent createSouthPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0));

        JPanel buttonPanel = new JPanel();

        if (SystemInfo.isMac) {
            panel.add(buttonPanel, BorderLayout.EAST);
            buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));

            if (!UIUtil.isUnderDarcula()) {
                myHelpButton.putClientProperty("JButton.buttonType", "help");
            }
            if (UIUtil.isUnderAquaLookAndFeel()) {
                myHelpButton.setText("");
            }

            JPanel leftPanel = new JPanel();
            if (ApplicationInfo.contextHelpAvailable()) {
                leftPanel.add(myHelpButton);
            }
            leftPanel.add(myCancelButton);
            panel.add(leftPanel, BorderLayout.WEST);

            if (mySteps.size() > 1) {
                buttonPanel.add(Box.createHorizontalStrut(5));
                buttonPanel.add(myPreviousButton);
            }
            buttonPanel.add(Box.createHorizontalStrut(5));
            buttonPanel.add(myNextButton);
        } else {
            panel.add(buttonPanel, BorderLayout.CENTER);
            GroupLayout layout = new GroupLayout(buttonPanel);
            buttonPanel.setLayout(layout);
            layout.setAutoCreateGaps(true);

            final GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
            final GroupLayout.ParallelGroup vGroup = layout.createParallelGroup();
            final Collection<Component> buttons = ContainerUtil.newArrayListWithCapacity(5);
            final boolean helpAvailable = ApplicationInfo.contextHelpAvailable();

            if (helpAvailable && UIUtil.isUnderGTKLookAndFeel()) {
                add(hGroup, vGroup, buttons, myHelpButton);
            }
            add(hGroup, vGroup, null, Box.createHorizontalGlue());
            if (mySteps.size() > 1) {
                add(hGroup, vGroup, buttons, myPreviousButton);
            }
            add(hGroup, vGroup, buttons, myNextButton, myCancelButton);
            if (helpAvailable && !UIUtil.isUnderGTKLookAndFeel()) {
                add(hGroup, vGroup, buttons, myHelpButton);
            }

            layout.setHorizontalGroup(hGroup);
            layout.setVerticalGroup(vGroup);
            layout.linkSize(buttons.toArray(new Component[buttons.size()]));
        }

        myPreviousButton.setEnabled(false);
        myPreviousButton.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                doPreviousAction();
            }
        });
        myNextButton.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (isLastStep()) {
                    // Commit data of current step and perform OK action
                    final Step currentStep = mySteps.get(myCurrentStep);
                    LOG.assertTrue(currentStep != null);
                    try {
                        currentStep._commit(true);
                        doOKAction();
                    } catch (final CommitStepException exc) {
                        String message = exc.getMessage();
                        if (message != null) {
                            Messages.showErrorDialog(myContentPanel, message);
                        }
                    }
                } else {
                    doNextAction();
                }
            }
        });

        myCancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                doCancelAction();
            }
        });
        myHelpButton.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                helpAction();
            }
        });

        return panel;
    }

    private static void add(final GroupLayout.Group hGroup, final GroupLayout.Group vGroup,
            @Nullable final Collection<Component> collection, final Component... components) {
        for (Component component : components) {
            hGroup.addComponent(component);
            vGroup.addComponent(component);
            if (collection != null)
                collection.add(component);
        }
    }

    public static class TallImageComponent extends OpaquePanel {
        private Icon myIcon;

        private TallImageComponent(Icon icon) {
            myIcon = icon;
        }

        @Override
        protected void paintChildren(Graphics g) {
            if (myIcon == null)
                return;

            paintIcon(g);
        }

        public void paintIcon(Graphics g) {
            final BufferedImage image = UIUtil.createImage(myIcon.getIconWidth(), myIcon.getIconHeight(),
                    BufferedImage.TYPE_INT_ARGB);
            final Graphics2D gg = image.createGraphics();
            myIcon.paintIcon(this, gg, 0, 0);

            final Rectangle bounds = g.getClipBounds();
            int y = myIcon.getIconHeight() - 1;
            while (y < bounds.y + bounds.height) {
                g.drawImage(image, bounds.x, y, bounds.x + bounds.width, y + 1, 0, myIcon.getIconHeight() - 1,
                        bounds.width, myIcon.getIconHeight(), this);

                y++;
            }

            g.drawImage(image, 0, 0, this);
        }

        public void setIcon(Icon icon) {
            myIcon = icon;
            revalidate();
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(myIcon != null ? myIcon.getIconWidth() : 0, 0);
        }

        @Override
        public Dimension getMinimumSize() {
            return new Dimension(myIcon != null ? myIcon.getIconWidth() : 0, 0);
        }
    }

    protected JComponent createCenterPanel() {
        final JPanel iconPanel = new JPanel(new BorderLayout());
        iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 8));
        iconPanel.add(myIcon, BorderLayout.CENTER);

        final JPanel panel = new JPanel(new BorderLayout());
        panel.add(iconPanel, BorderLayout.WEST);
        panel.add(myContentPanel, BorderLayout.CENTER);
        return panel;
    }

    public int getCurrentStep() {
        return myCurrentStep;
    }

    public int getStepCount() {
        return mySteps.size();
    }

    public T getCurrentStepObject() {
        return mySteps.get(myCurrentStep);
    }

    public void addStep(@NotNull final T step) {
        mySteps.add(step);

        if (step instanceof StepAdapter) {
            ((StepAdapter) step).registerStepListener(myStepListener);
        }
        // card layout is used
        final Component component = step.getComponent();
        if (component != null) {
            addStepComponent(component);
        }
    }

    protected void init() {
        super.init();
        updateStep();
    }

    protected String addStepComponent(final Component component) {
        String id = myComponentToIdMap.get(component);
        if (id == null) {
            id = Integer.toString(myComponentToIdMap.size());
            myComponentToIdMap.put(component, id);
            myContentPanel.add(component, id);
        }
        return id;
    }

    private void showStepComponent(final Component component) {
        String id = myComponentToIdMap.get(component);
        if (id == null) {
            id = addStepComponent(component);
            myContentPanel.revalidate();
            myContentPanel.repaint();
        }
        ((CardLayout) myContentPanel.getLayout()).show(myContentPanel, id);
    }

    protected void doPreviousAction() {
        // Commit data of current step
        final Step currentStep = mySteps.get(myCurrentStep);
        LOG.assertTrue(currentStep != null);
        try {
            currentStep._commit(false);
        } catch (final CommitStepException exc) {
            Messages.showErrorDialog(myContentPanel, exc.getMessage());
            return;
        }

        myCurrentStep = getPreviousStep(myCurrentStep);
        updateStep();
    }

    protected void doNextAction() {
        // Commit data of current step
        final Step currentStep = mySteps.get(myCurrentStep);
        LOG.assertTrue(currentStep != null);
        LOG.assertTrue(!isLastStep(), "steps: " + mySteps + " current: " + currentStep);
        try {
            currentStep._commit(false);
        } catch (final CommitStepException exc) {
            Messages.showErrorDialog(myContentPanel, exc.getMessage());
            return;
        }

        myCurrentStep = getNextStep(myCurrentStep);
        updateStep();
    }

    /**
     * override this to provide alternate step order
     * @param step index
     * @return the next step's index
     */
    protected int getNextStep(int step) {
        final int stepCount = mySteps.size();
        if (++step >= stepCount) {
            step = stepCount - 1;
        }
        return step;
    }

    protected final int getNextStep() {
        return getNextStep(getCurrentStep());
    }

    protected T getNextStepObject() {
        int step = getNextStep();
        return mySteps.get(step);
    }

    /**
     * override this to provide alternate step order
     * @param step index
     * @return the previous step's index
     */
    protected int getPreviousStep(int step) {
        if (--step < 0) {
            step = 0;
        }
        return step;
    }

    protected final int getPreviousStep() {
        return getPreviousStep(getCurrentStep());
    }

    protected void updateStep() {
        if (mySteps.isEmpty()) {
            return;
        }

        final Step step = mySteps.get(myCurrentStep);
        LOG.assertTrue(step != null);
        step._init();
        myCurrentStepComponent = step.getComponent();
        LOG.assertTrue(myCurrentStepComponent != null);
        showStepComponent(myCurrentStepComponent);

        myIcon.setIcon(step.getIcon());

        updateButtons();

        JComponent component = mySteps.get(getCurrentStep()).getPreferredFocusedComponent();
        requestFocusTo(component != null ? component : myNextButton);
    }

    private static void requestFocusTo(final JComponent component) {
        UiNotifyConnector.doWhenFirstShown(component, new Runnable() {
            @Override
            public void run() {
                final IdeFocusManager focusManager = IdeFocusManager.findInstanceByComponent(component);
                focusManager.requestFocus(component, false);
            }
        });
    }

    protected boolean canGoNext() {
        return true;
    }

    protected boolean canFinish() {
        return isLastStep() && canGoNext();
    }

    protected void updateButtons() {
        if (isLastStep()) {
            if (mySteps.size() > 1) {
                myNextButton.setText(UIUtil.removeMnemonic(IdeBundle.message("button.finish")));
                myNextButton.setMnemonic('F');
            } else {
                myNextButton.setText(IdeBundle.message("button.ok"));
            }
            myNextButton.setEnabled(canFinish());
        } else {
            myNextButton.setText(UIUtil.removeMnemonic(IdeBundle.message("button.wizard.next")));
            myNextButton.setMnemonic('N');
            myNextButton.setEnabled(canGoNext());
        }

        if (myNextButton.isEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
            getRootPane().setDefaultButton(myNextButton);
        }

        myPreviousButton.setEnabled(myCurrentStep > 0);
    }

    protected boolean isLastStep() {
        return myCurrentStep == mySteps.size() - 1 || getCurrentStep() == getNextStep(getCurrentStep());
    }

    protected JButton getNextButton() {
        return myNextButton;
    }

    protected JButton getPreviousButton() {
        return myPreviousButton;
    }

    protected JButton getHelpButton() {
        return myHelpButton;
    }

    public JButton getCancelButton() {
        return myCancelButton;
    }

    @Deprecated
    protected JButton getFinishButton() {
        return new JButton();
    }

    public Component getCurrentStepComponent() {
        return myCurrentStepComponent;
    }

    protected void helpAction() {
        HelpManager.getInstance().invokeHelp(getHelpID());
    }

    @Override
    protected void doHelpAction() {
        HelpManager.getInstance().invokeHelp(getHelpID());
    }

    protected int getNumberOfSteps() {
        return mySteps.size();
    }

    @Nullable
    @NonNls
    protected abstract String getHelpID();
}