diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form
index 000469cc2a44..1eaf1286e09e 100644
--- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form
+++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form
@@ -45,29 +45,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java
index 67c6cff9c257..a44a5aee83f7 100644
--- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java
+++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java
@@ -39,9 +39,18 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.platform.ProjectTemplate;
-import com.intellij.ui.components.JBLabel;
+import com.intellij.platform.ProjectTemplateEP;
+import com.intellij.platform.templates.LocalArchivedTemplate;
+import com.intellij.ui.CollectionListModel;
+import com.intellij.ui.ColoredListCellRenderer;
+import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBList;
+import com.intellij.ui.tabs.TabInfo;
+import com.intellij.ui.tabs.TabsListener;
+import com.intellij.ui.tabs.impl.JBTabsImpl;
+import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FactoryMap;
import com.intellij.util.containers.MultiMap;
@@ -53,6 +62,7 @@ import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
+import java.net.URL;
import java.util.*;
import java.util.List;
@@ -60,7 +70,7 @@ import java.util.List;
* @author Dmitry Avdeev
* Date: 04.09.13
*/
-public class ProjectTypeStep extends ModuleWizardStep {
+public class ProjectTypeStep extends ModuleWizardStep implements Disposable {
private static final String FRAMEWORKS_CARD = "frameworks card";
private static final String GROUP_CARD = "group description card";
@@ -69,9 +79,12 @@ public class ProjectTypeStep extends ModuleWizardStep {
private final ModulesProvider myModulesProvider;
private JPanel myPanel;
private JPanel myOptionsPanel;
- private JBLabel myGroupDescriptionLabel;
private JBList myProjectTypeList;
- private final ProjectTypesList myList;
+
+ private final ProjectTypesList myProjectTypesList;
+ private final JBList myTemplatesList;
+ private final TabInfo myFrameworksTab;
+ private final TabInfo myTemplatesTab;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final FactoryMap myBuilders = new FactoryMap() {
@@ -86,6 +99,7 @@ public class ProjectTypeStep extends ModuleWizardStep {
private final AddSupportForFrameworksPanel myFrameworksPanel;
private final ModuleBuilder.ModuleConfigurationUpdater myConfigurationUpdater;
private boolean myCommitted;
+ private final JBTabsImpl myTabs;
public ProjectTypeStep(WizardContext context, NewProjectWizard wizard, ModulesProvider modulesProvider) {
myContext = context;
@@ -129,19 +143,12 @@ public class ProjectTypeStep extends ModuleWizardStep {
}
}
- myList = new ProjectTypesList(myProjectTypeList, map);
+ myProjectTypesList = new ProjectTypesList(myProjectTypeList, map);
myProjectTypeList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-
@Override
public void valueChanged(ListSelectionEvent e) {
- ModuleBuilder builder = getSelectedBuilder();
- if (builder != null) {
- myContext.setProjectBuilder(builder);
- myWizard.getSequence().setType(builder.getBuilderId());
- builder.addModuleConfigurationUpdater(myConfigurationUpdater);
- }
- updateOptionsPanel(getSelectedObject());
+ projectTypeChanged(true);
}
});
@@ -152,17 +159,59 @@ public class ProjectTypeStep extends ModuleWizardStep {
myFrameworksPanel = new AddSupportForFrameworksPanel(Collections.emptyList(), model, true);
Disposer.register(wizard.getDisposable(), myFrameworksPanel);
- myOptionsPanel.add(myFrameworksPanel.getMainPanel(), FRAMEWORKS_CARD);
+ myTemplatesList = new JBList();
+ myTemplatesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ myTemplatesList.setCellRenderer(new ColoredListCellRenderer() {
+ @Override
+ protected void customizeCellRenderer(JList list, ProjectCategory value, int index, boolean selected, boolean hasFocus) {
+ append(value.getDisplayName()).setIcon(value.getIcon());
+ }
+ });
+ myTemplatesList.addListSelectionListener(new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ projectTypeChanged(false);
+ }
+ });
+
+ myTabs = new JBTabsImpl(null, IdeFocusManager.findInstance(), this);
+ myTabs.addListener(new TabsListener.Adapter() {
+ @Override
+ public void selectionChanged(TabInfo oldSelection, TabInfo newSelection) {
+ projectTypeChanged(false);
+ }
+ });
+ myFrameworksTab = new TabInfo(myFrameworksPanel.getMainPanel()).setText(" Frameworks ");
+ myTabs.addTab(myFrameworksTab);
+ myTemplatesTab = new TabInfo(ScrollPaneFactory.createScrollPane(myTemplatesList)).setText(" Templates ");
+ myTabs.addTab(myTemplatesTab);
+ myOptionsPanel.add(myTabs.getComponent(), FRAMEWORKS_CARD);
+ }
+
+ public void projectTypeChanged(boolean updatePanel) {
+ ModuleBuilder builder = getSelectedBuilder();
+ if (builder != null) {
+ myContext.setProjectBuilder(builder);
+ myWizard.getSequence().setType(builder.getBuilderId());
+ if (myFrameworksTab == myTabs.getSelectedInfo()) {
+ builder.addModuleConfigurationUpdater(myConfigurationUpdater);
+ }
+ }
+ if (updatePanel) {
+ updateOptionsPanel(getSelectedProjectType());
+ }
}
@Nullable
- public ProjectCategory getSelectedObject() {
- return myList.getSelectedTemplate();
+ public ProjectCategory getSelectedProjectType() {
+ return myTabs.getSelectedInfo() == myFrameworksTab ?
+ myProjectTypesList.getSelectedTemplate() :
+ (ProjectCategory)myTemplatesList.getSelectedValue();
}
@Nullable
private ModuleBuilder getSelectedBuilder() {
- ProjectCategory object = getSelectedObject();
+ ProjectCategory object = getSelectedProjectType();
return object == null ? null : myBuilders.get(object);
}
@@ -197,11 +246,17 @@ public class ProjectTypeStep extends ModuleWizardStep {
myFrameworksPanel.setProviders(matched,
new HashSet(Arrays.asList(projectCategory.getAssociatedFrameworkIds())),
new HashSet(Arrays.asList(projectCategory.getPreselectedFrameworkIds())));
+ List templates = getTemplates(projectCategory.getId());
+ myFrameworksTab.setHidden(matched.isEmpty() && !templates.isEmpty());
+
+ //noinspection unchecked
+ myTemplatesList.setModel(new CollectionListModel(templates));
+ myTemplatesTab.setHidden(templates.isEmpty());
+ if (!templates.isEmpty()) {
+ myTemplatesList.setSelectedIndex(0);
+ }
}
}
- else if (object instanceof TemplatesGroup) {
- myGroupDescriptionLabel.setText(((TemplatesGroup)object).getDescription());
- }
((CardLayout)myOptionsPanel.getLayout()).show(myOptionsPanel, card);
}
@@ -230,17 +285,17 @@ public class ProjectTypeStep extends ModuleWizardStep {
@Override
public void updateStep() {
- myList.resetSelection();
+ myProjectTypesList.resetSelection();
}
@Override
public void onStepLeaving() {
- myList.saveSelection();
+ myProjectTypesList.saveSelection();
}
@Override
public void onWizardFinished() throws CommitStepException {
- if (!myCommitted) {
+ if (!myCommitted && myTabs.getSelectedInfo() == myFrameworksTab) {
boolean ok = myFrameworksPanel.downloadLibraries();
if (!ok) {
int answer = Messages.showYesNoDialog(getComponent(),
@@ -266,6 +321,28 @@ public class ProjectTypeStep extends ModuleWizardStep {
@TestOnly
public boolean setSelectedProjectType(String group, String name) {
- return myList.setSelectedTemplate(group, name);
+ return myProjectTypesList.setSelectedTemplate(group, name);
}
+
+ @Override
+ public void dispose() {
+ }
+
+ private static List getTemplates(final String projectType) {
+ ProjectTemplateEP[] extensions = ProjectTemplateEP.EP_NAME.getExtensions();
+ return ContainerUtil.mapNotNull(extensions, new NullableFunction() {
+ @Nullable
+ @Override
+ public ProjectCategory fun(ProjectTemplateEP ep) {
+
+ if (!projectType.equals(ep.projectType)) {
+ return null;
+ }
+ ClassLoader classLoader = ep.getLoaderForClass();
+ URL url = classLoader.getResource(ep.templatePath);
+ return url == null ? null : new TemplateBasedProjectType(new LocalArchivedTemplate(url, classLoader));
+ }
+ });
+ }
+
}
diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.java b/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.java
index 8f462aea22aa..e9eefe505881 100644
--- a/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.java
+++ b/java/idea-ui/src/com/intellij/ide/projectWizard/TemplateBasedProjectType.java
@@ -17,12 +17,10 @@ package com.intellij.ide.projectWizard;
import com.intellij.ide.util.projectWizard.ModuleBuilder;
import com.intellij.platform.ProjectTemplate;
-import com.intellij.platform.templates.ArchivedTemplatesFactory;
import com.intellij.platform.templates.LocalArchivedTemplate;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
-import java.io.File;
import java.net.URL;
/**
@@ -36,8 +34,7 @@ public class TemplateBasedProjectType extends ProjectCategory {
public TemplateBasedProjectType(String templatePath) {
URL resource = getClass().getResource(templatePath);
assert resource != null : templatePath;
- String name = ArchivedTemplatesFactory.getTemplateName(new File(templatePath).getName());
- myTemplate = new LocalArchivedTemplate(name, resource, getClass().getClassLoader());
+ myTemplate = new LocalArchivedTemplate(resource, getClass().getClassLoader());
}
public TemplateBasedProjectType(ProjectTemplate template) {
diff --git a/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java b/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java
index 8ea988e72a95..b2ea5025efd2 100644
--- a/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java
+++ b/java/idea-ui/src/com/intellij/platform/templates/ArchivedTemplatesFactory.java
@@ -41,7 +41,7 @@ import java.util.*;
*/
public class ArchivedTemplatesFactory extends ProjectTemplatesFactory {
- private static final String ZIP = ".zip";
+ static final String ZIP = ".zip";
private final ClearableLazyValue>> myGroups = new ClearableLazyValue>>() {
@NotNull
@@ -83,7 +83,8 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory {
if (index != -1) {
child = child.substring(0, index);
}
- map.putValue(child.replace('_', ' '), Pair.create(new URL(url.getKey().toExternalForm() + "/" + child), url.getValue()));
+ String name = child.replace('_', ' ');
+ map.putValue(name, Pair.create(new URL(url.getKey().toExternalForm() + "/" + child), url.getValue()));
}
}
catch (IOException e) {
@@ -132,8 +133,7 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory {
for (String child : children) {
if (child.endsWith(ZIP)) {
URL templateUrl = new URL(url.first.toExternalForm() + "/" + child);
- String name = getTemplateName(child);
- templates.add(new LocalArchivedTemplate(name, templateUrl, url.second));
+ templates.add(new LocalArchivedTemplate(templateUrl, url.second));
}
}
}
@@ -144,10 +144,6 @@ public class ArchivedTemplatesFactory extends ProjectTemplatesFactory {
return templates.toArray(new ProjectTemplate[templates.size()]);
}
- public static String getTemplateName(String child) {
- return child.substring(0, child.length() - ZIP.length()).replace('_', ' ');
- }
-
@Override
public int getGroupWeight(String group) {
return CUSTOM_GROUP.equals(group) ? -2 : 0;
diff --git a/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java b/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java
index f671335e6d7e..dd29a6986922 100644
--- a/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java
+++ b/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
@@ -52,10 +53,9 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate {
private List myInputFields = Collections.emptyList();
private Icon myIcon;
- public LocalArchivedTemplate(@NotNull String displayName,
- @NotNull URL archivePath,
+ public LocalArchivedTemplate(@NotNull URL archivePath,
@NotNull ClassLoader classLoader) {
- super(displayName);
+ super(getTemplateName(archivePath));
myArchivePath = archivePath;
myModuleType = computeModuleType(this);
@@ -80,6 +80,11 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate {
}
}
+ private static String getTemplateName(URL url) {
+ String fileName = new File(url.getPath()).getName();
+ return fileName.substring(0, fileName.length() - ArchivedTemplatesFactory.ZIP.length()).replace('_', ' ');
+ }
+
@Override
public String getDescription() {
return readEntry(new Condition() {
diff --git a/platform/platform-impl/src/com/intellij/platform/ProjectTemplateEP.java b/platform/platform-impl/src/com/intellij/platform/ProjectTemplateEP.java
new file mode 100644
index 000000000000..b91a09bf336f
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/platform/ProjectTemplateEP.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2013 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.platform;
+
+import com.intellij.openapi.extensions.AbstractExtensionPointBean;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.util.xmlb.annotations.Attribute;
+
+/**
+ * @author Dmitry Avdeev
+ * Date: 07.11.13
+ */
+public class ProjectTemplateEP extends AbstractExtensionPointBean {
+
+ public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.projectTemplate");
+
+ @Attribute("projectType")
+ public String projectType;
+
+ @Attribute("templatePath")
+ public String templatePath;
+
+}
diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
index 6ac266db5c15..091006a1d0ca 100644
--- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
@@ -98,6 +98,8 @@
+