blob: 22f5435972c7d6821e6b7ec50213e833103ff887 [file] [log] [blame]
/*
* Copyright 2000-2011 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.util.ui.classpath;
import com.intellij.ide.CommonActionsManager;
import com.intellij.ide.DefaultTreeExpander;
import com.intellij.ide.TreeExpander;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.LibraryOrderEntry;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.impl.libraries.LibraryTableImplUtil;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.roots.ui.CellAppearanceEx;
import com.intellij.openapi.roots.ui.OrderEntryAppearanceService;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.DoubleClickListener;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.treeStructure.SimpleNode;
import com.intellij.ui.treeStructure.SimpleTree;
import com.intellij.ui.treeStructure.SimpleTreeBuilder;
import com.intellij.ui.treeStructure.WeightBasedComparator;
import com.intellij.util.CommonProcessors;
import com.intellij.util.PlatformIcons;
import com.intellij.util.Processor;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
/**
* @author Gregory.Shrago
*/
public abstract class ChooseLibrariesDialogBase extends DialogWrapper {
private final SimpleTree myTree = new SimpleTree();
private AbstractTreeBuilder myBuilder;
private List<Library> myResult;
private final Map<Object, Object> myParentsMap = new THashMap<Object, Object>();
protected ChooseLibrariesDialogBase(final JComponent parentComponent, final String title) {
super(parentComponent, false);
setTitle(title);
}
protected ChooseLibrariesDialogBase(Project project, String title) {
super(project, false);
setTitle(title);
}
@Override
protected void init() {
super.init();
updateOKAction();
}
private static String notEmpty(String nodeText) {
return StringUtil.isNotEmpty(nodeText) ? nodeText : "<unnamed>";
}
@Override
protected String getDimensionServiceKey() {
return "#com.intellij.util.ui.classpath.ChooseLibrariesDialog";
}
protected int getLibraryTableWeight(@NotNull LibraryTable libraryTable) {
return 0;
}
protected boolean isAutoExpandLibraryTable(@NotNull LibraryTable libraryTable) {
return false;
}
@Override
protected void doOKAction() {
processSelection(new CommonProcessors.CollectProcessor<Library>(myResult = new ArrayList<Library>()));
super.doOKAction();
}
private void updateOKAction() {
setOKActionEnabled(!processSelection(new CommonProcessors.FindFirstProcessor<Library>()));
}
@Override
public JComponent getPreferredFocusedComponent() {
return myTree;
}
@NotNull
public List<Library> getSelectedLibraries() {
return myResult == null? Collections.<Library>emptyList() : myResult;
}
protected void queueUpdateAndSelect(@NotNull final Library library) {
myBuilder.queueUpdate().doWhenDone(new Runnable() {
@Override
public void run() {
myBuilder.select(library);
}
});
}
private boolean processSelection(final Processor<Library> processor) {
for (Object element : myBuilder.getSelectedElements()) {
if (element instanceof Library) {
if (!processor.process((Library)element)) return false;
}
}
return true;
}
protected boolean acceptsElement(final Object element) {
return true;
}
@Override
protected JComponent createNorthPanel() {
final DefaultActionGroup group = new DefaultActionGroup();
final TreeExpander expander = new DefaultTreeExpander(myTree);
final CommonActionsManager actionsManager = CommonActionsManager.getInstance();
group.add(actionsManager.createExpandAllAction(expander, myTree));
group.add(actionsManager.createCollapseAllAction(expander, myTree));
final JComponent component = ActionManager.getInstance().createActionToolbar(ActionPlaces.PROJECT_VIEW_TOOLBAR, group, true).getComponent();
component.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.darkGray), component.getBorder()));
return component;
}
@Override
@Nullable
protected JComponent createCenterPanel() {
myBuilder = new SimpleTreeBuilder(myTree, new DefaultTreeModel(new DefaultMutableTreeNode()),
new MyStructure(getProject()),
WeightBasedComparator.FULL_INSTANCE);
myBuilder.initRootNode();
myTree.setDragEnabled(false);
myTree.setShowsRootHandles(true);
UIUtil.setLineStyleAngled(myTree);
myTree.setRootVisible(false);
myTree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(final TreeSelectionEvent e) {
updateOKAction();
}
});
new DoubleClickListener() {
@Override
protected boolean onDoubleClick(MouseEvent e) {
if (isOKActionEnabled()) {
doOKAction();
return true;
}
return false;
}
}.installOn(myTree);
myTree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ENTER");
myTree.getActionMap().put("ENTER", getOKAction());
final JScrollPane pane = ScrollPaneFactory.createScrollPane(myTree);
pane.setPreferredSize(new Dimension(500, 400));
return pane;
}
@NotNull
protected Project getProject() {
return ProjectManager.getInstance().getDefaultProject();
}
protected LibrariesTreeNodeBase<Library> createLibraryDescriptor(NodeDescriptor parentDescriptor, Library library) {
return new LibraryDescriptor(getProject(), parentDescriptor, library);
}
protected void collectChildren(Object element, final List<Object> result) {
if (element instanceof Application) {
Collections.addAll(result, ProjectManager.getInstance().getOpenProjects());
final LibraryTablesRegistrar instance = LibraryTablesRegistrar.getInstance();
result.add(instance.getLibraryTable()); //1
result.addAll(instance.getCustomLibraryTables()); //2
}
else if (element instanceof Project) {
Collections.addAll(result, ModuleManager.getInstance((Project)element).getModules());
result.add(LibraryTablesRegistrar.getInstance().getLibraryTable((Project)element));
}
else if (element instanceof LibraryTable) {
Collections.addAll(result, ((LibraryTable)element).getLibraries());
}
else if (element instanceof Module) {
for (OrderEntry entry : ModuleRootManager.getInstance((Module)element).getOrderEntries()) {
if (entry instanceof LibraryOrderEntry) {
final LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry;
if (LibraryTableImplUtil.MODULE_LEVEL.equals(libraryOrderEntry.getLibraryLevel())) {
final Library library = libraryOrderEntry.getLibrary();
result.add(library);
}
}
}
}
}
@Override
protected void dispose() {
Disposer.dispose(myBuilder);
super.dispose();
}
protected static class LibrariesTreeNodeBase<T> extends SimpleNode {
private final T myElement;
protected LibrariesTreeNodeBase(Project project, NodeDescriptor parentDescriptor, T element) {
super(project, parentDescriptor);
myElement = element;
}
@Override
public T getElement() {
return myElement;
}
@Override
public SimpleNode[] getChildren() {
return NO_CHILDREN;
}
@Override
public int getWeight() {
return 0;
}
@NotNull
@Override
public Object[] getEqualityObjects() {
return new Object[] {myElement};
}
@Override
protected void update(PresentationData presentation) {
//todo[nik] this is workaround for bug in getTemplatePresentation().setIcons()
presentation.setIcon(getTemplatePresentation().getIcon(false));
}
}
private static class RootDescriptor extends LibrariesTreeNodeBase<Object> {
protected RootDescriptor(final Project project) {
super(project, null, ApplicationManager.getApplication());
}
}
private static class ProjectDescriptor extends LibrariesTreeNodeBase<Project> {
protected ProjectDescriptor(final Project project, final Project element) {
super(project, null, element);
getTemplatePresentation().setIcon(PlatformIcons.PROJECT_ICON);
getTemplatePresentation().addText(notEmpty(getElement().getName()), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
}
private static class ModuleDescriptor extends LibrariesTreeNodeBase<Module> {
protected ModuleDescriptor(final Project project, final NodeDescriptor parentDescriptor, final Module element) {
super(project, parentDescriptor, element);
final PresentationData templatePresentation = getTemplatePresentation();
templatePresentation.setIcon(ModuleType.get(element).getIcon());
templatePresentation.addText(notEmpty(element.getName()), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
@Override
public int getWeight() {
return 1;
}
}
private static class LibraryDescriptor extends LibrariesTreeNodeBase<Library> {
protected LibraryDescriptor(final Project project, final NodeDescriptor parentDescriptor, final Library element) {
super(project, parentDescriptor, element);
final CellAppearanceEx appearance = OrderEntryAppearanceService.getInstance().forLibrary(project, element, false);
final SimpleColoredComponent coloredComponent = new SimpleColoredComponent();
appearance.customize(coloredComponent);
final PresentationData templatePresentation = getTemplatePresentation();
templatePresentation.setIcon(coloredComponent.getIcon());
templatePresentation.addText(notEmpty(appearance.getText()), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
}
private static class LibraryTableDescriptor extends LibrariesTreeNodeBase<LibraryTable> {
private final int myWeight;
private boolean myAutoExpand;
protected LibraryTableDescriptor(final Project project,
final NodeDescriptor parentDescriptor,
final LibraryTable table,
final int weight,
boolean autoExpand) {
super(project, parentDescriptor, table);
myWeight = weight;
myAutoExpand = autoExpand;
getTemplatePresentation().setIcon(PlatformIcons.LIBRARY_ICON);
final String nodeText = table.getPresentation().getDisplayName(true);
getTemplatePresentation().addText(notEmpty(nodeText), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
@Override
public boolean isAutoExpandNode() {
return myAutoExpand;
}
@Override
public int getWeight() {
return myWeight;
}
}
public boolean isEmpty() {
List<Object> children = new ArrayList<Object>();
collectChildren(myBuilder.getTreeStructure().getRootElement(), children);
return children.isEmpty();
}
private class MyStructure extends AbstractTreeStructure {
private final Project myProject;
public MyStructure(Project project) {
myProject = project;
}
@Override
public Object getRootElement() {
return ApplicationManager.getApplication();
}
@Override
public Object[] getChildElements(Object element) {
final List<Object> result = new ArrayList<Object>();
collectChildren(element, result);
final Iterator<Object> it = result.iterator();
while (it.hasNext()) {
if (!acceptsElement(it.next())) it.remove();
}
for (Object o : result) {
myParentsMap.put(o, element);
}
return result.toArray();
}
@Override
public Object getParentElement(Object element) {
if (element instanceof Application) return null;
if (element instanceof Project) return ApplicationManager.getApplication();
if (element instanceof Module) return ((Module)element).getProject();
if (element instanceof LibraryTable) return myParentsMap.get(element);
if (element instanceof Library) return myParentsMap.get(element);
throw new AssertionError();
}
@NotNull
@Override
public NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) {
if (element instanceof Application) return new RootDescriptor(myProject);
if (element instanceof Project) return new ProjectDescriptor(myProject, (Project)element);
if (element instanceof Module) return new ModuleDescriptor(myProject, parentDescriptor, (Module)element);
if (element instanceof LibraryTable) {
final LibraryTable libraryTable = (LibraryTable)element;
return new LibraryTableDescriptor(myProject, parentDescriptor, libraryTable,
getLibraryTableWeight(libraryTable),
isAutoExpandLibraryTable(libraryTable));
}
if (element instanceof Library) return createLibraryDescriptor(parentDescriptor, (Library)element);
throw new AssertionError();
}
@Override
public void commit() {
}
@Override
public boolean hasSomethingToCommit() {
return false;
}
}
}