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 680468047b02..000469cc2a44 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form @@ -28,15 +28,9 @@ - + - - - - - - - + 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 64feffc6a93f..b4d33c7ed4e3 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java @@ -36,23 +36,18 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.platform.ProjectTemplate; -import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.components.JBLabel; -import com.intellij.ui.treeStructure.Tree; +import com.intellij.ui.components.JBList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; import com.intellij.util.containers.MultiMap; -import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import java.awt.*; import java.util.*; import java.util.List; @@ -70,8 +65,9 @@ public class ProjectTypeStep extends ModuleWizardStep { private final ModulesProvider myModulesProvider; private JPanel myPanel; private JPanel myOptionsPanel; - private Tree myProjectTypeTree; private JBLabel myGroupDescriptionLabel; + private JBList myProjectTypeList; + private final ProjectTypesList myList; @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private final FactoryMap myBuilders = new FactoryMap() { @@ -113,55 +109,27 @@ public class ProjectTypeStep extends ModuleWizardStep { categories.putValue(category.getGroupName(), category); } - List list = new ArrayList(); - DefaultMutableTreeNode root = new DefaultMutableTreeNode(); MultiMap templatesMap = CreateFromTemplateMode.getTemplatesMap(context, false); List groups = new ArrayList(templatesMap.keySet()); Collections.sort(groups); + MultiMap map = new MultiMap(); for (TemplatesGroup group : groups) { - DefaultMutableTreeNode groupNode = new DefaultMutableTreeNode(group); - root.add(groupNode); + String name = group.getName(); for (ProjectTemplate template : templatesMap.get(group)) { TemplateBasedProjectType projectType = new TemplateBasedProjectType(template); - groupNode.add(new DefaultMutableTreeNode(projectType)); - list.add(projectType); + map.putValue(name, projectType); } - Collection collection = categories.get(group.getName()); - for (ProjectCategory category : collection) { - groupNode.add(new DefaultMutableTreeNode(category)); - list.add(category); + for (ProjectCategory category : categories.get(name)) { + map.putValue(name, category); } } - myProjectTypeTree.setModel(new DefaultTreeModel(root)); - TreeUtil.expandAll(myProjectTypeTree); + myList = new ProjectTypesList(myProjectTypeList, map, context); - myProjectTypeTree.setCellRenderer(new ColoredTreeCellRenderer() { - @Override - public void customizeCellRenderer(JTree tree, - Object value, - boolean selected, - boolean expanded, - boolean leaf, - int row, - boolean hasFocus) { - Object object = ((DefaultMutableTreeNode)value).getUserObject(); - if (object instanceof ProjectCategory) { - ProjectCategory category = (ProjectCategory)object; - append(category.getDisplayName()); - setIcon(category.getIcon()); - } - else { - TemplatesGroup group = (TemplatesGroup)object; - append(group.getName()); - setIcon(group.getIcon()); - } - } - }); + myProjectTypeList.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - myProjectTypeTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { @Override - public void valueChanged(TreeSelectionEvent e) { + public void valueChanged(ListSelectionEvent e) { ModuleBuilder builder = getSelectedBuilder(); if (builder != null) { myContext.setProjectBuilder(builder); @@ -172,29 +140,25 @@ public class ProjectTypeStep extends ModuleWizardStep { } }); - for (ProjectCategory category : list) { - myWizard.getSequence().addStepsForBuilder(myBuilders.get(category), context, modulesProvider, true); + for (ProjectCategory category : map.values()) { + myWizard.getSequence().addStepsForBuilder(myBuilders.get(category), context, modulesProvider, false); } myFrameworksPanel = new AddSupportForFrameworksPanel(Collections.emptyList(), model, true); Disposer.register(wizard.getDisposable(), myFrameworksPanel); myOptionsPanel.add(myFrameworksPanel.getMainPanel(), FRAMEWORKS_CARD); - - // todo save selection - myProjectTypeTree.addSelectionRow(1); } @Nullable - public Object getSelectedObject() { - TreePath path = myProjectTypeTree.getSelectionPath(); - return path == null ? null : ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject(); + public ProjectCategory getSelectedObject() { + return myList.getSelectedTemplate(); } @Nullable private ModuleBuilder getSelectedBuilder() { - Object object = getSelectedObject(); - return object instanceof ProjectCategory ? myBuilders.get(object) : null; + ProjectCategory object = getSelectedObject(); + return object == null ? null : myBuilders.get(object); } private void updateOptionsPanel(Object object) { @@ -284,13 +248,28 @@ public class ProjectTypeStep extends ModuleWizardStep { myWizard.getSequence().addStepsForBuilder(builder, myContext, myModulesProvider, true); } + @Override + public void updateStep() { + myList.resetSelection(); + } + + @Override + public void onStepLeaving() { + myList.saveSelection(); + } + @Override public JComponent getPreferredFocusedComponent() { - return myProjectTypeTree; + return myProjectTypeList; } @TestOnly public AddSupportForFrameworksPanel getFrameworksPanel() { return myFrameworksPanel; } + + @TestOnly + public boolean setSelectedProjectType(String group, String name) { + return myList.setSelectedTemplate(group, name); + } } diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java new file mode 100644 index 000000000000..26d49ea782b4 --- /dev/null +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypesList.java @@ -0,0 +1,207 @@ +/* + * 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.ide.projectWizard; + +import com.intellij.ide.util.newProjectWizard.SelectTemplateSettings; +import com.intellij.ide.util.projectWizard.WizardContext; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.ui.popup.ListItemDescriptor; +import com.intellij.openapi.util.Pair; +import com.intellij.ui.CollectionListModel; +import com.intellij.ui.ListSpeedSearch; +import com.intellij.ui.SpeedSearchComparator; +import com.intellij.ui.components.JBList; +import com.intellij.ui.popup.list.GroupedItemsListRenderer; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Dmitry Avdeev + * Date: 11/21/12 + */ +public class ProjectTypesList implements Disposable { + + private final JBList myList; + private final CollectionListModel myModel; + private Pair myBestMatch; + + public ProjectTypesList(JBList list, MultiMap map, final WizardContext context) { + myList = list; + + new ListSpeedSearch(myList) { + @Override + protected String getElementText(Object element) { + return super.getElementText(element); + } + }.setComparator(new SpeedSearchComparator(false)); + List items = buildItems(map); + myModel = new CollectionListModel(items); + + myList.setCellRenderer(new GroupedItemsListRenderer(new ListItemDescriptor() { + @Nullable + @Override + public String getTextFor(Object value) { + return ((TemplateItem)value).getName(); + } + + @Nullable + @Override + public String getTooltipFor(Object value) { + return null; + } + + @Nullable + @Override + public Icon getIconFor(Object value) { + return ((TemplateItem)value).getIcon(); + } + + @Override + public boolean hasSeparatorAboveOf(Object value) { + TemplateItem item = (TemplateItem)value; + int index = myModel.getElementIndex(item); + return index == 0 || !myModel.getElementAt(index - 1).getGroupName().equals(item.getGroupName()); + } + + @Nullable + @Override + public String getCaptionAboveOf(Object value) { + return ((TemplateItem)value).getGroupName(); + } + })); + + myList.setModel(myModel); + } + + void installKeyAction(JComponent component) { + new AnAction() { + @Override + public void actionPerformed(AnActionEvent e) { + InputEvent event = e.getInputEvent(); + if (event instanceof KeyEvent) { + int row = myList.getSelectedIndex(); + int toSelect; + switch (((KeyEvent)event).getKeyCode()) { + case KeyEvent.VK_UP: + toSelect = row == 0 ? myList.getItemsCount() - 1 : row - 1; + myList.setSelectedIndex(toSelect); + myList.ensureIndexIsVisible(toSelect); + break; + case KeyEvent.VK_DOWN: + toSelect = row < myList.getItemsCount() - 1 ? row + 1 : 0; + myList.setSelectedIndex(toSelect); + myList.ensureIndexIsVisible(toSelect); + break; + } + } + } + }.registerCustomShortcutSet(new CustomShortcutSet(KeyEvent.VK_UP, KeyEvent.VK_DOWN), component); + } + + void resetSelection() { + if (myList.getSelectedIndex() != -1) return; + SelectTemplateSettings settings = SelectTemplateSettings.getInstance(); + if (settings.getLastGroup() == null || !setSelectedTemplate(settings.getLastGroup(), settings.getLastTemplate())) { + myList.setSelectedIndex(0); + } + } + + void saveSelection() { + TemplateItem item = (TemplateItem)myList.getSelectedValue(); + if (item != null) { + SelectTemplateSettings.getInstance().setLastTemplate(item.getGroupName(), item.getName()); + } + } + + private List buildItems(MultiMap map) { + List items = new ArrayList(); + List groups = new ArrayList(map.keySet()); + Collections.sort(groups); + for (String group : groups) { + for (ProjectCategory template : map.get(group)) { + TemplateItem templateItem = new TemplateItem(template, group); + items.add(templateItem); + } + } + return items; + } + + @Nullable + public ProjectCategory getSelectedTemplate() { + Object value = myList.getSelectedValue(); + return value instanceof TemplateItem ? ((TemplateItem)value).myTemplate : null; + } + + public boolean setSelectedTemplate(@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)) { + myList.setSelectedIndex(i); + myList.ensureIndexIsVisible(i); + return true; + } + } + + return false; + } + + @Override + public void dispose() { + } + + class TemplateItem { + + private final ProjectCategory myTemplate; + private final String myGroup; + + TemplateItem(ProjectCategory template, String group) { + myTemplate = template; + myGroup = group; + } + + String getName() { + return myTemplate.getDisplayName(); + } + + public String getGroupName() { + return myGroup; + } + + Icon getIcon() { + return myTemplate.createModuleBuilder().getNodeIcon(); + } + + @Nullable + String getDescription() { + return myTemplate.getDescription(); + } + + @Override + public String toString() { + return getName() + " " + getGroupName(); + } + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java index 10465cfb6f50..5b933b1d1f9d 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java @@ -76,8 +76,9 @@ public abstract class AbstractExternalProjectSettingsControl + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java index 31c9f5a91fc4..36922d3806f9 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleModuleBuilder.java @@ -22,7 +22,7 @@ import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModule import com.intellij.openapi.module.JavaModuleType; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; -import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.util.io.FileUtilRt; @@ -76,7 +76,7 @@ public class GradleModuleBuilder extends AbstractExternalModuleBuilder() { + @Override + public void consume(Step step) { + if (step instanceof ProjectTypeStep) { + assertTrue(((ProjectTypeStep)step).setSelectedProjectType("Java", "Gradle")); + } + } + }); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + setupJdk(); + } +}