blob: 1dd80ac7477e4654ab533bfdc97934e5c915ded8 [file] [log] [blame]
/*
* 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.favoritesTreeView;
import com.intellij.history.LocalHistory;
import com.intellij.history.LocalHistoryAction;
import com.intellij.icons.AllIcons;
import com.intellij.ide.*;
import com.intellij.ide.dnd.aware.DnDAwareTree;
import com.intellij.ide.favoritesTreeView.actions.*;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.ide.projectView.impl.ModuleGroup;
import com.intellij.ide.projectView.impl.nodes.LibraryGroupElement;
import com.intellij.ide.projectView.impl.nodes.NamedLibraryElement;
import com.intellij.ide.projectView.impl.nodes.ProjectViewDirectoryHelper;
import com.intellij.ide.ui.customization.CustomizationUtil;
import com.intellij.ide.util.DeleteHandler;
import com.intellij.ide.util.DirectoryChooserUtil;
import com.intellij.ide.util.EditorHelper;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.ide.util.treeView.NodeRenderer;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.configuration.actions.ModuleDeleteProvider;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ex.ToolWindowEx;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.docking.DockableContent;
import com.intellij.ui.treeStructure.actions.CollapseAllAction;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.EditSourceOnEnterKeyHandler;
import com.intellij.util.PlatformUtils;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.*;
import java.util.List;
/**
* @author anna
* @author Konstantin Bulenkov
*/
public class FavoritesTreeViewPanel extends JPanel implements DataProvider, DockContainer {
private final FavoritesTreeStructure myFavoritesTreeStructure;
private FavoritesViewTreeBuilder myBuilder;
private final CopyPasteDelegator myCopyPasteDelegator;
private final MouseListener myTreePopupHandler;
public static final DataKey<FavoritesTreeNodeDescriptor[]> CONTEXT_FAVORITES_ROOTS_DATA_KEY = DataKey.create("FavoritesRoot");
public static final DataKey<DnDAwareTree> FAVORITES_TREE_KEY = DataKey.create("Favorites.Tree");
public static final DataKey<FavoritesViewTreeBuilder> FAVORITES_TREE_BUILDER_KEY = DataKey.create("Favorites.Tree.Builder");
public static final DataKey<String> FAVORITES_LIST_NAME_DATA_KEY = DataKey.create("FavoritesListName");
protected Project myProject;
protected DnDAwareTree myTree;
private final MyDeletePSIElementProvider myDeletePSIElementProvider = new MyDeletePSIElementProvider();
private final ModuleDeleteProvider myDeleteModuleProvider = new ModuleDeleteProvider();
private final AutoScrollToSourceHandler myAutoScrollToSourceHandler;
private final IdeView myIdeView = new MyIdeView();
private final FavoritesManager myFavoritesManager;
public FavoritesTreeViewPanel(Project project) {
super(new BorderLayout());
myProject = project;
myFavoritesManager = FavoritesManager.getInstance(myProject);
myFavoritesTreeStructure = new FavoritesTreeStructure(project);
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
root.setUserObject(myFavoritesTreeStructure.getRootElement());
final DefaultTreeModel treeModel = new DefaultTreeModel(root);
myTree = new DnDAwareTree(treeModel);
myBuilder = new FavoritesViewTreeBuilder(myProject, myTree, treeModel, myFavoritesTreeStructure);
DockManager.getInstance(project).register(this);
TreeUtil.installActions(myTree);
UIUtil.setLineStyleAngled(myTree);
myTree.setRootVisible(false);
myTree.setShowsRootHandles(true);
myTree.setLargeModel(true);
new TreeSpeedSearch(myTree);
ToolTipManager.sharedInstance().registerComponent(myTree);
final FavoritesComparator favoritesComparator =
new FavoritesComparator(ProjectView.getInstance(project), FavoritesProjectViewPane.ID);
myBuilder.setNodeDescriptorComparator(new Comparator<NodeDescriptor>() {
@Override
public int compare(NodeDescriptor o1, NodeDescriptor o2) {
if (o1 instanceof FavoritesTreeNodeDescriptor && o2 instanceof FavoritesTreeNodeDescriptor) {
final FavoritesListNode listNode1 = FavoritesTreeUtil.extractParentList((FavoritesTreeNodeDescriptor)o1);
final FavoritesListNode listNode2 = FavoritesTreeUtil.extractParentList((FavoritesTreeNodeDescriptor)o2);
if (listNode1.equals(listNode2)) {
final Comparator<FavoritesTreeNodeDescriptor> comparator = myFavoritesManager.getCustomComparator(listNode1.getName());
if (comparator != null) {
return comparator.compare((FavoritesTreeNodeDescriptor)o1, (FavoritesTreeNodeDescriptor)o2);
}
else {
return favoritesComparator.compare(o1, o2);
}
}
}
return o1.getIndex() - o2.getIndex();
}
});
myTree.setCellRenderer(new NodeRenderer() {
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
super.customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus);
if (value instanceof DefaultMutableTreeNode) {
final DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
//only favorites roots to explain
final Object userObject = node.getUserObject();
if (userObject instanceof FavoritesTreeNodeDescriptor) {
final FavoritesTreeNodeDescriptor favoritesTreeNodeDescriptor = (FavoritesTreeNodeDescriptor)userObject;
AbstractTreeNode treeNode = favoritesTreeNodeDescriptor.getElement();
FavoritesListProvider provider = FavoritesTreeUtil.getProvider(myFavoritesManager, favoritesTreeNodeDescriptor);
if (provider != null) {
Object o = myBuilder.getUi().getElementFor(value);
if (o instanceof AbstractTreeNode) {
o = ((AbstractTreeNode)o).getValue();
}
provider.customizeRenderer(this, tree, o, selected, expanded, leaf, row, hasFocus);
return;
}
final ItemPresentation presentation = treeNode.getPresentation();
String locationString = presentation.getLocationString();
if (locationString == null &&
node.getParent() != null &&
node.getParent().getParent() != null &&
node.getParent().getParent().getParent() == null) {
final String location = favoritesTreeNodeDescriptor.getLocation();
if (location != null && location.length() > 0) {
append(" (" + location + ")", SimpleTextAttributes.GRAY_ATTRIBUTES);
}
}
}
}
}
});
myTreePopupHandler =
CustomizationUtil.installPopupHandler(myTree, IdeActions.GROUP_FAVORITES_VIEW_POPUP, ActionPlaces.FAVORITES_VIEW_POPUP);
EditSourceOnDoubleClickHandler.install(myTree);
EditSourceOnEnterKeyHandler.install(myTree);
myCopyPasteDelegator = new CopyPasteDelegator(myProject, this) {
@Override
@NotNull
protected PsiElement[] getSelectedElements() {
return getSelectedPsiElements();
}
};
AnActionButton addActionButton = AnActionButton.fromAction(ActionManager.getInstance().getAction("AddNewFavoritesList"));
addActionButton.getTemplatePresentation().setIcon(CommonActionsPanel.Buttons.ADD.getIcon());
addActionButton.setShortcut(CommonActionsPanel.getCommonShortcut(CommonActionsPanel.Buttons.ADD));
AnActionButton editActionButton = AnActionButton.fromAction(new EditFavoritesAction());
editActionButton.setShortcut(CommonShortcuts.CTRL_ENTER);
AnActionButton deleteActionButton = new DeleteFromFavoritesAction();
deleteActionButton.setShortcut(CommonActionsPanel.getCommonShortcut(CommonActionsPanel.Buttons.REMOVE));
//final AnAction exportToTextFileAction = CommonActionsManager.getInstance().createExportToTextFileAction(createTextExporter());
//AnActionButton exportActionButton = AnActionButton.fromAction(exportToTextFileAction);
//exportActionButton.setShortcut(exportToTextFileAction.getShortcutSet());
final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTree)
.initPosition()
.disableAddAction().disableRemoveAction().disableDownAction().disableUpAction()
.addExtraAction(addActionButton)
.addExtraAction(editActionButton)
.addExtraAction(deleteActionButton);
//.addExtraAction(exportActionButton);
final AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_NEW_ELEMENT);
action.registerCustomShortcutSet(action.getShortcutSet(), myTree);
final JPanel panel = decorator.createPanel();
panel.setBorder(IdeBorderFactory.createEmptyBorder());
add(panel, BorderLayout.CENTER);
setBorder(IdeBorderFactory.createEmptyBorder());
myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() {
@Override
protected boolean isAutoScrollMode() {
return myFavoritesManager.getViewSettings().isAutoScrollToSource();
}
@Override
protected void setAutoScrollMode(boolean state) {
myFavoritesManager.getViewSettings().setAutoScrollToSource(state);
}
};
myAutoScrollToSourceHandler.install(myTree);
myFavoritesManager.addFavoritesListener(new FavoritesListener() {
@Override
public void rootsChanged() {
myBuilder.updateFromRoot();
myTree.repaint();
}
@Override
public void listAdded(String listName) {
myBuilder.updateFromRoot();
myTree.repaint();
}
@Override
public void listRemoved(String listName) {
myBuilder.updateFromRoot();
myTree.repaint();
}
});
}
private ExporterToTextFile createTextExporter() {
return new ExporterToTextFile() {
@Override
public JComponent getSettingsEditor() {
return null;
}
@Override
public void addSettingsChangedListener(ChangeListener listener) throws TooManyListenersException {
}
@Override
public void removeSettingsChangedListener(ChangeListener listener) {
}
@Override
public String getReportText() {
final StringBuilder sb = new StringBuilder();
final Object[] elements = myBuilder.getStructure().getChildElements(myBuilder.getRoot());
final TreeUtil.Traverse traverse = new TreeUtil.Traverse() {
@Override
public boolean accept(Object node) {
if (node instanceof LoadingNode) return true;
final AbstractTreeNode abstractTreeNode = (AbstractTreeNode)node;
if (sb.length() > 0) {
sb.append('\n');
}
int deepLevel = getDeepLevel((AbstractTreeNode)node);
for (int i = 1; i < deepLevel; i++) {
sb.append('\t');
}
abstractTreeNode.update();
final PresentationData presentation = abstractTreeNode.getPresentation();
sb.append(presentation.getPresentableText());
String locationString = presentation.getLocationString();
if (locationString == null) {
locationString = FavoritesTreeNodeDescriptor.getLocation(abstractTreeNode, myProject);
}
if (locationString != null) {
sb.append(" (").append(locationString).append(")");
}
return true;
}
public int getDeepLevel(AbstractTreeNode node) {
int result = 0;
while (node.getParent() != null) {
result++;
node = node.getParent();
}
return result;
}
};
for (Object element : elements) {
traverseDepth((AbstractTreeNode)element, traverse);
}
return sb.toString();
}
@Override
public String getDefaultFilePath() {
return myProject.getBasePath() + File.separator + "Favorites.txt";
}
@Override
public void exportedTo(String filePath) {
}
@Override
public boolean canExport() {
return true;
}
};
}
private static boolean traverseDepth(final AbstractTreeNode node, final TreeUtil.Traverse traverse) {
if (!traverse.accept(node)) return false;
final Collection<? extends AbstractTreeNode> children = node.getChildren();
for (AbstractTreeNode child : children) {
child.setParent(node);
if (!traverseDepth(child, traverse)) return false;
}
return true;
}
public void selectElement(final Object selector, final VirtualFile file, final boolean requestFocus) {
myBuilder.select(selector, file, requestFocus);
}
@Override
public void dispose() {
Disposer.dispose(myBuilder);
myBuilder = null;
}
public DnDAwareTree getTree() {
return myTree;
}
@NotNull
private PsiElement[] getSelectedPsiElements() {
final Object[] elements = getSelectedNodeElements();
if (elements == null) {
return PsiElement.EMPTY_ARRAY;
}
ArrayList<PsiElement> result = new ArrayList<PsiElement>();
for (Object element : elements) {
if (element instanceof PsiElement) {
result.add((PsiElement)element);
}
else if (element instanceof SmartPsiElementPointer) {
PsiElement psiElement = ((SmartPsiElementPointer)element).getElement();
if (psiElement != null) {
result.add(psiElement);
}
}
else {
for (FavoriteNodeProvider provider : Extensions.getExtensions(FavoriteNodeProvider.EP_NAME, myProject)) {
final PsiElement psiElement = provider.getPsiElement(element);
if (psiElement != null) {
result.add(psiElement);
break;
}
}
}
}
return PsiUtilCore.toPsiElementArray(result);
}
public FavoritesTreeStructure getFavoritesTreeStructure() {
return myFavoritesTreeStructure;
}
@Override
public Object getData(String dataId) {
if (CommonDataKeys.PROJECT.is(dataId)) {
return myProject;
}
if (CommonDataKeys.NAVIGATABLE.is(dataId)) {
final FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree);
return selectedNodeDescriptors.length == 1 ? selectedNodeDescriptors[0].getElement() : null;
}
if (CommonDataKeys.NAVIGATABLE_ARRAY.is(dataId)) {
final List<Navigatable> selectedElements = getSelectedElements(Navigatable.class);
return selectedElements.isEmpty() ? null : selectedElements.toArray(new Navigatable[selectedElements.size()]);
}
if (PlatformDataKeys.CUT_PROVIDER.is(dataId)) {
return myCopyPasteDelegator.getCutProvider();
}
if (PlatformDataKeys.COPY_PROVIDER.is(dataId)) {
return myCopyPasteDelegator.getCopyProvider();
}
if (PlatformDataKeys.PASTE_PROVIDER.is(dataId)) {
return myCopyPasteDelegator.getPasteProvider();
}
if (PlatformDataKeys.HELP_ID.is(dataId)) {
return "reference.toolWindows.favorites";
}
if (LangDataKeys.NO_NEW_ACTION.is(dataId)) {
return Boolean.TRUE;
}
if (CommonDataKeys.PSI_ELEMENT.is(dataId)) {
PsiElement[] elements = getSelectedPsiElements();
if (elements.length != 1) {
return null;
}
return elements[0] != null && elements[0].isValid() ? elements[0] : null;
}
if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
final PsiElement[] elements = getSelectedPsiElements();
ArrayList<PsiElement> result = new ArrayList<PsiElement>();
for (PsiElement element : elements) {
if (element.isValid()) {
result.add(element);
}
}
return result.isEmpty() ? null : PsiUtilCore.toPsiElementArray(result);
}
if (LangDataKeys.IDE_VIEW.is(dataId)) {
return myIdeView;
}
if (LangDataKeys.TARGET_PSI_ELEMENT.is(dataId)) {
return null;
}
if (LangDataKeys.MODULE_CONTEXT.is(dataId)) {
Module[] selected = getSelectedModules();
return selected != null && selected.length == 1 ? selected[0] : null;
}
if (LangDataKeys.MODULE_CONTEXT_ARRAY.is(dataId)) {
return getSelectedModules();
}
if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) {
final Object[] elements = getSelectedNodeElements();
return elements != null && elements.length >= 1 && elements[0] instanceof Module
? myDeleteModuleProvider
: myDeletePSIElementProvider;
}
if (ModuleGroup.ARRAY_DATA_KEY.is(dataId)) {
final List<ModuleGroup> selectedElements = getSelectedElements(ModuleGroup.class);
return selectedElements.isEmpty() ? null : selectedElements.toArray(new ModuleGroup[selectedElements.size()]);
}
if (LibraryGroupElement.ARRAY_DATA_KEY.is(dataId)) {
final List<LibraryGroupElement> selectedElements = getSelectedElements(LibraryGroupElement.class);
return selectedElements.isEmpty() ? null : selectedElements.toArray(new LibraryGroupElement[selectedElements.size()]);
}
if (NamedLibraryElement.ARRAY_DATA_KEY.is(dataId)) {
final List<NamedLibraryElement> selectedElements = getSelectedElements(NamedLibraryElement.class);
return selectedElements.isEmpty() ? null : selectedElements.toArray(new NamedLibraryElement[selectedElements.size()]);
}
if (CONTEXT_FAVORITES_ROOTS_DATA_KEY.is(dataId)) {
List<FavoritesTreeNodeDescriptor> result = new ArrayList<FavoritesTreeNodeDescriptor>();
FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree);
for (FavoritesTreeNodeDescriptor selectedNodeDescriptor : selectedNodeDescriptors) {
if (FavoritesTreeUtil.getProvider(myFavoritesManager, selectedNodeDescriptor) != null) {
continue;
}
FavoritesTreeNodeDescriptor root = selectedNodeDescriptor.getFavoritesRoot();
if (root != null && root.getElement() instanceof FavoritesListNode) {
result.add(selectedNodeDescriptor);
}
}
return result.toArray(new FavoritesTreeNodeDescriptor[result.size()]);
}
if (FAVORITES_TREE_KEY.is(dataId)) {
return myTree;
}
if (FAVORITES_TREE_BUILDER_KEY.is(dataId)) {
return myBuilder;
}
if (FAVORITES_LIST_NAME_DATA_KEY.is(dataId)) {
final FavoritesTreeNodeDescriptor[] descriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree);
Set<String> selectedNames = new HashSet<String>();
for (FavoritesTreeNodeDescriptor descriptor : descriptors) {
FavoritesListNode node = FavoritesTreeUtil.extractParentList(descriptor);
if (node != null) {
selectedNames.add(node.getValue());
}
}
if (selectedNames.size() == 1) {
return selectedNames.iterator().next();
}
return null;
}
FavoritesTreeNodeDescriptor[] descriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree);
if (descriptors.length > 0) {
List<AbstractTreeNode> nodes = new ArrayList<AbstractTreeNode>();
for (FavoritesTreeNodeDescriptor descriptor : descriptors) {
nodes.add(descriptor.getElement());
}
return myFavoritesTreeStructure.getDataFromProviders(nodes, dataId);
}
return null;
}
private Set<FavoritesListNode> getSelectedListsNodes() {
final Set<FavoritesListNode> result = new HashSet<FavoritesListNode>();
final FavoritesTreeNodeDescriptor[] descriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree);
for (FavoritesTreeNodeDescriptor descriptor : descriptors) {
final FavoritesListNode listNode = FavoritesTreeUtil.extractParentList(descriptor);
if (listNode != null) {
result.add(listNode);
}
}
return result;
}
private <T> List<T> getSelectedElements(Class<T> klass) {
final Object[] elements = getSelectedNodeElements();
ArrayList<T> result = new ArrayList<T>();
if (elements == null) {
return result;
}
for (Object element : elements) {
if (element == null) continue;
if (klass.isAssignableFrom(element.getClass())) {
result.add((T)element);
}
}
return result;
}
private Module[] getSelectedModules() {
final Object[] elements = getSelectedNodeElements();
if (elements == null) {
return null;
}
ArrayList<Module> result = new ArrayList<Module>();
for (Object element : elements) {
if (element instanceof Module) {
result.add((Module)element);
}
else if (element instanceof ModuleGroup) {
result.addAll(((ModuleGroup)element).modulesInGroup(myProject, true));
}
}
return result.isEmpty() ? null : result.toArray(new Module[result.size()]);
}
private Object[] getSelectedNodeElements() {
final FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree);
ArrayList<Object> result = new ArrayList<Object>();
for (FavoritesTreeNodeDescriptor selectedNodeDescriptor : selectedNodeDescriptors) {
if (selectedNodeDescriptor != null) {
Object value = selectedNodeDescriptor.getElement().getValue();
if (value instanceof SmartPsiElementPointer) {
value = ((SmartPsiElementPointer)value).getElement();
}
result.add(value);
}
}
return ArrayUtil.toObjectArray(result);
}
public void setupToolWindow(ToolWindowEx window) {
final CollapseAllAction collapseAction = new CollapseAllAction(myTree);
collapseAction.getTemplatePresentation().setIcon(AllIcons.General.CollapseAll);
collapseAction.getTemplatePresentation().setHoveredIcon(AllIcons.General.CollapseAllHover);
window.setTitleActions(collapseAction);
final DefaultActionGroup group = new DefaultActionGroup();
final ProjectViewDirectoryHelper helper = ProjectViewDirectoryHelper.getInstance(myProject);
if (helper.supportsFlattenPackages()) {
group.add(new FavoritesFlattenPackagesAction(myProject, myBuilder));
}
if (helper.supportsHideEmptyMiddlePackages()) {
group.add(new FavoritesCompactEmptyMiddlePackagesAction(myProject, myBuilder));
}
if (helper.supportsFlattenPackages()) {
group.addAction(new FavoritesAbbreviatePackageNamesAction(myProject, myBuilder));
}
if (!PlatformUtils.isCidr()) {
group.add(new FavoritesShowMembersAction(myProject, myBuilder));
}
final FavoritesAutoscrollFromSourceHandler handler = new FavoritesAutoscrollFromSourceHandler(myProject, myBuilder);
handler.install();
group.add(handler.createToggleAction());
group.add(new FavoritesAutoScrollToSourceAction(myProject, myAutoScrollToSourceHandler, myBuilder));
window.setAdditionalGearActions(group);
}
public static String getQualifiedName(final VirtualFile file) {
return file.getPresentableUrl();
}
public FavoritesViewTreeBuilder getBuilder() {
return myBuilder;
}
@Nullable
FavoritesListNode findFavoritesListNode(Point point) {
final TreePath path = myTree.getClosestPathForLocation(point.x, point.y);
final FavoritesListNode node = getListNodeFromPath(path);
return node == null ? (FavoritesListNode)((FavoritesRootNode)myFavoritesTreeStructure.getRootElement()).getChildren().iterator().next()
: node;
}
static FavoritesListNode getListNodeFromPath(TreePath path) {
if (path != null && path.getPathCount() > 1) {
final Object o = path.getPath()[1];
if (o instanceof DefaultMutableTreeNode) {
final Object obj = ((DefaultMutableTreeNode)o).getUserObject();
if (obj instanceof FavoritesTreeNodeDescriptor) {
final AbstractTreeNode node = ((FavoritesTreeNodeDescriptor)obj).getElement();
if (node instanceof FavoritesListNode) {
return (FavoritesListNode)node;
}
}
}
}
return null;
}
void dropPsiElements(FavoritesManager mgr, FavoritesListNode node, PsiElement[] elements) {
if (elements != null && elements.length > 0) {
final ArrayList<AbstractTreeNode> nodes = new ArrayList<AbstractTreeNode>();
for (PsiElement element : elements) {
if (element instanceof SmartPsiElementPointer) {
element = ((SmartPsiElementPointer)element).getElement();
}
final Collection<AbstractTreeNode> tmp = AddToFavoritesAction
.createNodes(myProject, null, element, true, FavoritesManager.getInstance(myProject).getViewSettings());
nodes.addAll(tmp);
mgr.addRoots(node.getValue(), nodes);
}
myBuilder.select(nodes.toArray(), null);
}
}
private final class MyDeletePSIElementProvider implements DeleteProvider {
@Override
public boolean canDeleteElement(@NotNull DataContext dataContext) {
final PsiElement[] elements = getElementsToDelete();
return DeleteHandler.shouldEnableDeleteAction(elements);
}
@Override
public void deleteElement(@NotNull DataContext dataContext) {
List<PsiElement> allElements = Arrays.asList(getElementsToDelete());
List<PsiElement> validElements = new ArrayList<PsiElement>();
for (PsiElement psiElement : allElements) {
if (psiElement != null && psiElement.isValid()) validElements.add(psiElement);
}
final PsiElement[] elements = PsiUtilCore.toPsiElementArray(validElements);
LocalHistoryAction a = LocalHistory.getInstance().startAction(IdeBundle.message("progress.deleting"));
try {
DeleteHandler.deletePsiElement(elements, myProject);
}
finally {
a.finish();
}
}
private PsiElement[] getElementsToDelete() {
ArrayList<PsiElement> result = new ArrayList<PsiElement>();
Object[] elements = getSelectedNodeElements();
for (int idx = 0; elements != null && idx < elements.length; idx++) {
if (elements[idx] instanceof PsiElement) {
final PsiElement element = (PsiElement)elements[idx];
result.add(element);
if (element instanceof PsiDirectory) {
final VirtualFile virtualFile = ((PsiDirectory)element).getVirtualFile();
final String path = virtualFile.getPath();
if (path.endsWith(JarFileSystem.JAR_SEPARATOR)) { // if is jar-file root
final VirtualFile vFile =
LocalFileSystem.getInstance().findFileByPath(path.substring(0, path.length() - JarFileSystem.JAR_SEPARATOR.length()));
if (vFile != null) {
final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile);
if (psiFile != null) {
elements[idx] = psiFile;
}
}
}
}
}
}
return PsiUtilCore.toPsiElementArray(result);
}
}
private final class MyIdeView implements IdeView {
@Override
public void selectElement(final PsiElement element) {
if (element != null) {
selectPsiElement(element, false);
boolean requestFocus = true;
final boolean isDirectory = element instanceof PsiDirectory;
if (!isDirectory) {
Editor editor = EditorHelper.openInEditor(element);
if (editor != null) {
ToolWindowManager.getInstance(myProject).activateEditorComponent();
requestFocus = false;
}
}
if (requestFocus) {
selectPsiElement(element, true);
}
}
}
private void selectPsiElement(PsiElement element, boolean requestFocus) {
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
FavoritesTreeViewPanel.this.selectElement(element, virtualFile, requestFocus);
}
@Nullable
private PsiDirectory[] getSelectedDirectories() {
if (myBuilder == null) return null;
final Object[] selectedNodeElements = getSelectedNodeElements();
if (selectedNodeElements.length != 1) return null;
for (FavoriteNodeProvider nodeProvider : Extensions.getExtensions(FavoriteNodeProvider.EP_NAME, myProject)) {
final PsiElement psiElement = nodeProvider.getPsiElement(selectedNodeElements[0]);
if (psiElement instanceof PsiDirectory) {
return new PsiDirectory[]{(PsiDirectory)psiElement};
}
else if (psiElement instanceof PsiDirectoryContainer) {
final String moduleName = nodeProvider.getElementModuleName(selectedNodeElements[0]);
GlobalSearchScope searchScope = GlobalSearchScope.projectScope(myProject);
if (moduleName != null) {
final Module module = ModuleManager.getInstance(myProject).findModuleByName(moduleName);
if (module != null) {
searchScope = GlobalSearchScope.moduleScope(module);
}
}
return ((PsiDirectoryContainer)psiElement).getDirectories(searchScope);
}
else if (psiElement != null) {
PsiFile file = psiElement.getContainingFile();
if (file != null) {
PsiDirectory parent = file.getParent();
if (parent != null) {
return new PsiDirectory[]{parent};
}
}
}
}
return selectedNodeElements[0] instanceof PsiDirectory ? new PsiDirectory[]{(PsiDirectory)selectedNodeElements[0]} : null;
}
@Override
public PsiDirectory[] getDirectories() {
final PsiDirectory[] directories = getSelectedDirectories();
return directories == null ? PsiDirectory.EMPTY_ARRAY : directories;
}
@Override
public PsiDirectory getOrChooseDirectory() {
return DirectoryChooserUtil.getOrChooseDirectory(this);
}
}
//DockContainer methods
@Override
public RelativeRectangle getAcceptArea() {
return new RelativeRectangle(myTree);
}
@NotNull
@Override
public ContentResponse getContentResponse(@NotNull DockableContent content, RelativePoint point) {
if (content.getKey() instanceof VirtualFile) {
return ContentResponse.ACCEPT_COPY;
}
return ContentResponse.DENY;
}
@Override
public JComponent getContainerComponent() {
return this;
}
@Override
public void add(@NotNull DockableContent content, RelativePoint dropTarget) {
if (content.getKey() instanceof VirtualFile) {
VirtualFile vFile = (VirtualFile)content.getKey();
final PsiFileSystemItem psiFile = vFile.isDirectory()
? PsiManager.getInstance(myProject).findDirectory(vFile)
: PsiManager.getInstance(myProject).findFile(vFile);
Point p = dropTarget.getScreenPoint();
SwingUtilities.convertPointFromScreen(p, myTree);
FavoritesListNode node = findFavoritesListNode(p);
if (node != null && psiFile != null) {
dropPsiElements(myFavoritesManager, node, new PsiElement[]{psiFile});
}
}
}
@Override
public void closeAll() {
}
@Override
public void addListener(Listener listener, Disposable parent) {
throw new UnsupportedOperationException("Method is not supported");
}
@Override
public boolean isEmpty() {
return myTree.isEmpty();
}
@Nullable
@Override
public Image startDropOver(@NotNull DockableContent content, RelativePoint point) {
return null;
}
@Nullable
@Override
public Image processDropOver(@NotNull DockableContent content, RelativePoint point) {
Point p = point.getScreenPoint();
SwingUtilities.convertPointFromScreen(p, myTree);
TreePath treePath = myTree.getClosestPathForLocation(p.x, p.y);
FavoritesListNode node = getListNodeFromPath(treePath);
treePath = node != null ? myTree.getPath(node) : null;
if (treePath != null) {
myTree.setSelectionPath(treePath);
}
return null;
}
@Override
public void resetDropOver(@NotNull DockableContent content) {
}
@Override
public boolean isDisposeWhenEmpty() {
return false;
}
@Override
public void showNotify() {
}
@Override
public void hideNotify() {
}
}