| /* |
| * Copyright 2000-2012 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.util.newProjectWizard; |
| |
| 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.progress.ProgressIndicator; |
| import com.intellij.openapi.progress.ProgressManager; |
| import com.intellij.openapi.progress.Task; |
| import com.intellij.openapi.ui.popup.ListItemDescriptorAdapter; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.platform.ProjectTemplate; |
| import com.intellij.platform.templates.RemoteTemplatesFactory; |
| import com.intellij.psi.codeStyle.MinusculeMatcher; |
| 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.NotNull; |
| 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<TemplateItem> myModel; |
| private MinusculeMatcher myMatcher; |
| private Pair<TemplateItem, Integer> myBestMatch; |
| |
| private TemplateItem myLoadingItem; |
| |
| public ProjectTypesList(JBList list, MultiMap<TemplatesGroup, ProjectTemplate> map, final WizardContext context) { |
| myList = list; |
| |
| new ListSpeedSearch(myList) { |
| @Override |
| protected String getElementText(Object element) { |
| return super.getElementText(element); |
| } |
| }.setComparator(new SpeedSearchComparator(false)); |
| List<TemplateItem> items = buildItems(map); |
| final TemplatesGroup samplesGroup = new TemplatesGroup("Loading Templates...", "", null, 0, null, null, null); |
| myLoadingItem = new TemplateItem(new LoadingProjectTemplate(), samplesGroup) { |
| @Override |
| Icon getIcon() { |
| return null; |
| } |
| |
| @Override |
| String getDescription() { |
| return ""; |
| } |
| }; |
| items.add(myLoadingItem); |
| myModel = new CollectionListModel<TemplateItem>(items); |
| |
| final RemoteTemplatesFactory factory = new RemoteTemplatesFactory(); |
| ProgressManager.getInstance().run(new Task.Backgroundable(context.getProject(), "Loading Templates") { |
| @Override |
| public void run(@NotNull ProgressIndicator indicator) { |
| try { |
| myList.setPaintBusy(true); |
| String[] groups = factory.getGroups(); |
| final List<TemplateItem> items = new ArrayList<TemplateItem>(); |
| for (String group : groups) { |
| TemplatesGroup templatesGroup = new TemplatesGroup(group, "", factory.getGroupIcon(group), 0, null, null, null); |
| ProjectTemplate[] templates = factory.createTemplates(group, context); |
| for (ProjectTemplate template : templates) { |
| items.add(new TemplateItem(template, templatesGroup)); |
| } |
| } |
| //noinspection SSBasedInspection |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| int index = myList.getSelectedIndex(); |
| myModel.remove(myLoadingItem); |
| myModel.add(items); |
| myList.setSelectedIndex(index); |
| } |
| }); |
| } |
| finally { |
| myList.setPaintBusy(false); |
| } |
| } |
| }); |
| |
| myList.setCellRenderer(new GroupedItemsListRenderer(new ListItemDescriptorAdapter() { |
| @Nullable |
| @Override |
| public String getTextFor(Object value) { |
| return ((TemplateItem)value).getName(); |
| } |
| |
| @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<TemplateItem> buildItems(MultiMap<TemplatesGroup, ProjectTemplate> map) { |
| List<TemplateItem> items = new ArrayList<TemplateItem>(); |
| List<TemplatesGroup> groups = new ArrayList<TemplatesGroup>(map.keySet()); |
| Collections.sort(groups); |
| for (TemplatesGroup group : groups) { |
| for (ProjectTemplate template : map.get(group)) { |
| TemplateItem templateItem = new TemplateItem(template, group); |
| items.add(templateItem); |
| } |
| } |
| return items; |
| } |
| |
| @Nullable |
| public ProjectTemplate 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.getName().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 ProjectTemplate myTemplate; |
| private final TemplatesGroup myGroup; |
| |
| TemplateItem(ProjectTemplate template, TemplatesGroup group) { |
| myTemplate = template; |
| myGroup = group; |
| } |
| |
| String getName() { |
| return myTemplate.getName(); |
| } |
| |
| public String getGroupName() { |
| return myGroup.getName(); |
| } |
| |
| Icon getIcon() { |
| return myTemplate.createModuleBuilder().getNodeIcon(); |
| } |
| |
| protected int getMatchingDegree() { |
| if (myMatcher == null) return Integer.MAX_VALUE; |
| String text = getName() + " " + getGroupName(); |
| String description = getDescription(); |
| if (description != null) { |
| text += " " + StringUtil.stripHtml(description, false); |
| } |
| int i = myMatcher.matchingDegree(text); |
| if (myBestMatch == null || i > myBestMatch.second) { |
| myBestMatch = Pair.create(this, i); |
| } |
| return i; |
| } |
| |
| @Nullable |
| String getDescription() { |
| return myTemplate.getDescription(); |
| } |
| |
| @Override |
| public String toString() { |
| return getName() + " " + getGroupName(); |
| } |
| } |
| } |