IDEA-129108 (wizard step added)
[idea/community.git] / platform / platform-impl / src / com / intellij / ide / customize / CustomizeIDEWizardDialog.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.ide.customize;
17
18 import com.intellij.ide.startup.StartupActionScriptManager;
19 import com.intellij.idea.Main;
20 import com.intellij.openapi.application.ApplicationNamesInfo;
21 import com.intellij.openapi.ui.DialogWrapper;
22 import com.intellij.openapi.util.SystemInfo;
23 import com.intellij.ui.JBCardLayout;
24 import com.intellij.util.PlatformUtils;
25 import org.jetbrains.annotations.Nullable;
26
27 import javax.swing.*;
28 import java.awt.*;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.ActionListener;
31 import java.util.ArrayList;
32 import java.util.List;
33
34 public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionListener {
35   private static final String BUTTONS = "BUTTONS";
36   private static final String NOBUTTONS = "NOBUTTONS";
37   private final JButton mySkipButton = new JButton("Skip All and Set Defaults");
38   private final JButton myBackButton = new JButton("Back");
39   private final JButton myNextButton = new JButton("Next");
40
41   private final JBCardLayout myCardLayout = new JBCardLayout();
42   protected final List<AbstractCustomizeWizardStep> mySteps = new ArrayList<AbstractCustomizeWizardStep>();
43   private int myIndex = 0;
44   private final JLabel myNavigationLabel = new JLabel();
45   private final JLabel myHeaderLabel = new JLabel();
46   private final JLabel myFooterLabel = new JLabel();
47   private final CardLayout myButtonWrapperLayout = new CardLayout();
48   private final JPanel myButtonWrapper = new JPanel(myButtonWrapperLayout);
49   private JPanel myContentPanel;
50
51   public CustomizeIDEWizardDialog() {
52     super(null, true, true);
53     setTitle("Customize " + ApplicationNamesInfo.getInstance().getProductName());
54     getPeer().setAppIcons();
55     initSteps();
56     mySkipButton.addActionListener(this);
57     myBackButton.addActionListener(this);
58     myNextButton.addActionListener(this);
59     myNavigationLabel.setEnabled(false);
60     myFooterLabel.setEnabled(false);
61     init();
62     initCurrentStep(true);
63     setSize(400, 300);
64     System.setProperty(StartupActionScriptManager.STARTUP_WIZARD_MODE, "true");
65   }
66
67   public static void showCustomSteps(String stepsProviderName) {
68     final CustomizeIDEWizardStepsProvider provider;
69
70     try {
71       Class<CustomizeIDEWizardStepsProvider> providerClass = (Class<CustomizeIDEWizardStepsProvider>)Class.forName(stepsProviderName);
72       provider = providerClass.newInstance();
73     }
74     catch (Throwable e) {
75       Main.showMessage("Start Failed", e);
76       return;
77     }
78
79     new CustomizeIDEWizardDialog() {
80       @Override
81       protected void initSteps() {
82         provider.initSteps(this, mySteps);
83       }
84     }.show();
85   }
86
87   @Override
88   protected void dispose() {
89     System.clearProperty(StartupActionScriptManager.STARTUP_WIZARD_MODE);
90     super.dispose();
91   }
92
93   protected void initSteps() {
94     mySteps.add(new CustomizeUIThemeStepPanel());
95     if (SystemInfo.isMac) {
96       mySteps.add(new CustomizeKeyboardSchemeStepPanel());
97     }
98     if (CustomizeDesktopEntryStep.isAvailable()) {
99       mySteps.add(new CustomizeDesktopEntryStep("/UbuntuDesktopEntry.png"));
100     }
101
102     PluginGroups pluginGroups = new PluginGroups();
103     mySteps.add(new CustomizePluginsStepPanel(pluginGroups));
104     try {
105       mySteps.add(new CustomizeFeaturedPluginsStepPanel(pluginGroups));
106     }
107     catch (CustomizeFeaturedPluginsStepPanel.OfflineException e) {
108       //skip featured step if we're offline
109     }
110   }
111
112   @Override
113   protected JComponent createCenterPanel() {
114     JPanel result = new JPanel(new BorderLayout(5, 5));
115     myContentPanel = new JPanel(myCardLayout);
116     for (AbstractCustomizeWizardStep step : mySteps) {
117       myContentPanel.add(step, step.getTitle());
118     }
119     JPanel topPanel = new JPanel(new BorderLayout(5, 5));
120     topPanel.add(myNavigationLabel, BorderLayout.NORTH);
121     topPanel.add(myHeaderLabel, BorderLayout.CENTER);
122     result.add(topPanel, BorderLayout.NORTH);
123     result.add(myContentPanel, BorderLayout.CENTER);
124     result.add(myFooterLabel, BorderLayout.SOUTH);
125     result.setPreferredSize(new Dimension(700, 600));
126     result.setBorder(AbstractCustomizeWizardStep.createSmallEmptyBorder());
127     return result;
128   }
129
130   @Override
131   protected JComponent createSouthPanel() {
132     final JPanel buttonPanel = new JPanel(new GridBagLayout());
133     GridBagConstraints gbc = new GridBagConstraints();
134     gbc.insets.right = 5;
135     gbc.fill = GridBagConstraints.BOTH;
136     gbc.gridx = 0;
137     gbc.gridy = 0;
138     if (!PlatformUtils.isCLion()) {
139       buttonPanel.add(mySkipButton, gbc);
140       gbc.gridx++;
141     }
142     buttonPanel.add(myBackButton, gbc);
143     gbc.gridx++;
144     gbc.weightx = 1;
145     buttonPanel.add(Box.createHorizontalGlue(), gbc);
146     gbc.gridx++;
147     gbc.weightx = 0;
148     buttonPanel.add(myNextButton, gbc);
149     buttonPanel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0));
150     myButtonWrapper.add(buttonPanel, BUTTONS);
151     myButtonWrapper.add(new JLabel(), NOBUTTONS);
152     myButtonWrapperLayout.show(myButtonWrapper, BUTTONS);
153     return myButtonWrapper;
154   }
155
156   void setButtonsVisible(boolean visible) {
157     myButtonWrapperLayout.show(myButtonWrapper, visible ? BUTTONS : NOBUTTONS);
158   }
159
160   @Override
161   public void actionPerformed(ActionEvent e) {
162     if (e.getSource() == mySkipButton) {
163       doOKAction();
164       return;
165     }
166     if (e.getSource() == myBackButton) {
167       myIndex--;
168       initCurrentStep(false);
169       return;
170     }
171     if (e.getSource() == myNextButton) {
172       if (myIndex >= mySteps.size() - 1) {
173         doOKAction();
174         return;
175       }
176       myIndex++;
177       initCurrentStep(true);
178     }
179   }
180
181   @Nullable
182   @Override
183   protected ActionListener createCancelAction() {
184     return null;//Prevent closing by <Esc>
185   }
186
187   @Override
188   public void doCancelAction() {
189     doOKAction();
190   }
191
192   @Override
193   protected void doOKAction() {
194     for (AbstractCustomizeWizardStep step : mySteps) {
195       if (!step.beforeOkAction()) {
196         int index = mySteps.indexOf(step);
197         if (myIndex != index) {
198           myIndex = index;
199           initCurrentStep(true);
200         }
201         return;
202       }
203     }
204     super.doOKAction();
205   }
206
207   private void initCurrentStep(boolean forward) {
208     final AbstractCustomizeWizardStep myCurrentStep = mySteps.get(myIndex);
209     myCurrentStep.beforeShown(forward);
210     myCardLayout.swipe(myContentPanel, myCurrentStep.getTitle(), JBCardLayout.SwipeDirection.AUTO, new Runnable() {
211       @Override
212       public void run() {
213         Component component = myCurrentStep.getDefaultFocusedComponent();
214         if (component != null) {
215           component.requestFocus();
216         }
217       }
218     });
219
220     myBackButton.setVisible(myIndex > 0);
221     if (myIndex > 0) {
222       myBackButton.setText("Back to " + mySteps.get(myIndex - 1).getTitle());
223     }
224     mySkipButton.setText("Skip " + (myIndex > 0 ? "Remaining" : "All") + " and Set Defaults");
225
226     myNextButton.setText(myIndex < mySteps.size() - 1
227                          ? "Next: " + mySteps.get(myIndex + 1).getTitle()
228                          : "Start using " + ApplicationNamesInfo.getInstance().getFullProductName());
229     myHeaderLabel.setText(myCurrentStep.getHTMLHeader());
230     myFooterLabel.setText(myCurrentStep.getHTMLFooter());
231     StringBuilder navHTML = new StringBuilder("<html><body>");
232     for (int i = 0; i < mySteps.size(); i++) {
233       if (i > 0) navHTML.append("&nbsp;&#8594;&nbsp;");
234       if (i == myIndex) navHTML.append("<b>");
235       navHTML.append(mySteps.get(i).getTitle());
236       if (i == myIndex) navHTML.append("</b>");
237     }
238     myNavigationLabel.setText(navHTML.toString());
239   }
240 }