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 163ddca7a9e9..57cf52906f15 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java @@ -29,6 +29,9 @@ import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.ide.wizard.CommitStepException; import com.intellij.openapi.Disposable; import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.ModifiableRootModel; @@ -42,13 +45,16 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplateEP; +import com.intellij.platform.templates.ArchivedProjectTemplate; import com.intellij.platform.templates.LocalArchivedTemplate; +import com.intellij.platform.templates.RemoteTemplatesFactory; import com.intellij.ui.*; 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.Function; +import com.intellij.util.containers.ConcurrentMultiMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; import com.intellij.util.containers.MultiMap; @@ -71,7 +77,6 @@ import java.util.List; public class ProjectTypeStep extends ModuleWizardStep implements Disposable { private static final String FRAMEWORKS_CARD = "frameworks card"; - private static final String GROUP_CARD = "group description card"; private final WizardContext myContext; private final NewProjectWizard myWizard; private final ModulesProvider myModulesProvider; @@ -99,6 +104,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { private final ModuleBuilder.ModuleConfigurationUpdater myConfigurationUpdater; private boolean myCommitted; private final JBTabsImpl myTabs; + private final MultiMap myTemplates = loadLocalTemplates(); public ProjectTypeStep(WizardContext context, NewProjectWizard wizard, ModulesProvider modulesProvider) { myContext = context; @@ -154,7 +160,6 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { for (ProjectCategory category : map.values()) { myWizard.getSequence().addStepsForBuilder(myBuilders.get(category), context, modulesProvider); } - myFrameworksPanel = new AddSupportForFrameworksPanel(Collections.emptyList(), model, true); Disposer.register(wizard.getDisposable(), myFrameworksPanel); @@ -192,11 +197,12 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { Messages.installHyperlinkSupport(myTemplateDescription); templatesPanel.add(myTemplateDescription, BorderLayout.SOUTH); - myTemplatesTab = new TabInfo(templatesPanel); + myTemplatesTab = new TabInfo(templatesPanel).setText(" Templates "); myTabs.addTab(myTemplatesTab); myOptionsPanel.add(myTabs.getComponent(), FRAMEWORKS_CARD); } + // new category or template is selected public void projectTypeChanged(boolean updatePanel) { ModuleBuilder builder = getSelectedBuilder(); if (builder != null) { @@ -207,14 +213,17 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { } } if (updatePanel) { - updateOptionsPanel(getSelectedProjectType()); + ProjectCategory type = getSelectedProjectType(); + if (type != null) { + updateOptionsPanel(type); + } } } @Nullable public ProjectCategory getSelectedProjectType() { return myTabs.getSelectedInfo() == myFrameworksTab ? - myProjectTypesList.getSelectedTemplate() : + myProjectTypesList.getSelectedType() : (ProjectCategory)myTemplatesList.getSelectedValue(); } @@ -224,52 +233,58 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { return object == null ? null : myBuilders.get(object); } - private void updateOptionsPanel(Object object) { - String card = GROUP_CARD; - if (object instanceof ProjectCategory) { - final ProjectCategory projectCategory = (ProjectCategory)object; - ModuleBuilder builder = myBuilders.get(projectCategory); - JComponent panel = builder.getCustomOptionsPanel(new Disposable() { - @Override - public void dispose() { - disposeUIResources(); - } - }); - if (panel != null) { - card = builder.getBuilderId(); - if (myCards.add(card)) { - myOptionsPanel.add(panel, card); - } + private void updateOptionsPanel(final @NotNull ProjectCategory projectCategory) { + ModuleBuilder builder = myBuilders.get(projectCategory); + JComponent panel = builder.getCustomOptionsPanel(new Disposable() { + @Override + public void dispose() { + disposeUIResources(); } - else { - card = FRAMEWORKS_CARD; - List allProviders = FrameworkSupportUtil.getProviders(builder); - List matched = - ContainerUtil.filter(allProviders, new Condition() { - @Override - public boolean value(FrameworkSupportInModuleProvider provider) { - return matchFramework(projectCategory, provider); - } - }); - - 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); - myTemplatesTab.setText(" Templates (" + templates.size() + ") "); - } + }); + String card; + if (panel != null) { + card = builder.getBuilderId(); + if (myCards.add(card)) { + myOptionsPanel.add(panel, card); } } + else { + card = FRAMEWORKS_CARD; + List allProviders = FrameworkSupportUtil.getProviders(builder); + List matched = + ContainerUtil.filter(allProviders, new Condition() { + @Override + public boolean value(FrameworkSupportInModuleProvider provider) { + return matchFramework(projectCategory, provider); + } + }); + + myFrameworksPanel.setProviders(matched, + new HashSet(Arrays.asList(projectCategory.getAssociatedFrameworkIds())), + new HashSet(Arrays.asList(projectCategory.getPreselectedFrameworkIds()))); + myFrameworksTab.setEnabled(!matched.isEmpty()); + + updateTemplates(projectCategory, true); + } ((CardLayout)myOptionsPanel.getLayout()).show(myOptionsPanel, card); } + private void updateTemplates(ProjectCategory projectCategory, boolean initial) { + List templates = ContainerUtil.map(myTemplates.get(projectCategory.getId()), new Function() { + @Override + public ProjectCategory fun(ProjectTemplate template) { + return new TemplateBasedProjectType(template); + } + }); + + //noinspection unchecked + myTemplatesList.setModel(new CollectionListModel(templates)); + myTemplatesTab.setEnabled(!templates.isEmpty()); + if (initial && !templates.isEmpty()) { + myTemplatesList.setSelectedIndex(0); + } + } + private boolean matchFramework(ProjectCategory projectCategory, FrameworkSupportInModuleProvider framework) { if (!framework.isEnabledForModuleBuilder(myBuilders.get(projectCategory))) return false; @@ -296,6 +311,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { @Override public void updateStep() { myProjectTypesList.resetSelection(); + loadRemoteTemplates(); } @Override @@ -331,28 +347,63 @@ public class ProjectTypeStep extends ModuleWizardStep implements Disposable { @TestOnly public boolean setSelectedProjectType(String group, String name) { - return myProjectTypesList.setSelectedTemplate(group, name); + return myProjectTypesList.setSelectedType(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)); - } - }); + @Override + public void disposeUIResources() { + Disposer.dispose(this); } + private static MultiMap loadLocalTemplates() { + ConcurrentMultiMap map = new ConcurrentMultiMap(); + ProjectTemplateEP[] extensions = ProjectTemplateEP.EP_NAME.getExtensions(); + for (ProjectTemplateEP ep : extensions) { + ClassLoader classLoader = ep.getLoaderForClass(); + URL url = classLoader.getResource(ep.templatePath); + if (url != null) { + map.putValue(ep.projectType, new LocalArchivedTemplate(url, classLoader)); + } + } + return map; + } + + private void loadRemoteTemplates() { + ProgressManager.getInstance().run(new Task.Backgroundable(myContext.getProject(), "Loading Templates") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + myTemplatesList.setPaintBusy(true); + RemoteTemplatesFactory factory = new RemoteTemplatesFactory(); + String[] groups = factory.getGroups(); + for (String group : groups) { + ProjectTemplate[] templates = factory.createTemplates(group, myContext); + for (ProjectTemplate template : templates) { + String id = ((ArchivedProjectTemplate)template).getCategory(); + myTemplates.putValue(id == null ? group : id, template); + } + } + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + public void run() { + int index = myTemplatesList.getSelectedIndex(); + ProjectCategory type = myProjectTypesList.getSelectedType(); + if (type != null) { + updateTemplates(type, false); + } + myTemplatesList.setSelectedIndex(index); + } + }); + } + finally { + myTemplatesList.setPaintBusy(false); + } + } + }); + + } } diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java index ddac3b1c9927..b5d60bc7f024 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java @@ -125,7 +125,7 @@ public class ProjectTypesList implements Disposable { void resetSelection() { if (myList.getSelectedIndex() != -1) return; SelectTemplateSettings settings = SelectTemplateSettings.getInstance(); - if (settings.getLastGroup() == null || !setSelectedTemplate(settings.getLastGroup(), settings.getLastTemplate())) { + if (settings.getLastGroup() == null || !setSelectedType(settings.getLastGroup(), settings.getLastTemplate())) { myList.setSelectedIndex(0); } } @@ -151,12 +151,12 @@ public class ProjectTypesList implements Disposable { } @Nullable - public ProjectCategory getSelectedTemplate() { + public ProjectCategory getSelectedType() { Object value = myList.getSelectedValue(); return value instanceof TemplateItem ? ((TemplateItem)value).myTemplate : null; } - public boolean setSelectedTemplate(@Nullable String group, @Nullable String name) { + public boolean setSelectedType(@Nullable String group, @Nullable String name) { for (int i = 0; i < myList.getModel().getSize(); i++) { Object o = myList.getModel().getElementAt(i); if (o instanceof TemplateItem && ((TemplateItem)o).myGroup.equals(group) && ((TemplateItem)o).getName().equals(name)) { @@ -173,7 +173,7 @@ public class ProjectTypesList implements Disposable { public void dispose() { } - class TemplateItem { + static class TemplateItem { private final ProjectCategory myTemplate; private final String myGroup; diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/LoadingProjectTemplate.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/LoadingProjectTemplate.java index 2154ec25c4ed..9cd0f67c9549 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/LoadingProjectTemplate.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/LoadingProjectTemplate.java @@ -27,7 +27,7 @@ import javax.swing.*; * @author Dmitry Avdeev * Date: 11/28/12 */ -class LoadingProjectTemplate implements ProjectTemplate { +public class LoadingProjectTemplate implements ProjectTemplate { @NotNull @Override public String getName() { diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/ProjectTypesList.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/ProjectTypesList.java index 813eae735b90..1af97c19d3cd 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/ProjectTypesList.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/ProjectTypesList.java @@ -68,7 +68,6 @@ public class ProjectTypesList implements Disposable { } }.setComparator(new SpeedSearchComparator(false)); List items = buildItems(map); - final RemoteTemplatesFactory factory = new RemoteTemplatesFactory(); final TemplatesGroup samplesGroup = new TemplatesGroup("Loading Templates...", "", null, 0); myLoadingItem = new TemplateItem(new LoadingProjectTemplate(), samplesGroup) { @Override @@ -84,6 +83,7 @@ public class ProjectTypesList implements Disposable { items.add(myLoadingItem); myModel = new CollectionListModel(items); + final RemoteTemplatesFactory factory = new RemoteTemplatesFactory(); ProgressManager.getInstance().run(new Task.Backgroundable(context.getProject(), "Loading Templates") { @Override public void run(@NotNull ProgressIndicator indicator) { diff --git a/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java b/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java index adc9ddd65c36..8937dd97dcc8 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java +++ b/java/idea-ui/src/com/intellij/platform/templates/ArchivedProjectTemplate.java @@ -35,9 +35,11 @@ import java.util.zip.ZipInputStream; public abstract class ArchivedProjectTemplate implements ProjectTemplate { protected final String myDisplayName; + @Nullable private final String myCategory; - public ArchivedProjectTemplate(@NotNull String displayName) { + public ArchivedProjectTemplate(@NotNull String displayName, @Nullable String category) { myDisplayName = displayName; + myCategory = category; } @NotNull @@ -67,4 +69,9 @@ public abstract class ArchivedProjectTemplate implements ProjectTemplate { } public abstract ZipInputStream getStream() throws IOException; + + @Nullable + public String getCategory() { + return myCategory; + } } 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 dd29a6986922..e9c84800dafe 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java +++ b/java/idea-ui/src/com/intellij/platform/templates/LocalArchivedTemplate.java @@ -55,7 +55,7 @@ public class LocalArchivedTemplate extends ArchivedProjectTemplate { public LocalArchivedTemplate(@NotNull URL archivePath, @NotNull ClassLoader classLoader) { - super(getTemplateName(archivePath)); + super(getTemplateName(archivePath), null); myArchivePath = archivePath; myModuleType = computeModuleType(this); diff --git a/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java b/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java index d3db36470740..f62333ce30b2 100644 --- a/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java +++ b/java/idea-ui/src/com/intellij/platform/templates/RemoteTemplatesFactory.java @@ -147,7 +147,7 @@ public class RemoteTemplatesFactory extends ProjectTemplatesFactory { final String path = element.getChildText("path", ns); final String description = element.getChildTextTrim("description", ns); String name = element.getChildTextTrim("name", ns); - return new ArchivedProjectTemplate(name) { + return new ArchivedProjectTemplate(name, element.getChildTextTrim("category")) { @Override protected ModuleType getModuleType() { return moduleType;