blob: 7a502443fcdb9d3c820f458851092aa53d1aa362 [file] [log] [blame]
/*
* 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();
}
}
}