replaced <code></code> with more concise {@code}
[idea/community.git] / platform / external-system-impl / src / com / intellij / openapi / externalSystem / service / settings / AbstractImportFromExternalSystemControl.java
1 /*
2  * Copyright 2000-2013 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.openapi.externalSystem.service.settings;
17
18 import com.intellij.ide.util.BrowseFilesListener;
19 import com.intellij.ide.util.projectWizard.NamePathComponent;
20 import com.intellij.ide.util.projectWizard.WizardContext;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.externalSystem.ExternalSystemManager;
23 import com.intellij.openapi.externalSystem.model.ProjectSystemId;
24 import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
25 import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
26 import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListener;
27 import com.intellij.openapi.externalSystem.util.*;
28 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
29 import com.intellij.openapi.options.ConfigurationException;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.text.StringUtil;
32 import com.intellij.projectImport.ProjectFormatPanel;
33 import com.intellij.ui.HideableTitledPanel;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
36
37 import javax.swing.*;
38 import javax.swing.event.DocumentEvent;
39 import javax.swing.event.DocumentListener;
40 import java.awt.*;
41
42 /**
43  * A control which knows how to manage settings of external project being imported.
44  * 
45  * @author Denis Zhdanov
46  * @since 4/30/13 2:33 PM
47  */
48 public abstract class AbstractImportFromExternalSystemControl<
49   ProjectSettings extends ExternalProjectSettings,
50   L extends ExternalSystemSettingsListener<ProjectSettings>,
51   SystemSettings extends AbstractExternalSystemSettings<SystemSettings, ProjectSettings, L>>
52 {
53   @NotNull private final SystemSettings  mySystemSettings;
54   @NotNull private final ProjectSettings myProjectSettings;
55
56   @NotNull private final PaintAwarePanel           myComponent              = new PaintAwarePanel(new GridBagLayout());
57   @NotNull private final NamePathComponent myLinkedProjectPathField;
58   @Nullable private final HideableTitledPanel hideableSystemSettingsPanel;
59   @NotNull private final ProjectFormatPanel myProjectFormatPanel;
60
61   @NotNull private final  ExternalSystemSettingsControl<ProjectSettings> myProjectSettingsControl;
62   @NotNull private final  ProjectSystemId                                myExternalSystemId;
63   @Nullable private final ExternalSystemSettingsControl<SystemSettings>  mySystemSettingsControl;
64
65   @Nullable Project myCurrentProject;
66
67   private boolean myShowProjectFormatPanel;
68   private final JLabel myProjectFormatLabel;
69
70   protected AbstractImportFromExternalSystemControl(@NotNull ProjectSystemId externalSystemId,
71                                                     @NotNull SystemSettings systemSettings,
72                                                     @NotNull ProjectSettings projectSettings)
73   {
74     this(externalSystemId, systemSettings, projectSettings, false);
75   }
76
77   @SuppressWarnings("AbstractMethodCallInConstructor")
78   protected AbstractImportFromExternalSystemControl(@NotNull ProjectSystemId externalSystemId,
79                                                     @NotNull SystemSettings systemSettings,
80                                                     @NotNull ProjectSettings projectSettings,
81                                                     boolean showProjectFormatPanel)
82   {
83     myExternalSystemId = externalSystemId;
84     mySystemSettings = systemSettings;
85     myProjectSettings = projectSettings;
86     myProjectSettingsControl = createProjectSettingsControl(projectSettings);
87     mySystemSettingsControl = createSystemSettingsControl(systemSettings);
88     myShowProjectFormatPanel = showProjectFormatPanel;
89
90     String projectPathTitle = ExternalSystemBundle.message("settings.label.select.project", externalSystemId.getReadableName());
91     ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
92     assert manager != null;
93
94     myLinkedProjectPathField = new NamePathComponent("", projectPathTitle, projectPathTitle, "", false, false);
95     myLinkedProjectPathField.setNameComponentVisible(false);
96     myLinkedProjectPathField.setNameValue("untitled");
97
98     FileChooserDescriptor fileChooserDescriptor = manager.getExternalProjectDescriptor();
99     final BrowseFilesListener browseButtonActionListener = new BrowseFilesListener(
100       myLinkedProjectPathField.getPathComponent(), projectPathTitle, "", fileChooserDescriptor);
101
102     myLinkedProjectPathField.getPathPanel().setBrowseButtonActionListener(browseButtonActionListener);
103     myLinkedProjectPathField.getPathComponent().getDocument().addDocumentListener(new DocumentListener() {
104       @Override
105       public void insertUpdate(DocumentEvent e) {
106         onLinkedProjectPathChange(myLinkedProjectPathField.getPath());
107       }
108
109       @Override
110       public void removeUpdate(DocumentEvent e) {
111         onLinkedProjectPathChange(myLinkedProjectPathField.getPath());
112       }
113
114       @Override
115       public void changedUpdate(DocumentEvent e) {
116         onLinkedProjectPathChange(myLinkedProjectPathField.getPath());
117       }
118     });
119     myComponent.add(myLinkedProjectPathField, ExternalSystemUiUtil.getFillLineConstraints(0));
120     myProjectSettingsControl.fillUi(myComponent, 0);
121
122     myProjectFormatPanel = new ProjectFormatPanel();
123     myProjectFormatLabel = new JLabel(ExternalSystemBundle.message("settings.label.project.format"));
124     myComponent.add(myProjectFormatLabel, ExternalSystemUiUtil.getLabelConstraints(0));
125     myComponent.add(myProjectFormatPanel.getStorageFormatComboBox(), ExternalSystemUiUtil.getFillLineConstraints(0));
126
127     if (mySystemSettingsControl != null) {
128       final PaintAwarePanel mySystemSettingsControlPanel = new PaintAwarePanel();
129       mySystemSettingsControl.fillUi(mySystemSettingsControlPanel, 0);
130
131       JPanel panel = new JPanel(new BorderLayout());
132       panel.add(mySystemSettingsControlPanel, BorderLayout.CENTER);
133       hideableSystemSettingsPanel = new HideableTitledPanel(
134         ExternalSystemBundle.message("settings.title.system.settings", myExternalSystemId.getReadableName()), false);
135       hideableSystemSettingsPanel.setContentComponent(panel);
136       hideableSystemSettingsPanel.setOn(false);
137       myComponent.add(hideableSystemSettingsPanel, ExternalSystemUiUtil.getFillLineConstraints(0));
138     } else {
139       hideableSystemSettingsPanel = null;
140     }
141     ExternalSystemUiUtil.fillBottom(myComponent);
142   }
143
144   /**
145    * This control is assumed to be used at least at two circumstances:
146    * <pre>
147    * <ul>
148    *   <li>new ide project is being created on the external project basis;</li>
149    *   <li>new ide module(s) is being added to the existing ide project on the external project basis;</li>
150    * </ul>
151    * </pre>
152    * We need to differentiate these situations, for example, we don't want to allow linking an external project to existing ide
153    * project if it's already linked.
154    * <p/>
155    * This property helps us to achieve that - when an ide project is defined, that means that new modules are being imported
156    * to that ide project from external project; when this property is {@code null} that means that new ide project is being
157    * created on the target external project basis.
158    * 
159    * @param currentProject  current ide project (if any)
160    */
161   public void setCurrentProject(@Nullable Project currentProject) {
162     myCurrentProject = currentProject;
163   }
164
165   protected abstract void onLinkedProjectPathChange(@NotNull String path);
166
167   /**
168    * Creates a control for managing given project settings.
169    *
170    * @param settings  target external project settings
171    * @return          control for managing given project settings
172    */
173   @NotNull
174   protected abstract ExternalSystemSettingsControl<ProjectSettings> createProjectSettingsControl(@NotNull ProjectSettings settings);
175
176   /**
177    * Creates a control for managing given system-level settings (if any).
178    *
179    * @param settings  target system settings
180    * @return          a control for managing given system-level settings;
181    *                  {@code null} if current external system doesn't have system-level settings (only project-level settings)
182    */
183   @Nullable
184   protected abstract ExternalSystemSettingsControl<SystemSettings> createSystemSettingsControl(@NotNull SystemSettings settings);
185
186   @NotNull
187   public JComponent getComponent() {
188     return myComponent;
189   }
190
191   @NotNull
192   public ExternalSystemSettingsControl<ProjectSettings> getProjectSettingsControl() {
193     return myProjectSettingsControl;
194   }
195
196   @Nullable
197   public ExternalSystemSettingsControl<SystemSettings> getSystemSettingsControl() {
198     return mySystemSettingsControl;
199   }
200
201   public void setLinkedProjectPath(@NotNull String path) {
202     myProjectSettings.setExternalProjectPath(path);
203     myLinkedProjectPathField.setPath(path);
204   }
205
206   @NotNull
207   public SystemSettings getSystemSettings() {
208     return mySystemSettings;
209   }
210
211   @NotNull
212   public ProjectSettings getProjectSettings() {
213     return myProjectSettings;
214   }
215
216   public void setShowProjectFormatPanel(boolean showProjectFormatPanel) {
217     myShowProjectFormatPanel = showProjectFormatPanel;
218   }
219
220   public void reset() {
221     myLinkedProjectPathField.setNameComponentVisible(false);
222     myLinkedProjectPathField.setNameValue("untitled");
223     myLinkedProjectPathField.setPath("");
224     myProjectSettingsControl.reset();
225     if (mySystemSettingsControl != null) {
226       mySystemSettingsControl.reset();
227     }
228     if (hideableSystemSettingsPanel != null) {
229       hideableSystemSettingsPanel.setOn(false);
230     }
231     myProjectFormatLabel.setVisible(myShowProjectFormatPanel);
232     myProjectFormatPanel.setVisible(myShowProjectFormatPanel);
233     myProjectFormatPanel.getPanel().setVisible(myShowProjectFormatPanel);
234     myProjectFormatPanel.getStorageFormatComboBox().setVisible(myShowProjectFormatPanel);
235   }
236
237   public void apply() {
238     String linkedProjectPath = myLinkedProjectPathField.getPath();
239     //noinspection ConstantConditions
240     myProjectSettings.setExternalProjectPath(ExternalSystemApiUtil.normalizePath(linkedProjectPath));
241     myProjectSettingsControl.apply(myProjectSettings);
242     if (mySystemSettingsControl != null) {
243       mySystemSettingsControl.apply(mySystemSettings);
244     }
245   }
246
247   @Nullable
248   public ProjectFormatPanel getProjectFormatPanel() {
249     return myShowProjectFormatPanel ? myProjectFormatPanel : null;
250   }
251
252   public boolean validate(WizardContext wizardContext, boolean defaultFormat) throws ConfigurationException {
253     if (ApplicationManager.getApplication().isHeadlessEnvironment()) return true;
254
255     if (!myProjectSettingsControl.validate(myProjectSettings)) return false;
256     if (mySystemSettingsControl != null && !mySystemSettingsControl.validate(mySystemSettings)) return false;
257     String linkedProjectPath = myLinkedProjectPathField.getPath();
258     if (StringUtil.isEmpty(linkedProjectPath)) {
259       throw new ConfigurationException(ExternalSystemBundle.message("error.project.undefined"));
260     }
261     else if (myCurrentProject != null) {
262       ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(myExternalSystemId);
263       assert manager != null;
264       AbstractExternalSystemSettings<?, ?,?> settings = manager.getSettingsProvider().fun(myCurrentProject);
265       if (settings.getLinkedProjectSettings(linkedProjectPath) != null) {
266         throw new ConfigurationException(ExternalSystemBundle.message("error.project.already.registered"));
267       }
268     }
269
270     return !(wizardContext.isCreatingNewProject() && !myLinkedProjectPathField.validateNameAndPath(wizardContext, defaultFormat));
271   }
272 }