diff --git a/platform/lang-api/src/com/intellij/openapi/actionSystem/LangDataKeys.java b/platform/lang-api/src/com/intellij/openapi/actionSystem/LangDataKeys.java index 0150e9b5ba69..a7235246ee96 100644 --- a/platform/lang-api/src/com/intellij/openapi/actionSystem/LangDataKeys.java +++ b/platform/lang-api/src/com/intellij/openapi/actionSystem/LangDataKeys.java @@ -49,6 +49,7 @@ public class LangDataKeys extends PlatformDataKeys { * Returns {@link com.intellij.ide.IdeView} (one of project, packages, commander or favorites view). */ public static final DataKey IDE_VIEW = DataKey.create("IDEView"); + public static final DataKey NO_NEW_ACTION = DataKey.create("IDEview.no.create.element.action"); public static final DataKey> PRESELECT_NEW_ACTION_CONDITION = DataKey.create("newElementAction.preselect.id"); public static final DataKey TARGET_PSI_ELEMENT = DataKey.create("psi.TargetElement"); diff --git a/platform/lang-api/src/com/intellij/usageView/UsageInfo.java b/platform/lang-api/src/com/intellij/usageView/UsageInfo.java index 37aacd8539e5..719c0fe54db2 100644 --- a/platform/lang-api/src/com/intellij/usageView/UsageInfo.java +++ b/platform/lang-api/src/com/intellij/usageView/UsageInfo.java @@ -69,6 +69,31 @@ public class UsageInfo { this.isNonCodeUsage = isNonCodeUsage; } + public UsageInfo(@NotNull SmartPsiElementPointer smartPointer, + SmartPsiFileRange psiFileRange, boolean dynamicUsage, + boolean nonCodeUsage) { + myDynamicUsage = dynamicUsage; + isNonCodeUsage = nonCodeUsage; + myPsiFileRange = psiFileRange; + mySmartPointer = smartPointer; + } + + public SmartPsiElementPointer getSmartPointer() { + return mySmartPointer; + } + + public SmartPsiFileRange getPsiFileRange() { + return myPsiFileRange; + } + + public boolean isNonCodeUsage() { + return isNonCodeUsage; + } + + public void setDynamicUsage(boolean dynamicUsage) { + myDynamicUsage = dynamicUsage; + } + public UsageInfo(@NotNull PsiElement element, boolean isNonCodeUsage) { this(element, -1, -1, isNonCodeUsage); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/NewElementAction.java b/platform/lang-impl/src/com/intellij/ide/actions/NewElementAction.java index b5b2d40817db..31d879ea72e1 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/NewElementAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/NewElementAction.java @@ -90,6 +90,10 @@ public class NewElementAction extends AnAction implements DumbAware, PopupActio presentation.setEnabled(false); return; } + if (Boolean.TRUE.equals(LangDataKeys.NO_NEW_ACTION.getData(context))) { + presentation.setEnabled(false); + return; + } final IdeView ideView = LangDataKeys.IDE_VIEW.getData(context); if (ideView == null) { presentation.setEnabled(false); diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/Concept.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/Concept.java new file mode 100644 index 000000000000..e4a2d3c57b1f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/Concept.java @@ -0,0 +1,27 @@ +/* + * 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.favoritesTreeView; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/1/12 + * Time: 2:14 PM + */ +public class Concept { + private String myTagName; + private String myDescription; +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListNode.java index a667fcc1a413..2415484f26ce 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListNode.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListNode.java @@ -22,6 +22,7 @@ import com.intellij.ide.projectView.impl.AbstractUrl; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.util.TreeItem; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -35,17 +36,23 @@ import java.util.List; public class FavoritesListNode extends AbstractTreeNode { private final Project myProject; private final String myListName; + private final boolean myAllowsTree; - protected FavoritesListNode(Project project, String listName) { + protected FavoritesListNode(Project project, String listName, boolean tree) { super(project, listName); myProject = project; myListName = listName; + myAllowsTree = tree; + } + + public boolean isAllowsTree() { + return myAllowsTree; } @NotNull @Override public Collection getChildren() { - return getFavoritesRoots(myProject, myListName); + return getFavoritesRoots(myProject, myListName, this); } @Override @@ -54,32 +61,53 @@ public class FavoritesListNode extends AbstractTreeNode { presentation.setPresentableText(myListName); } - @NotNull public static Collection getFavoritesRoots(Project project, String listName) { - final Collection> pairs = FavoritesManager.getInstance(project).getFavoritesListRootUrls(listName); + @NotNull public static Collection getFavoritesRoots(Project project, String listName, final FavoritesListNode listNode) { + final Collection>> pairs = FavoritesManager.getInstance(project).getFavoritesListRootUrls(listName); if (pairs == null) return Collections.emptyList(); - return createFavoriteRoots(project, pairs); + return createFavoriteRoots(project, pairs, listNode); } @NotNull - private static Collection createFavoriteRoots(Project project, @NotNull Collection> urls) { - List result = new ArrayList(); - for (Pair pair : urls) { - AbstractUrl abstractUrl = pair.getFirst(); + private static Collection createFavoriteRoots(Project project, @NotNull Collection>> urls, + final AbstractTreeNode me) { + Collection result = new ArrayList(); + processUrls(project, urls, result, me); + return result; + } + + private static void processUrls(Project project, + Collection>> urls, + Collection result, final AbstractTreeNode me) { + for (TreeItem> pair : urls) { + AbstractUrl abstractUrl = pair.getData().getFirst(); final Object[] path = abstractUrl.createPath(project); if (path == null || path.length < 1 || path[0] == null) { continue; } try { - final String className = pair.getSecond(); + final String className = pair.getData().getSecond(); @SuppressWarnings("unchecked") final Class nodeClass = (Class)Class.forName(className); - final AbstractTreeNode node = ProjectViewNode.createTreeNode(nodeClass, project, path[path.length - 1], FavoritesManager.getInstance(project).getViewSettings()); + final AbstractTreeNode node = ProjectViewNode + .createTreeNode(nodeClass, project, path[path.length - 1], FavoritesManager.getInstance(project).getViewSettings()); + node.setParent(me); + node.setIndex(result.size()); result.add(node); + + if (node instanceof ProjectViewNodeWithChildrenList) { + final List>> children = pair.getChildren(); + if (children != null && ! children.isEmpty()) { + Collection childList = new ArrayList(); + processUrls(project, children, childList, node); + for (AbstractTreeNode treeNode : childList) { + ((ProjectViewNodeWithChildrenList)node).addChild(treeNode); + } + } + } } catch (Exception ignored) { } } - return result; - } + } } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListProvider.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListProvider.java new file mode 100644 index 000000000000..a80ab7f13fa9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesListProvider.java @@ -0,0 +1,51 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.dnd.aware.DnDAwareTree; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; + +import javax.swing.tree.TreeCellRenderer; +import java.util.Comparator; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 4:17 PM + */ +public interface FavoritesListProvider { + ExtensionPointName EP_NAME = new ExtensionPointName("com.intellij.favoritesListProvider"); + + String getListName(final Project project); + boolean canBeRemoved(); + boolean isTreeLike(); + + Comparator getNodeDescriptorComparator(); + + Operation getCustomDeleteOperation(); + Operation getCustomAddOperation(); + Operation getCustomEditOperation(); + + TreeCellRenderer getTreeCellRenderer(); + + interface Operation { + boolean willHandle(final DnDAwareTree tree); + String getCustomName(); + void handle(Project project, final DnDAwareTree tree); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesManager.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesManager.java index 44744c76c999..80d1f6a7118e 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesManager.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesManager.java @@ -34,21 +34,31 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; +import com.intellij.util.TreeItem; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.tree.TreeCellRenderer; import java.util.*; public class FavoritesManager implements ProjectComponent, JDOMExternalizable { // fav list name -> list of (root: root url, root class) - private final Map>> myName2FavoritesRoots = - new LinkedHashMap>>(); + private final Map>>> myName2FavoritesRoots = + new LinkedHashMap>>>(); + private final Set myReadOnlyLists = new HashSet(); + private final Set myAllowsTreeLists = new HashSet(); private final Project myProject; private final List myListeners = new ArrayList(); private final FavoritesViewSettings myViewSettings = new FavoritesViewSettings(); - + private final Map myEditHandlers = new HashMap(); + private final Map myAddHandlers = new HashMap(); + private final Map myDeleteHandlers = new HashMap(); + private final Map myCustomRenderers = new HashMap(); + private final Map> myComparators = new HashMap>(); + private final FavoritesListener fireListeners = new FavoritesListener() { public void rootsChanged(String listName) { FavoritesListener[] listeners = myListeners.toArray(new FavoritesListener[myListeners.size()]); @@ -79,6 +89,31 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { myListeners.remove(listener); } + public synchronized FavoritesListProvider.Operation getCustomAdd(final String name) { + return myAddHandlers.get(name); + } + + public synchronized FavoritesListProvider.Operation getCustomEdit(final String name) { + return myEditHandlers.get(name); + } + + public synchronized FavoritesListProvider.Operation getCustomDelete(final String name) { + return myDeleteHandlers.get(name); + } + + public void removeRootByIndexes(String name, List elementsIndexes) { + List>> list = getFavoritesListRootUrls(name); + assert list != null; + for (Integer index : elementsIndexes.subList(0, elementsIndexes.size() - 1)) { + assert index >= 0 && index < list.size(); + final TreeItem> item = list.get(index); + list = item.getChildren(); + } + assert list != null && ! list.isEmpty(); + list.remove(elementsIndexes.get(elementsIndexes.size() - 1).intValue()); + fireListeners.rootsChanged(name); + } + public static FavoritesManager getInstance(Project project) { return project.getComponent(FavoritesManager.class); } @@ -87,31 +122,45 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { myProject = project; } - @NotNull public String[] getAvailableFavoritesLists(){ + @NotNull public String[] getAvailableFavoritesListNames(){ final Set keys = myName2FavoritesRoots.keySet(); return ArrayUtil.toStringArray(keys); } - public synchronized void createNewList(@NotNull String name){ - myName2FavoritesRoots.put(name, new LinkedHashSet>()); + public synchronized boolean allowsTree(@NotNull final String name) { + return myAllowsTreeLists.contains(name); + } + + public synchronized void createNewList(@NotNull String name, boolean readOnly, boolean allowsTree){ + myName2FavoritesRoots.put(name, new ArrayList>>()); + if (readOnly) { + myReadOnlyLists.add(name); + } + if (allowsTree) { + myAllowsTreeLists.add(name); + } fireListeners.listAdded(name); } + public synchronized void fireListeners(@NotNull final String listName) { + fireListeners.rootsChanged(listName); + } + public FavoritesViewSettings getViewSettings() { return myViewSettings; } public synchronized boolean removeFavoritesList(@NotNull String name){ - if (name.equals(myProject.getName())) return false; + if (myReadOnlyLists.contains(name)) return false; boolean result = myName2FavoritesRoots.remove(name) != null; fireListeners.listRemoved(name); return result; } @NotNull - public Collection> getFavoritesListRootUrls(@NotNull String name) { - final LinkedHashSet> pairs = myName2FavoritesRoots.get(name); - return pairs == null ? Collections.>emptyList() : pairs; + public List>> getFavoritesListRootUrls(@NotNull String name) { + final List>> pairs = myName2FavoritesRoots.get(name); + return pairs == null ? Collections.>>emptyList() : pairs; } public synchronized boolean addRoots(@NotNull String name, Module moduleContext, @NotNull Object elements) { @@ -119,27 +168,139 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { return !nodes.isEmpty() && addRoots(name, nodes); } + public synchronized Comparator getCustomComparator(@NotNull final String name) { + return myComparators.get(name); + } + + private Pair createPairForNode(AbstractTreeNode node) { + final String className = node.getClass().getName(); + final Object value = node.getValue(); + final AbstractUrl url = createUrlByElement(value, myProject); + if (url == null) return null; + return Pair.create(url, className); + } + public boolean addRoots(final String name, final Collection nodes) { - final Collection> list = getFavoritesListRootUrls(name); + final Collection>> list = getFavoritesListRootUrls(name); for (AbstractTreeNode node : nodes) { - final String className = node.getClass().getName(); - final Object value = node.getValue(); - final AbstractUrl url = createUrlByElement(value, myProject); - if (url != null) { - list.add(Pair.create(url, className)); + final Pair pair = createPairForNode(node); + if (pair != null) { + final TreeItem> treeItem = new TreeItem>(pair); + list.add(treeItem); + appendChildNodes(node, treeItem); } } fireListeners.rootsChanged(name); return true; } - public synchronized boolean removeRoot(@NotNull String name, @NotNull Object element) { - AbstractUrl url = createUrlByElement(element, myProject); + private void appendChildNodes(AbstractTreeNode node, TreeItem> treeItem) { + final Collection children = node.getChildren(); + for (AbstractTreeNode child : children) { + final TreeItem> childTreeItem = new TreeItem>(createPairForNode(child)); + treeItem.addChild(childTreeItem); + appendChildNodes(child, childTreeItem); + } + } + + public synchronized boolean addRoot(@NotNull String name, + @NotNull List parentElements, + final AbstractTreeNode newElement, + @Nullable AbstractTreeNode sibling) { + final List>> items = myName2FavoritesRoots.get(name); + if (items == null) return false; + AbstractUrl url = createUrlByElement(newElement.getValue(), myProject); if (url == null) return false; - Collection> list = getFavoritesListRootUrls(name); - Pair found = null; - for (Pair pair : list) { - if (url.equals(pair.getFirst())) { + final TreeItem> newItem = + new TreeItem>(Pair.create(url, newElement.getClass().getName())); + + if (parentElements.isEmpty()) { + // directly to list + if (sibling != null) { + TreeItem> after = null; + AbstractUrl siblingUrl = createUrlByElement(sibling.getValue(), myProject); + int idx = -1; + for (int i = 0; i < items.size(); i++) { + TreeItem> item = items.get(i); + if (item.getData().getFirst().equals(siblingUrl)) { + idx = i; + break; + } + } + if (idx != -1) { + items.add(idx, newItem); + } else { + items.add(newItem); + } + } else { + items.add(newItem); + } + + fireListeners.rootsChanged(name); + return true; + } + + Collection>> list = items; + TreeItem> item = null; + for (AbstractTreeNode obj : parentElements) { + item = findNextItem(obj, list); + if (item == null) return false; + list = item.getChildren(); + } + + if (sibling != null) { + TreeItem> after = null; + AbstractUrl siblingUrl = createUrlByElement(sibling.getValue(), myProject); + for (TreeItem> treeItem : list) { + if (treeItem.getData().getFirst().equals(siblingUrl)) { + after = treeItem; + break; + } + } + if (after == null) { + item.addChild(newItem); + } else { + item.addChildAfter(newItem, after); + } + } else { + item.addChild(newItem); + } + fireListeners.rootsChanged(name); + return true; + } + + public synchronized boolean editRoot(@NotNull String name, @NotNull List elementsIndexes, final AbstractTreeNode newElement) { + List>> list = getFavoritesListRootUrls(name); + assert list != null; + for (Integer index : elementsIndexes.subList(0, elementsIndexes.size() - 1)) { + assert index >= 0 && index < list.size(); + final TreeItem> item = list.get(index); + list = item.getChildren(); + } + assert list != null && ! list.isEmpty(); + final Object value = newElement.getValue(); + final AbstractUrl urlByElement = createUrlByElement(value, myProject); + if (urlByElement == null) return false; + list.set(elementsIndexes.get(elementsIndexes.size() - 1).intValue(), new TreeItem>(Pair.create(urlByElement, newElement.getClass().getName()))); + return true; + } + + public synchronized boolean removeRoot(@NotNull String name, @NotNull List elements) { + Collection>> list = getFavoritesListRootUrls(name); + if (elements.size() > 1) { + final List sublist = elements.subList(0, elements.size() - 1); + for (AbstractTreeNode obj : sublist) { + final TreeItem> item = findNextItem(obj, list); + if (item == null || item.getChildren() == null) return false; + list = item.getChildren(); + } + } + + TreeItem> found = null; + AbstractUrl url = createUrlByElement(elements.get(elements.size() - 1).getValue(), myProject); + if (url == null) return false; + for (TreeItem> pair : list) { + if (url.equals(pair.getData().getFirst())) { found = pair; break; } @@ -149,11 +310,23 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { fireListeners.rootsChanged(name); return true; } + return false; } + private TreeItem> findNextItem(AbstractTreeNode obj, Collection>> list) { + AbstractUrl url = createUrlByElement(obj.getValue(), myProject); + for (TreeItem> pair : list) { + if (url.equals(pair.getData().getFirst())) { + return pair; + } + } + return null; + } + public synchronized boolean renameFavoritesList(@NotNull String oldName, @NotNull String newName) { - LinkedHashSet> list = myName2FavoritesRoots.remove(oldName); + if (myReadOnlyLists.contains(oldName)) return false; + List>> list = myName2FavoritesRoots.remove(oldName); if (list != null && newName.length() > 0) { myName2FavoritesRoots.put(newName, list); fireListeners.listRemoved(oldName); @@ -163,6 +336,10 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { return false; } + public synchronized boolean isReadOnly(@NotNull final String listName) { + return myReadOnlyLists.contains(listName); + } + public void initComponent() { } @@ -171,9 +348,34 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { public void projectOpened() { StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() { public void run() { - if (myName2FavoritesRoots.isEmpty()) { - final String name = myProject.getName(); - createNewList(name); + final FavoritesListProvider[] extensions = Extensions.getExtensions(FavoritesListProvider.EP_NAME, myProject); + for (FavoritesListProvider extension : extensions) { + final String name = extension.getListName(myProject); + if (! myName2FavoritesRoots.containsKey(name)) { + createNewList(name, extension.canBeRemoved(), extension.isTreeLike()); + } else if (! myReadOnlyLists.contains(name) && ! extension.canBeRemoved()) { + myReadOnlyLists.add(name); + } + final FavoritesListProvider.Operation addOperation = extension.getCustomAddOperation(); + if (! myAddHandlers.containsKey(name)) { + myAddHandlers.put(name, addOperation); + } + final FavoritesListProvider.Operation editOperation = extension.getCustomEditOperation(); + if (! myEditHandlers.containsKey(name)) { + myEditHandlers.put(name, editOperation); + } + final FavoritesListProvider.Operation deleteOperation = extension.getCustomDeleteOperation(); + if (! myDeleteHandlers.containsKey(name)) { + myDeleteHandlers.put(name, deleteOperation); + } + final TreeCellRenderer treeCellRenderer = extension.getTreeCellRenderer(); + if (treeCellRenderer != null && ! myCustomRenderers.containsKey(name)) { + myCustomRenderers.put(name, treeCellRenderer); + } + final Comparator comparator = extension.getNodeDescriptorComparator(); + if (comparator != null && ! myComparators.containsKey(name)) { + myComparators.put(name, comparator); + } } final MyRootsChangeAdapter myPsiTreeChangeAdapter = new MyRootsChangeAdapter(); @@ -190,11 +392,15 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { return "FavoritesManager"; } + public synchronized TreeCellRenderer getCustomRenderer(@NotNull final String name) { + return myCustomRenderers.get(name); + } + public void readExternal(Element element) throws InvalidDataException { myName2FavoritesRoots.clear(); for (Object list : element.getChildren(ELEMENT_FAVORITES_LIST)) { final String name = ((Element)list).getAttributeValue(ATTRIBUTE_NAME); - LinkedHashSet> roots = readRoots((Element)list, myProject); + List>> roots = readRoots((Element)list, myProject); myName2FavoritesRoots.put(name, roots); } DefaultJDOMExternalizer.readExternal(this, element); @@ -204,16 +410,26 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { @NonNls private static final String FAVORITES_ROOT = "favorite_root"; @NonNls private static final String ELEMENT_FAVORITES_LIST = "favorites_list"; @NonNls private static final String ATTRIBUTE_NAME = "name"; - private static LinkedHashSet> readRoots(final Element list, Project project) { - LinkedHashSet> result = new LinkedHashSet>(); - for (Object favorite : list.getChildren(FAVORITES_ROOT)) { - final String className = ((Element)favorite).getAttributeValue(CLASS_NAME); - final AbstractUrl abstractUrl = readUrlFromElement((Element)favorite, project); + private static List>> readRoots(final Element list, Project project) { + List>> result = new ArrayList>>(); + readFavoritesOneLevel(list, project, result); + return result; + } + + private static void readFavoritesOneLevel(Element list, Project project, Collection>> result) { + final List listChildren = list.getChildren(FAVORITES_ROOT); + if (listChildren == null || listChildren.isEmpty()) return; + + for (Object favorite : listChildren) { + final Element favoriteElement = (Element)favorite; + final String className = favoriteElement.getAttributeValue(CLASS_NAME); + final AbstractUrl abstractUrl = readUrlFromElement(favoriteElement, project); if (abstractUrl != null) { - result.add(Pair.create(abstractUrl, className)); + final TreeItem> treeItem = new TreeItem>(Pair.create(abstractUrl, className)); + result.add(treeItem); + readFavoritesOneLevel(favoriteElement, project, treeItem.getChildren()); } } - return result; } private static final ArrayList ourAbstractUrlProviders = new ArrayList(); @@ -279,18 +495,22 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { return null; } - private static void writeRoots(Element element, LinkedHashSet> roots) { - for (Pair root : roots) { - final AbstractUrl url = root.getFirst(); + private static void writeRoots(Element element, Collection>> roots) { + for (TreeItem> root : roots) { + final AbstractUrl url = root.getData().getFirst(); if (url == null) continue; final Element list = new Element(FAVORITES_ROOT); url.write(list); - list.setAttribute(CLASS_NAME, root.getSecond()); + list.setAttribute(CLASS_NAME, root.getData().getSecond()); element.addContent(list); + final List>> children = root.getChildren(); + if (children != null && ! children.isEmpty()) { + writeRoots(list, children); + } } } - + // currently only one level here.. public boolean contains(@NotNull String name, @NotNull final VirtualFile vFile){ final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); final Set find = new HashSet(); @@ -303,9 +523,9 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { } }; - Collection> urls = getFavoritesListRootUrls(name); - for (Pair pair : urls) { - AbstractUrl abstractUrl = pair.getFirst(); + Collection>> urls = getFavoritesListRootUrls(name); + for (TreeItem> pair : urls) { + AbstractUrl abstractUrl = pair.getData().getFirst(); if (abstractUrl == null) { continue; } @@ -377,6 +597,19 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { return false; } + private void iterateTreeItems(final Collection>> coll, Consumer>> consumer) { + final ArrayDeque>> queue = new ArrayDeque>>(); + queue.addAll(coll); + while (! queue.isEmpty()) { + final TreeItem> item = queue.removeFirst(); + consumer.consume(item); + final List>> children = item.getChildren(); + if (children != null && ! children.isEmpty()) { + queue.addAll(children); + } + } + } + private class MyRootsChangeAdapter extends PsiTreeChangeAdapter { public void beforeChildMovement(@NotNull final PsiTreeChangeEvent event) { final PsiElement oldParent = event.getOldParent(); @@ -393,26 +626,29 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { childUrl = new DirectoryUrl(((PsiDirectory)newParent).getVirtualFile().getUrl() + "/" + ((PsiDirectory)child).getName(), module.getName()); } + for (String listName : myName2FavoritesRoots.keySet()) { - final LinkedHashSet> roots = myName2FavoritesRoots.get(listName); - final LinkedHashSet> newRoots = new LinkedHashSet>(); - for (Pair root : roots) { - final Object[] path = root.first.createPath(myProject); - if (path == null || path.length < 1 || path[0] == null) { - continue; - } - final Object element = path[path.length - 1]; - if (element == child && childUrl != null) { - newRoots.add(Pair.create(childUrl, root.second)); - } - else { - if (element == oldParent) { - newRoots.add(Pair.create(root.first.createUrlByElement(newParent), root.second)); + final List>> roots = myName2FavoritesRoots.get(listName); + final AbstractUrl finalChildUrl = childUrl; + iterateTreeItems(roots, new Consumer>>() { + @Override + public void consume(TreeItem> item) { + final Pair root = item.getData(); + final Object[] path = root.first.createPath(myProject); + if (path == null || path.length < 1 || path[0] == null) { + return; + } + final Object element = path[path.length - 1]; + if (element == child && finalChildUrl != null) { + item.setData(Pair.create(finalChildUrl, root.second)); + } + else { + if (element == oldParent) { + item.setData(Pair.create(root.first.createUrlByElement(newParent), root.second)); + } } - newRoots.add(root); } - } - myName2FavoritesRoots.put(listName, newRoots); + }); } } } @@ -425,22 +661,26 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable { if (module == null) return; final String url = ((PsiDirectory)psiElement.getParent()).getVirtualFile().getUrl() + "/" + event.getNewValue(); final AbstractUrl childUrl = psiElement instanceof PsiFile ? new PsiFileUrl(url) : new DirectoryUrl(url, module.getName()); + for (String listName : myName2FavoritesRoots.keySet()) { - final LinkedHashSet> roots = myName2FavoritesRoots.get(listName); - final LinkedHashSet> newRoots = new LinkedHashSet>(); - for (Pair root : roots) { - final Object[] path = root.first.createPath(myProject); - if (path == null || path.length < 1 || path[0] == null) { - continue; + final List>> roots = myName2FavoritesRoots.get(listName); + iterateTreeItems(roots, new Consumer>>() { + @Override + public void consume(TreeItem> item) { + final Pair root = item.getData(); + final Object[] path = root.first.createPath(myProject); + if (path == null || path.length < 1 || path[0] == null) { + return; + } + final Object element = path[path.length - 1]; + if (element == psiElement && psiElement instanceof PsiFile) { + item.setData(Pair.create(childUrl, root.second)); + } + else { + item.setData(root); + } } - final Object element = path[path.length - 1]; - if (element == psiElement && psiElement instanceof PsiFile) { - newRoots.add(Pair.create(childUrl, root.second)); - } else { - newRoots.add(root); - } - } - myName2FavoritesRoots.put(listName, newRoots); + }); } } } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesPanel.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesPanel.java index d2e0864f3941..a2066fbed8fe 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesPanel.java @@ -34,6 +34,7 @@ import javax.swing.tree.TreePath; import java.awt.*; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; /** * @author Konstantin Bulenkov @@ -73,6 +74,7 @@ public class FavoritesPanel { return new DnDDragStartBean(""); } }) + // todo process drag-and-drop here for tasks .setTargetChecker(new DnDTargetChecker() { @Override public boolean update(DnDEvent event) { @@ -132,9 +134,9 @@ public class FavoritesPanel { final String listFrom = getListNodeFromPath(path).getValue(); if (listTo.equals(listFrom)) return; if (path.getPathCount() == 3) { - final Object element = ((FavoritesTreeNodeDescriptor)((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject()) + final AbstractTreeNode element = (AbstractTreeNode)((FavoritesTreeNodeDescriptor)((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject()) .getElement().getValue(); - mgr.removeRoot(listFrom, element); + mgr.removeRoot(listFrom, Collections.singletonList(element)); mgr.addRoots(listTo, null, element); } } @@ -143,7 +145,8 @@ public class FavoritesPanel { if (elements != null && elements.length > 0) { ArrayList nodes = new ArrayList(); for (PsiElement element : elements) { - final Collection tmp = AddToFavoritesAction.createNodes(myProject, null, element, true, FavoritesManager.getInstance(myProject).getViewSettings()); + final Collection tmp = AddToFavoritesAction + .createNodes(myProject, null, element, true, FavoritesManager.getInstance(myProject).getViewSettings()); nodes.addAll(tmp); mgr.addRoots(listTo, nodes); } @@ -171,7 +174,7 @@ public class FavoritesPanel { } return null; } - + @Nullable private FavoritesListNode findFavoritesListNode(Point point) { diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java index 3965f1a6cc87..b0c9b0a69c28 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java @@ -69,7 +69,7 @@ public class FavoritesProjectViewPane extends AbstractProjectViewPane { myProjectView.addProjectPane(FavoritesProjectViewPane.this); myFavoritesManager.addFavoritesListener(myFavoritesListener); - if (ArrayUtil.find(myFavoritesManager.getAvailableFavoritesLists(), listName) == -1) { + if (ArrayUtil.find(myFavoritesManager.getAvailableFavoritesListNames(), listName) == -1) { listName = null; } myProjectView.changeView(ID, listName); @@ -113,7 +113,7 @@ public class FavoritesProjectViewPane extends AbstractProjectViewPane { @NotNull public String[] getSubIds() { - return myFavoritesManager.getAvailableFavoritesLists(); + return myFavoritesManager.getAvailableFavoritesListNames(); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesRootNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesRootNode.java index 03b690e33698..cdbf688563de 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesRootNode.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesRootNode.java @@ -39,8 +39,9 @@ public class FavoritesRootNode extends AbstractTreeNode { public Collection getChildren() { if (myFavoritesRoots == null) { myFavoritesRoots = new ArrayList(); - for (String list : FavoritesManager.getInstance(myProject).getAvailableFavoritesLists()) { - myFavoritesRoots.add(new FavoritesListNode(myProject, list)); + final FavoritesManager favoritesManager = FavoritesManager.getInstance(myProject); + for (String list : favoritesManager.getAvailableFavoritesListNames()) { + myFavoritesRoots.add(new FavoritesListNode(myProject, list, favoritesManager.allowsTree(list))); } } return myFavoritesRoots; diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeStructure.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeStructure.java index 442685b29c7f..ba38609b0adc 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeStructure.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeStructure.java @@ -29,10 +29,10 @@ import com.intellij.psi.SmartPsiElementPointer; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.util.List; /** * @author Konstantin Bulenkov @@ -62,8 +62,10 @@ public class FavoritesTreeStructure extends ProjectTreeStructure { return super.getChildElements(favTreeElement); } - final Set result = new HashSet(); - for (AbstractTreeNode abstractTreeNode : FavoritesListNode.getFavoritesRoots(myProject, ((FavoritesListNode)element).getName())) { + final List result = new ArrayList(); + final FavoritesListNode listNode = (FavoritesListNode)element; + final Collection roots = FavoritesListNode.getFavoritesRoots(myProject, listNode.getName(), listNode); + for (AbstractTreeNode abstractTreeNode : roots) { final Object value = abstractTreeNode.getValue(); if (value == null) continue; diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeUtil.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeUtil.java new file mode 100644 index 000000000000..3abb8d3a08d1 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeUtil.java @@ -0,0 +1,120 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.dnd.aware.DnDAwareTree; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import org.jetbrains.annotations.NotNull; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/9/12 + * Time: 5:33 PM + */ +public class FavoritesTreeUtil { + @NotNull + public static FavoritesTreeNodeDescriptor[] getSelectedNodeDescriptors(final DnDAwareTree tree) { + TreePath[] path = tree.getSelectionPaths(); + if (path == null) { + return FavoritesTreeNodeDescriptor.EMPTY_ARRAY; + } + ArrayList result = new ArrayList(); + for (TreePath treePath : path) { + DefaultMutableTreeNode lastPathNode = (DefaultMutableTreeNode)treePath.getLastPathComponent(); + Object userObject = lastPathNode.getUserObject(); + if (!(userObject instanceof FavoritesTreeNodeDescriptor)) { + continue; + } + FavoritesTreeNodeDescriptor treeNodeDescriptor = (FavoritesTreeNodeDescriptor)userObject; + result.add(treeNodeDescriptor); + } + return result.toArray(new FavoritesTreeNodeDescriptor[result.size()]); + } + + public static List getLogicalPathToSelected(final DnDAwareTree tree) { + final List result = new ArrayList(); + final TreePath selectionPath = tree.getSelectionPath(); + return getLogicalPathTo(result, selectionPath); + } + + public static List getLogicalIndexPathTo(TreePath selectionPath) { + final List result = new ArrayList(); + final Object component = selectionPath.getLastPathComponent(); + if (component instanceof DefaultMutableTreeNode) { + final Object uo = ((DefaultMutableTreeNode)component).getUserObject(); + if (uo instanceof FavoritesTreeNodeDescriptor) { + AbstractTreeNode treeNode = ((FavoritesTreeNodeDescriptor)uo).getElement(); + while ((! (treeNode instanceof FavoritesListNode)) && treeNode != null) { +// final int idx = getIndex(treeNode.getParent().getChildren(), treeNode); +// if (idx == -1) return null; + result.add(treeNode.getIndex()); + treeNode = treeNode.getParent(); + } + Collections.reverse(result); + return result; + } + } + return Collections.emptyList(); + } + + /*private static int getIndex(Collection children, AbstractTreeNode node) { + int idx = 0; + for (AbstractTreeNode child : children) { + if (child == node) { + return idx; + } + ++ idx; + } + assert false; + return -1; + }*/ + + public static List getLogicalPathTo(List result, TreePath selectionPath) { + final Object component = selectionPath.getLastPathComponent(); + if (component instanceof DefaultMutableTreeNode) { + final Object uo = ((DefaultMutableTreeNode)component).getUserObject(); + if (uo instanceof FavoritesTreeNodeDescriptor) { + AbstractTreeNode treeNode = ((FavoritesTreeNodeDescriptor)uo).getElement(); + while ((! (treeNode instanceof FavoritesListNode)) && treeNode != null) { + result.add(treeNode); + treeNode = treeNode.getParent(); + } + Collections.reverse(result); + return result; + } + } + return Collections.emptyList(); + } + + public static FavoritesListNode extractParentList(FavoritesTreeNodeDescriptor descriptor) { + final AbstractTreeNode node = descriptor.getElement(); + AbstractTreeNode current = node; + while (current != null) { + if (current instanceof FavoritesListNode) { + return (FavoritesListNode) current; + } + current = current.getParent(); + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java index 510ce562be71..93cdcfe78a18 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java @@ -34,6 +34,7 @@ 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.actionSystem.*; @@ -64,11 +65,12 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; +import javax.swing.tree.TreeCellRenderer; import java.awt.*; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; /** @@ -76,12 +78,14 @@ import java.util.List; * @author Konstantin Bulenkov */ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { + public static final String NEW_FAVORITES_LIST = "New Favorites List..."; private final FavoritesTreeStructure myFavoritesTreeStructure; private FavoritesViewTreeBuilder myBuilder; private final CopyPasteDelegator myCopyPasteDelegator; private final MouseListener myTreePopupHandler; public static final DataKey CONTEXT_FAVORITES_ROOTS_DATA_KEY = DataKey.create("FavoritesRoot"); + public static final DataKey FAVORITES_TREE_KEY = DataKey.create("Favorites.Tree"); public static final DataKey FAVORITES_LIST_NAME_DATA_KEY = DataKey.create("FavoritesListName"); protected Project myProject; @@ -89,25 +93,16 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { private final MyDeletePSIElementProvider myDeletePSIElementProvider = new MyDeletePSIElementProvider(); private final ModuleDeleteProvider myDeleteModuleProvider = new ModuleDeleteProvider(); - private final AutoScrollToSourceHandler myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() { - @Override - protected boolean isAutoScrollMode() { - return FavoritesManager.getInstance(myProject).getViewSettings().isAutoScrollToSource(); - } - - @Override - protected void setAutoScrollMode(boolean state) { - FavoritesManager.getInstance(myProject).getViewSettings().setAutoScrollToSource(state); - } - }; - - + private final AutoScrollToSourceHandler myAutoScrollToSourceHandler; private final IdeView myIdeView = new MyIdeView(); + private final FavoritesManager myFavoritesManager; + private final NodeRenderer myNodeRenderer; public FavoritesTreeViewPanel(Project project) { super(new BorderLayout()); myProject = project; + myFavoritesManager = FavoritesManager.getInstance(myProject); myFavoritesTreeStructure = new FavoritesTreeStructure(project); DefaultMutableTreeNode root = new DefaultMutableTreeNode(); @@ -121,9 +116,26 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { myTree.setRootVisible(false); myTree.setShowsRootHandles(true); myTree.setLargeModel(true); + myTree.setRowHeight(0); new TreeSpeedSearch(myTree); ToolTipManager.sharedInstance().registerComponent(myTree); - myTree.setCellRenderer(new NodeRenderer() { + myBuilder.setNodeDescriptorComparator(new Comparator() { + @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 comparator = myFavoritesManager.getCustomComparator(listNode1.getName()); + if (comparator != null) { + return comparator.compare((FavoritesTreeNodeDescriptor) o1, (FavoritesTreeNodeDescriptor) o2); + } + } + } + return o1.getIndex() - o2.getIndex(); + } + }); + myNodeRenderer = new NodeRenderer() { public void customizeCellRenderer(JTree tree, Object value, boolean selected, @@ -153,6 +165,41 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { } } } + }; + myTree.setCellRenderer(new TreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean 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(); + while (treeNode != null && (!(treeNode instanceof FavoritesListNode))) { + treeNode = treeNode.getParent(); + } + if (treeNode != null) { + final String name = ((FavoritesListNode)treeNode).getValue(); + final TreeCellRenderer customRenderer = myFavoritesManager.getCustomRenderer(name); + if (customRenderer != null) { + final Component component = + customRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + if (component != null) { + return component; + } + } + } + } + } + return myNodeRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + } }); myTreePopupHandler = CustomizationUtil.installPopupHandler(myTree, IdeActions.GROUP_FAVORITES_VIEW_POPUP, ActionPlaces.FAVORITES_VIEW_POPUP); @@ -167,18 +214,41 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { } }; - ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTree) - .setAddAction(new AnActionButtonRunnable() { - @Override - public void run(AnActionButton button) { - AddNewFavoritesListAction.doAddNewFavoritesList(myProject); + final AnActionButtonRunnable addListOrNoteAction = new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + final List nodes = getSelectedListsNodes(); + if (nodes.size() == 1) { + final FavoritesListProvider.Operation customAdd = myFavoritesManager.getCustomAdd(nodes.get(0).getName()); + if (customAdd != null && customAdd.willHandle(myTree)) { + customAdd.handle(myProject, myTree); + return; + } } - }) + AddNewFavoritesListAction.doAddNewFavoritesList(myProject); + } + }; + final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTree) + .setAddAction(addListOrNoteAction) .setLineBorder(0, 0, 1, 0) - .setAddActionName("New Favorites List") + .setAddActionName(NEW_FAVORITES_LIST) .disableRemoveAction() .disableDownAction() .disableUpAction() + .setAddActionUpdater(new AnActionButtonUpdater() { + @Override + public boolean isEnabled(AnActionEvent e) { + e.getPresentation().setText(NEW_FAVORITES_LIST); + final List nodes = getSelectedListsNodes(); + if (nodes.size() == 1) { + final FavoritesListProvider.Operation customAdd = myFavoritesManager.getCustomAdd(nodes.get(0).getName()); + if (customAdd != null && customAdd.willHandle(myTree)) { + e.getPresentation().setText(customAdd.getCustomName()); + } + } + return true; + } + }) .addExtraAction(new DeleteFromFavoritesAction() { { getTemplatePresentation().setIcon(IconUtil.getRemoveIcon()); @@ -188,15 +258,54 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { public ShortcutSet getShortcut() { return CustomShortcutSet.fromString("DELETE"); } + }).addExtraAction(new AnActionButton("Edit", AllIcons.Actions.Edit) { + @Override + public ShortcutSet getShortcut() { + return CommonShortcuts.getRename(); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final List nodes = getSelectedListsNodes(); + if (nodes.size() == 1) { + final FavoritesListProvider.Operation customEdit = myFavoritesManager.getCustomEdit(nodes.get(0).getName()); + if (customEdit != null && customEdit.willHandle(myTree)) { + customEdit.handle(myProject, myTree); + } + } + } + + @Override + public boolean isEnabled() { + final List nodes = getSelectedListsNodes(); + if (nodes.size() == 1) { + final FavoritesListProvider.Operation customEdit = myFavoritesManager.getCustomEdit(nodes.get(0).getName()); + if (customEdit != null && customEdit.willHandle(myTree)) { + return true; + } + } + return false; + } }); - AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_NEW_ELEMENT); + final AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_NEW_ELEMENT); action.registerCustomShortcutSet(action.getShortcutSet(), myTree); final JPanel panel = decorator.createPanel(); panel.setBorder(IdeBorderFactory.createEmptyBorder(0)); add(panel, BorderLayout.CENTER); setBorder(IdeBorderFactory.createEmptyBorder(0)); + myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() { + @Override + protected boolean isAutoScrollMode() { + return myFavoritesManager.getViewSettings().isAutoScrollToSource(); + } + + @Override + protected void setAutoScrollMode(boolean state) { + myFavoritesManager.getViewSettings().setAutoScrollToSource(state); + } + }; myAutoScrollToSourceHandler.install(myTree); } @@ -251,7 +360,7 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { return myProject; } if (PlatformDataKeys.NAVIGATABLE.is(dataId)) { - final FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = getSelectedNodeDescriptors(); + final FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree); return selectedNodeDescriptors.length == 1 ? selectedNodeDescriptors[0].getElement() : null; } if (PlatformDataKeys.NAVIGATABLE_ARRAY.is(dataId)) { @@ -271,6 +380,9 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { if (PlatformDataKeys.HELP_ID.is(dataId)) { return "reference.toolWindows.favorites"; } + if (LangDataKeys.NO_NEW_ACTION.is(dataId)) { + return Boolean.TRUE; + } if (LangDataKeys.PSI_ELEMENT.is(dataId)) { PsiElement[] elements = getSelectedPsiElements(); if (elements.length != 1) { @@ -326,7 +438,7 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { } if (CONTEXT_FAVORITES_ROOTS_DATA_KEY.is(dataId)) { List result = new ArrayList(); - FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = getSelectedNodeDescriptors(); + FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree); for (FavoritesTreeNodeDescriptor selectedNodeDescriptor : selectedNodeDescriptors) { FavoritesTreeNodeDescriptor root = selectedNodeDescriptor.getFavoritesRoot(); if (root != null && root.getElement() instanceof FavoritesListNode) { @@ -335,8 +447,11 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { } return result.toArray(new FavoritesTreeNodeDescriptor[result.size()]); } + if (FAVORITES_TREE_KEY.is(dataId)) { + return myTree; + } if (FAVORITES_LIST_NAME_DATA_KEY.is(dataId)) { - final FavoritesTreeNodeDescriptor[] descriptors = getSelectedNodeDescriptors(); + final FavoritesTreeNodeDescriptor[] descriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree); if (descriptors.length == 1) { final AbstractTreeNode node = descriptors[0].getElement(); if (node instanceof FavoritesListNode) { @@ -345,7 +460,7 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { } return null; } - FavoritesTreeNodeDescriptor[] descriptors = getSelectedNodeDescriptors(); + FavoritesTreeNodeDescriptor[] descriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree); if (descriptors.length > 0) { List nodes = new ArrayList(); for (FavoritesTreeNodeDescriptor descriptor : descriptors) { @@ -356,6 +471,18 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { return null; } + private List getSelectedListsNodes() { + final List result = new SmartList(); + 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 List getSelectedElements(Class klass) { final Object[] elements = getSelectedNodeElements(); ArrayList result = new ArrayList(); @@ -390,7 +517,7 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { } private Object[] getSelectedNodeElements() { - final FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = getSelectedNodeDescriptors(); + final FavoritesTreeNodeDescriptor[] selectedNodeDescriptors = FavoritesTreeUtil.getSelectedNodeDescriptors(myTree); ArrayList result = new ArrayList(); for (FavoritesTreeNodeDescriptor selectedNodeDescriptor : selectedNodeDescriptors) { if (selectedNodeDescriptor != null) { @@ -404,25 +531,6 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { return ArrayUtil.toObjectArray(result); } - @NotNull - public FavoritesTreeNodeDescriptor[] getSelectedNodeDescriptors() { - TreePath[] path = myTree.getSelectionPaths(); - if (path == null) { - return FavoritesTreeNodeDescriptor.EMPTY_ARRAY; - } - ArrayList result = new ArrayList(); - for (TreePath treePath : path) { - DefaultMutableTreeNode lastPathNode = (DefaultMutableTreeNode)treePath.getLastPathComponent(); - Object userObject = lastPathNode.getUserObject(); - if (!(userObject instanceof FavoritesTreeNodeDescriptor)) { - continue; - } - FavoritesTreeNodeDescriptor treeNodeDescriptor = (FavoritesTreeNodeDescriptor)userObject; - result.add(treeNodeDescriptor); - } - return result.toArray(new FavoritesTreeNodeDescriptor[result.size()]); - } - public void setupToolWindow(ToolWindowEx window) { final CollapseAllAction collapseAction = new CollapseAllAction(myTree); collapseAction.getTemplatePresentation().setIcon(AllIcons.General.CollapseAll); diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java index ed52ffd3afee..254f0d0ce22c 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java @@ -112,7 +112,7 @@ public class FavoritesViewSelectInTarget extends SelectInTargetPsiWrapper { public static String findSuitableFavoritesList(VirtualFile file, Project project, final String currentSubId) { final FavoritesManager favoritesManager = FavoritesManager.getInstance(project); if (currentSubId != null && favoritesManager.contains(currentSubId, file)) return currentSubId; - final String[] lists = favoritesManager.getAvailableFavoritesLists(); + final String[] lists = favoritesManager.getAvailableFavoritesListNames(); for (String name : lists) { if (favoritesManager.contains(name, file)) return name; } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FileGroupingProjectNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FileGroupingProjectNode.java new file mode 100644 index 000000000000..4f7704a0e40d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FileGroupingProjectNode.java @@ -0,0 +1,87 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/8/12 + * Time: 12:23 PM + */ +public class FileGroupingProjectNode extends ProjectViewNodeWithChildrenList { + private VirtualFile myVirtualFile; + + public FileGroupingProjectNode(Project project, File file, ViewSettings viewSettings) { + super(project, file, viewSettings); + final LocalFileSystem lfs = LocalFileSystem.getInstance(); + myVirtualFile = lfs.findFileByIoFile(file); + if (myVirtualFile == null) { + myVirtualFile = lfs.refreshAndFindFileByIoFile(file); + } + } + + @Override + public boolean contains(@NotNull VirtualFile file) { + return file.equals(myVirtualFile); + } + + @Override + protected void update(PresentationData presentation) { + if (myVirtualFile != null && myVirtualFile.isDirectory()) { + presentation.setOpenIcon(AllIcons.Nodes.TreeOpen); + presentation.setClosedIcon(AllIcons.Nodes.TreeClosed); + } else if (myVirtualFile != null) { + presentation.setIcons(myVirtualFile.getFileType().getIcon()); + } else { + presentation.setIcons(AllIcons.FileTypes.Unknown); + } + presentation.setPresentableText(getValue().getName()); + } + + @Override + public VirtualFile getVirtualFile() { + return myVirtualFile; + } + + @Override + public void navigate(boolean requestFocus) { + if (myVirtualFile != null) { + new OpenFileDescriptor(myProject, myVirtualFile).navigate(requestFocus); + } + } + + // todo possibly we need file + @Override + public boolean canNavigate() { + return myVirtualFile != null && myVirtualFile.isValid(); + } + + @Override + public boolean canNavigateToSource() { + return myVirtualFile != null && myVirtualFile.isValid(); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FileSerializable.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FileSerializable.java new file mode 100644 index 000000000000..b409b84e3851 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FileSerializable.java @@ -0,0 +1,54 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.openapi.project.Project; + +import java.io.File; +import java.io.IOException; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/8/12 + * Time: 12:43 PM + */ +public class FileSerializable implements WorkingSetSerializable { + @Override + public String getId() { + return File.class.getName(); + } + + @Override + public int getVersion() { + return 0; + } + + @Override + public void serializeMe(File t, StringBuilder oos) throws IOException { + oos.append(t.getPath()); + } + + @Override + public File deserializeMe(Project project, String ois) throws IOException { + return new File(ois); + } + + @Override + public File deserializeMeInvalid(Project project, String ois) throws IOException { + return new File(ois); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/Flag.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/Flag.java new file mode 100644 index 000000000000..5d2a7805c69e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/Flag.java @@ -0,0 +1,46 @@ +/* + * 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.favoritesTreeView; + +import java.awt.*; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/1/12 + * Time: 2:03 PM + */ +public enum Flag { + orange(new Color(255,128,0)), + blue(new Color(0,102,204)), + green(new Color(0, 130,130)), + red(new Color(255,45,45)), + brown(new Color(128,64,0)), + magenta(new Color(255,0,255)), + violet(new Color(128,0,255)), + yellow(new Color(255,255,0)), + grey(new Color(140,140,140)); + + private final Color myColor; + + private Flag(Color color) { + myColor = color; + } + + public Color getColor() { + return myColor; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ImportUsagesAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ImportUsagesAction.java new file mode 100644 index 000000000000..bd837f38862c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ImportUsagesAction.java @@ -0,0 +1,69 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.project.Project; +import com.intellij.usages.Usage; +import com.intellij.usages.UsageView; + +import java.util.Collection; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/1/12 + * Time: 11:22 PM + */ +public class ImportUsagesAction extends AnAction { + public ImportUsagesAction() { + super("To Favorites", "To Favorites", AllIcons.Toolwindows.ToolWindowFavorites); + } + + @Override + public void update(AnActionEvent e) { + final DataContext dc = e.getDataContext(); + final boolean enabled = isEnabled(dc); + e.getPresentation().setEnabled(enabled); + } + + private boolean isEnabled(DataContext dc) { + final Project project = PlatformDataKeys.PROJECT.getData(dc); + final Usage[] usages = UsageView.USAGES_KEY.getData(dc); + return project != null && usages != null && usages.length > 0; + } + + @Override + public void actionPerformed(AnActionEvent e) { + final DataContext dc = e.getDataContext(); + final boolean enabled = isEnabled(dc); + if (! enabled) return; + + final Project project = PlatformDataKeys.PROJECT.getData(dc); + + final Collection nodes = new UsageFavoriteNodeProvider().getFavoriteNodes(dc, ViewSettings.DEFAULT); + final FavoritesManager favoritesManager = FavoritesManager.getInstance(project); + if (nodes != null && ! nodes.isEmpty()) { + favoritesManager.addRoots(TaskDefaultFavoriteListProvider.CURRENT_TASK, nodes); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/InvalidUsageNoteNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/InvalidUsageNoteNode.java new file mode 100644 index 000000000000..366eba3f1fec --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/InvalidUsageNoteNode.java @@ -0,0 +1,55 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.usages.TextChunk; + +import java.util.List; +import java.util.Set; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 1:26 PM + */ +public class InvalidUsageNoteNode { + private PercentDone myPercentDone = PercentDone._0; + private Set myFlags; + private Set myConcepts; + + final List myText; + + public InvalidUsageNoteNode(List text) { + myText = text; + } + + public PercentDone getPercentDone() { + return myPercentDone; + } + + public Set getFlags() { + return myFlags; + } + + public Set getConcepts() { + return myConcepts; + } + + public List getText() { + return myText; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/InvalidUsageNoteProjectNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/InvalidUsageNoteProjectNode.java new file mode 100644 index 000000000000..f1f4cd09e0c4 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/InvalidUsageNoteProjectNode.java @@ -0,0 +1,50 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.usages.TextChunk; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 1:28 PM + */ +public class InvalidUsageNoteProjectNode extends ProjectViewNodeWithChildrenList { + public InvalidUsageNoteProjectNode(Project project, InvalidUsageNoteNode node, ViewSettings viewSettings) { + super(project, node, viewSettings); + } + + @Override + public boolean contains(@NotNull VirtualFile file) { + return false; + } + + @Override + protected void update(PresentationData presentation) { + final List text = getValue().getText(); + if (! text.isEmpty()) { + UsageProjectTreeNode.updatePresentationWithTextChunks(presentation, text.toArray(new TextChunk[text.size()])); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteNode.java new file mode 100644 index 000000000000..f99fd0ffa436 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteNode.java @@ -0,0 +1,74 @@ +/* + * 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.favoritesTreeView; + +import java.util.Set; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 5/31/12 + * Time: 8:47 PM + */ +public class NoteNode { + private PercentDone myPercentDone = PercentDone._0; + private Set myFlags; + private Set myConcepts; + + private String myText; + private boolean myReadonly; + + public NoteNode(String text, boolean readonly) { + myText = text; + myReadonly = readonly; + } + + public PercentDone getPercentDone() { + return myPercentDone; + } + + public void setPercentDone(PercentDone percentDone) { + myPercentDone = percentDone; + } + + public Set getFlags() { + return myFlags; + } + + public void setFlags(Set flags) { + myFlags = flags; + } + + public Set getConcepts() { + return myConcepts; + } + + public void setConcepts(Set concepts) { + myConcepts = concepts; + } + + public String getText() { + return myText; + } + + public void setText(String text) { + myText = text; + } + + public boolean isReadonly() { + return myReadonly; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteProjectNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteProjectNode.java new file mode 100644 index 000000000000..1ea507dcfe46 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteProjectNode.java @@ -0,0 +1,52 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.FileStatus; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 12:15 PM + */ +public class NoteProjectNode extends ProjectViewNodeWithChildrenList { + public NoteProjectNode(Project project, NoteNode node, ViewSettings viewSettings) { + super(project, node, viewSettings); + } + + @Override + public boolean contains(@NotNull VirtualFile file) { + return false; + } + + @Override + public String toString() { + return getValue().getText(); + } + + @Override + protected void update(PresentationData presentation) { + presentation.setPresentableText(getValue().getText()); + // todo define own color + presentation.setForcedTextForeground(FileStatus.COLOR_SWITCHED); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteSerializable.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteSerializable.java new file mode 100644 index 000000000000..86d8847fed49 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/NoteSerializable.java @@ -0,0 +1,63 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; + +import java.io.IOException; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/9/12 + * Time: 4:11 PM + */ +public class NoteSerializable implements WorkingSetSerializable { + + @Override + public String getId() { + return NoteNode.class.getName(); + } + + @Override + public int getVersion() { + return 0; + } + + @Override + public void serializeMe(NoteNode t, StringBuilder oos) throws IOException { + oos.append(StringUtil.escapeXml(t.getText())); + oos.append("<>"); + oos.append(String.valueOf(t.isReadonly())); + oos.append("<>"); + } + + @Override + public NoteNode deserializeMe(Project project, String ois) throws IOException { + final List strings = StringUtil.split(ois, "<>", true); + if (strings.size() == 2) { + return new NoteNode(StringUtil.unescapeXml(strings.get(0)), Boolean.parseBoolean(strings.get(1))); + } + return null; + } + + @Override + public NoteNode deserializeMeInvalid(Project project, String ois) throws IOException { + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/PercentDone.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/PercentDone.java new file mode 100644 index 000000000000..0dfaa4115169 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/PercentDone.java @@ -0,0 +1,36 @@ +/* + * 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.favoritesTreeView; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/1/12 + * Time: 1:53 PM + */ +public enum PercentDone { + _0(0),_05(5),_20(20),_50(50),_70(70),_100(100); + + private final int myPercent; + + private PercentDone(int percent) { + myPercent = percent; + } + + public int getPercent() { + return myPercent; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ProjectDefaultFavoriteListProvider.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ProjectDefaultFavoriteListProvider.java new file mode 100644 index 000000000000..2b763a180133 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ProjectDefaultFavoriteListProvider.java @@ -0,0 +1,69 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.openapi.project.Project; + +import javax.swing.tree.TreeCellRenderer; +import java.util.Comparator; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 4:30 PM + */ +public class ProjectDefaultFavoriteListProvider implements FavoritesListProvider { + @Override + public String getListName(Project project) { + return project.getName(); + } + + @Override + public boolean canBeRemoved() { + return false; + } + + @Override + public boolean isTreeLike() { + return false; + } + + @Override + public Comparator getNodeDescriptorComparator() { + return null; + } + + @Override + public Operation getCustomDeleteOperation() { + return null; + } + + @Override + public Operation getCustomAddOperation() { + return null; + } + + @Override + public Operation getCustomEditOperation() { + return null; + } + + @Override + public TreeCellRenderer getTreeCellRenderer() { + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ProjectViewNodeWithChildrenList.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ProjectViewNodeWithChildrenList.java new file mode 100644 index 000000000000..08cee563a32d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/ProjectViewNodeWithChildrenList.java @@ -0,0 +1,69 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.projectView.ProjectViewNode; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 12:41 PM + */ +public abstract class ProjectViewNodeWithChildrenList extends ProjectViewNode { + protected final List myChildren; + + protected ProjectViewNodeWithChildrenList(Project project, T t, ViewSettings viewSettings) { + super(project, t, viewSettings); + myChildren = new ArrayList(); + } + + @NotNull + @Override + public Collection getChildren() { + return myChildren; + } + + public void addChild(final AbstractTreeNode node) { + myChildren.add(node); + node.setParent(this); + } + + public void addChildBefore(final AbstractTreeNode newNode, final AbstractTreeNode existingNode) { + int idx = -1; + for (int i = 0; i < myChildren.size(); i++) { + AbstractTreeNode node = myChildren.get(i); + // exactly the same node! + if (node == existingNode) { + idx = i; + break; + } + } + if (idx == -1) { + addChild(newNode); + } else { + myChildren.add(idx, newNode); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/TaskDefaultFavoriteListProvider.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/TaskDefaultFavoriteListProvider.java new file mode 100644 index 000000000000..760c10b4168e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/TaskDefaultFavoriteListProvider.java @@ -0,0 +1,283 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.dnd.aware.DnDAwareTree; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonShortcuts; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ex.MultiLineLabel; +import com.intellij.openapi.ui.popup.ComponentPopupBuilder; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.MultilineTreeCellRenderer; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.Consumer; +import com.intellij.util.ui.UIUtil; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 4:33 PM + */ +public class TaskDefaultFavoriteListProvider implements FavoritesListProvider { + public static final String CURRENT_TASK = "Current task"; + + @Override + public String getListName(Project project) { + return CURRENT_TASK; + } + + @Override + public boolean canBeRemoved() { + return false; + } + + @Override + public boolean isTreeLike() { + return false; + } + + @Override + public Comparator getNodeDescriptorComparator() { + return new Comparator() { + @Override + public int compare(FavoritesTreeNodeDescriptor o1, FavoritesTreeNodeDescriptor o2) { + return o1.getIndex() - o2.getIndex(); + } + }; + } + + @Override + public Operation getCustomDeleteOperation() { + return null; + } + + @Override + public Operation getCustomAddOperation() { + return new Operation() { + @Override + public boolean willHandle(DnDAwareTree tree) { + final int count = tree.getSelectionCount(); + if (count != 1) { + return false; + } + final TreePath path = tree.getSelectionPath(); + if (path.getPathCount() > 2) return true; + return false; + } + + @Override + public String getCustomName() { + return "New Note"; + } + + @Override + public void handle(final Project project, final DnDAwareTree tree) { + final Object component = tree.getSelectionPath().getLastPathComponent(); + if (component instanceof DefaultMutableTreeNode) { + final Object uo = ((DefaultMutableTreeNode)component).getUserObject(); + if (uo instanceof FavoritesTreeNodeDescriptor) { + final FavoritesManager favoritesManager = FavoritesManager.getInstance(project); + + final AbstractTreeNode treeNode = ((FavoritesTreeNodeDescriptor)uo).getElement(); + final NoteNode node = new NoteNode("Test text", false); + final NoteProjectNode noteNode = new NoteProjectNode(project, node, favoritesManager.getViewSettings()); + final Consumer after = new Consumer() { + @Override + public void consume(String text) { + node.setText(text); + // above it + final AbstractTreeNode parent = treeNode.getParent(); + noteNode.setParent(parent); + if (parent instanceof ProjectViewNodeWithChildrenList) { + // add through manager + //((ProjectViewNodeWithChildrenList)parent).addChildBefore(noteNode, treeNode); + final List pathToSelected = FavoritesTreeUtil.getLogicalPathToSelected(tree); + final List elements; + AbstractTreeNode sibling; + if (pathToSelected.isEmpty()) { + elements = pathToSelected; + sibling = null; + } + else { + elements = pathToSelected.subList(0, pathToSelected.size() - 1); + sibling = pathToSelected.get(pathToSelected.size() - 1); + } + favoritesManager.addRoot(CURRENT_TASK, elements, noteNode, sibling); + } else if (parent instanceof FavoritesListNode) { + favoritesManager.addRoot(CURRENT_TASK, Collections.emptyList(), noteNode, treeNode); + } + } + }; + showNotePopup(project, tree, after, ""); + } + } + } + }; + } + + private void showNotePopup(Project project, + final DnDAwareTree tree, + final Consumer after, final String initText) { + final JTextArea textArea = new JTextArea(3, 50); + textArea.setFont(UIUtil.getTreeFont()); + textArea.setText(initText); + final JBScrollPane pane = new JBScrollPane(textArea); + final ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(pane, textArea) + .setCancelOnClickOutside(true) + .setAdText(KeymapUtil.getShortcutsText(CommonShortcuts.CTRL_ENTER.getShortcuts()) + " to finish") + .setTitle("Comment") + .setMovable(true) + .setRequestFocus(true).setResizable(true).setMayBeParent(true); + final JBPopup popup = builder.createPopup(); + final JComponent content = popup.getContent(); + final AnAction action = new AnAction() { + @Override + public void actionPerformed(AnActionEvent e) { + popup.closeOk(e.getInputEvent()); + unregisterCustomShortcutSet(content); + after.consume(textArea.getText()); + } + }; + action.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, content); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + popup.showInCenterOf(tree); + } + }, ModalityState.NON_MODAL, project.getDisposed()); + } + + @Override + public Operation getCustomEditOperation() { + return new Operation() { + @Override + public boolean willHandle(DnDAwareTree tree) { + final int count = tree.getSelectionCount(); + if (count != 1) { + return false; + } + final TreePath path = tree.getSelectionPath(); + if (path.getPathCount() < 2) return false; + // todo temporarily + if (path.getLastPathComponent() instanceof DefaultMutableTreeNode) { + final Object uo = ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject(); + if (uo instanceof FavoritesTreeNodeDescriptor) { + return ((FavoritesTreeNodeDescriptor)uo).getElement() instanceof NoteProjectNode; + } + } + return false; + } + + @Override + public String getCustomName() { + return null; + } + + @Override + public void handle(Project project, final DnDAwareTree tree) { + final Object component = tree.getSelectionPath().getLastPathComponent(); + if (component instanceof DefaultMutableTreeNode) { + final Object uo = ((DefaultMutableTreeNode)component).getUserObject(); + if (uo instanceof FavoritesTreeNodeDescriptor) { + final FavoritesManager favoritesManager = FavoritesManager.getInstance(project); + + final AbstractTreeNode treeNode = ((FavoritesTreeNodeDescriptor)uo).getElement(); + + if (treeNode instanceof NoteProjectNode) { + showNotePopup(project, tree, new Consumer() { + @Override + public void consume(String s) { + ((NoteProjectNode)treeNode).getValue().setText(s); + favoritesManager.editRoot(CURRENT_TASK, FavoritesTreeUtil.getLogicalIndexPathTo(tree.getSelectionPath()), treeNode); + favoritesManager.fireListeners(CURRENT_TASK); + } + }, ((NoteProjectNode)treeNode).getValue().getText()); + } + } + } + } + }; + } + + @Override + public TreeCellRenderer getTreeCellRenderer() { + return new MyRenderer(); + } + + private static class MyRenderer implements TreeCellRenderer { + private AbstractTreeNode myNode; + + private final MultilineTreeCellRenderer myMultilineTreeCellRenderer = new MultilineTreeCellRenderer() { + @Override + protected void initComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + if (myNode instanceof NoteProjectNode) { + setForeground(UIUtil.getListSelectionBackground()); + final NoteNode note = ((NoteProjectNode)myNode).getValue(); + final String[] lines = StringUtil.splitByLines(note.getText()); + setText(lines, null); + } + } + }; + + private final MultiLineLabel myLabel = new MultiLineLabel(); + + @Override + public Component getTreeCellRendererComponent(JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean 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(); + if (treeNode instanceof NoteProjectNode) { + myNode = treeNode; + myLabel.setText(((NoteProjectNode)myNode).getValue().getText()); + //myLabel.setBackground(selected ? ); + myMultilineTreeCellRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + return myMultilineTreeCellRenderer; + //return myLabel; + } + } + } + return null; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageFavoriteNodeProvider.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageFavoriteNodeProvider.java new file mode 100644 index 000000000000..ac9f38092b89 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageFavoriteNodeProvider.java @@ -0,0 +1,313 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.Usage; +import com.intellij.usages.UsageInfo2UsageAdapter; +import com.intellij.usages.UsageView; +import com.intellij.usages.impl.NullUsage; +import com.intellij.usages.rules.UsageInFile; +import com.intellij.usages.rules.UsageInFiles; +import com.intellij.util.ProxyComparator; +import com.intellij.util.SmartList; +import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/6/12 + * Time: 6:51 PM + */ +public class UsageFavoriteNodeProvider extends FavoriteNodeProvider { + private final static Map> ourSerializables = new HashMap>(); + private final static Comparator VIRTUAL_FILE_COMPARATOR = + new ProxyComparator(new Convertor() { + @Override + public String convert(VirtualFile o) { + return o.getPath(); + } + }); + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.favoritesTreeView.UsageFavoriteNodeProvider"); + + static { + final TreeSet usageSet = createSet(); + final UsageSerializable serializable = new UsageSerializable(); + ourSerializables.put(serializable.getId(), usageSet); + usageSet.add(serializable); + + final TreeSet fileSet = createSet(); + final FileSerializable fileSerializable = new FileSerializable(); + ourSerializables.put(fileSerializable.getId(), fileSet); + fileSet.add(fileSerializable); + + final TreeSet noteSet = createSet(); + final NoteSerializable noteSerializable = new NoteSerializable(); + ourSerializables.put(noteSerializable.getId(), noteSet); + noteSet.add(noteSerializable); + } + + private static TreeSet createSet() { + return new TreeSet(new Comparator() { + @Override + public int compare(WorkingSetSerializable o1, WorkingSetSerializable o2) { + assert o1.getId().equals(o1.getId()); + return Comparing.compare(o1.getVersion(), o2.getVersion()); + } + }); + } + + @Override + public Collection getFavoriteNodes(DataContext context, ViewSettings viewSettings) { + final Project project = PlatformDataKeys.PROJECT.getData(context); + if (project == null) { + return null; + } + final Usage[] usages = UsageView.USAGES_KEY.getData(context); + if (usages != null) { + + final List result = new SmartList(); + final MultiMap map = new MultiMap(); + final List nonMapped = new ArrayList(); + for (Usage usage : usages) { + if (usage instanceof UsageInFile) { + map.putValue(((UsageInFile)usage).getFile(), usage); + } else if (usage instanceof UsageInFiles) { + final VirtualFile[] files = ((UsageInFiles)usage).getFiles(); + for (VirtualFile file : files) { + map.putValue(file, usage); + } + } else { + nonMapped.add(usage); + } + } + + final TreeSet keys = new TreeSet(VIRTUAL_FILE_COMPARATOR); + keys.addAll(map.keySet()); + for (VirtualFile key : keys) { + final FileGroupingProjectNode grouping = new FileGroupingProjectNode(project, new File(key.getPath()), viewSettings); + result.add(grouping); + final Collection subUsages = map.get(key); + for (Usage usage : subUsages) { + if (usage instanceof UsageInfo2UsageAdapter) { + final UsageProjectTreeNode node = + new UsageProjectTreeNode(project, ((UsageInfo2UsageAdapter)usage).getUsageInfo(), viewSettings); + grouping.addChild(node); + } else if (NullUsage.INSTANCE.equals(usage)) { + continue; + } else { + grouping.addChild(new NoteProjectNode(project, new NoteNode(usage.getPresentation().getPlainText(), true), viewSettings)); + } + } + } + for (Usage usage : nonMapped) { + if (usage instanceof UsageInfo2UsageAdapter) { + final UsageProjectTreeNode node = + new UsageProjectTreeNode(project, ((UsageInfo2UsageAdapter)usage).getUsageInfo(), viewSettings); + result.add(node); + } else if (NullUsage.INSTANCE.equals(usage)) { + continue; + } else { + result.add(new NoteProjectNode(project, new NoteNode(usage.getPresentation().getPlainText(), true), viewSettings)); + } + } + + return result; + } + return null; + } + + @Override + public AbstractTreeNode createNode(Project project, Object element, ViewSettings viewSettings) { + if (element instanceof UsageInfo) { + return new UsageProjectTreeNode(project, (UsageInfo)element, viewSettings); + } else if (element instanceof InvalidUsageNoteNode) { + return new InvalidUsageNoteProjectNode(project, (InvalidUsageNoteNode)element, viewSettings); + } else if (element instanceof NoteNode) { + return new NoteProjectNode(project, (NoteNode)element, viewSettings); + } else if (element instanceof File) { + return new FileGroupingProjectNode(project, (File)element, viewSettings); + } + return super.createNode(project, element, viewSettings); + } + + @Override + public PsiElement getPsiElement(Object element) { + if (element instanceof UsageInfo) { + return ((UsageInfo)element).getElement(); + } + return super.getPsiElement(element); + } + + @Override + public boolean elementContainsFile(Object element, VirtualFile vFile) { + return false; + } + + @Override + public int getElementWeight(Object element, boolean isSortByType) { + return 0; + } + + @Override + public String getElementLocation(Object element) { + if (element instanceof UsageInfo) { + final PsiElement psiElement = ((UsageInfo)element).getElement(); + final PsiFile file = psiElement.getContainingFile(); + /*if (parent != null) { + return ClassPresentationUtil.getNameForClass(parent, true); + }*/ + return file.getPresentation().getPresentableText();//+- // todo do smthg for invalid usage + } else if (element instanceof File) { + return ((File)element).getParent(); + } + return null; + } + + @Override + public boolean isInvalidElement(Object element) { + /*if (element instanceof UsageInfo) { + return ((UsageInfo)element).getElement().isValid(); + } else if (element instanceof InvalidUsageNoteNode) { + return true; + } */ + return false; + } + + @NotNull + @Override + public String getFavoriteTypeId() { + return "usage"; + } + + @Override + public String getElementUrl(Object element) { + //if (element instanceof UsageInfo) { + final TreeSet serializables = ourSerializables.get(element.getClass().getName()); + if (serializables != null && ! serializables.isEmpty()) { + final WorkingSetSerializable last = serializables.last(); + //final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + //final ObjectOutputStream os = new ObjectOutputStream(baos); + final StringBuilder sb = new StringBuilder(); + sb.append(last.getId()); + sb.append(' '); + sb.append("" + last.getVersion()); + sb.append(' '); + + //os.writeUTF(last.getId()); + //os.writeInt(last.getVersion()); + last.serializeMe(element, sb); + //os.close(); + //final byte[] bytes = baos.toByteArray(); + return sb.toString(); + //return new String(bytes, 4, bytes.length - 4); + } + catch (IOException e) { + LOG.info(e); + return null; + } + } + //} + return null; + } + + @Override + public String getElementModuleName(Object element) { + if (element instanceof UsageInfo) { + Module module = ModuleUtil.findModuleForPsiElement(((UsageInfo)element).getElement()); + return module != null ? module.getName() : null; + } + return null; + } + + @Override + public Object[] createPathFromUrl(Project project, String url, String moduleName) { + try { + //final byte[] bytes = url.getBytes(CharsetToolkit.UTF8_CHARSET); + /*final byte[] wrapped = new byte[bytes.length + 4]; + final ByteArrayOutputStream bas = new ByteArrayOutputStream(); + final ObjectOutputStream oos = new ObjectOutputStream(bas); + oos.close(); + final byte[] header = bas.toByteArray(); + System.arraycopy(header, 0, wrapped, 0, 4); + System.arraycopy(bytes, 0, wrapped, 0, bytes.length);*/ + + //ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bytes)); + final List parts = StringUtil.split(url, " ", true); + if (parts.size() < 3) return null; + + final String id = parts.get(0); + final TreeSet set = ourSerializables.get(id); + if (set != null && ! set.isEmpty()) { + final int version = Integer.parseInt(parts.get(1)); + final String cut = StringUtil.join(parts.subList(2, parts.size()), " "); + for (java.util.Iterator iterator = set.descendingIterator(); iterator.hasNext(); ) { + WorkingSetSerializable serializable = iterator.next(); + if (serializable.getVersion() == version) { + return readWithSerializable(project, url, cut, serializable); + } + } + readWithSerializable(project, url, cut, set.last()); + } + } + catch (IOException e) { + LOG.info(e); + } + return null; + } + + private Object[] readWithSerializable(Project project, String url, String is, WorkingSetSerializable serializable) + throws IOException { + Object obj = serializable.deserializeMe(project, is); + if (obj == null) { + obj = serializable.deserializeMeInvalid(project, is); + } + return obj == null ? null : new Object[] {obj}; + /*Object obj = serializable.deserializeMe(project, is); + if (obj == null) { + is.close(); + is = new ObjectInputStream(new ByteArrayInputStream(url.getBytes(CharsetToolkit.UTF8_CHARSET))); + is.readUTF(); + is.readInt(); + obj = serializable.deserializeMeInvalid(project, is); + } + if (obj != null) { + return new Object[]{obj}; + } else { + return null; + }*/ + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageNode.java new file mode 100644 index 000000000000..e9be02390e3d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageNode.java @@ -0,0 +1,61 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.pom.Navigatable; +import com.intellij.usages.Usage; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/1/12 + * Time: 1:51 PM + */ +public class UsageNode implements Navigatable { + private Usage myUsage; + private NoteNode myComment; + + public Usage getUsage() { + return myUsage; + } + + public void setUsage(Usage usage) { + myUsage = usage; + } + + public NoteNode getComment() { + return myComment; + } + + public void setComment(NoteNode comment) { + myComment = comment; + } + + @Override + public void navigate(boolean requestFocus) { + myUsage.navigate(requestFocus); + } + + @Override + public boolean canNavigate() { + return myUsage.isValid() && myUsage.canNavigate(); + } + + @Override + public boolean canNavigateToSource() { + return myUsage.isValid() && myUsage.canNavigate(); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageProjectTreeNode.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageProjectTreeNode.java new file mode 100644 index 000000000000..5e95607ef707 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageProjectTreeNode.java @@ -0,0 +1,91 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.TextChunk; +import com.intellij.usages.UsageInfo2UsageAdapter; +import com.intellij.usages.UsagePresentation; +import org.jetbrains.annotations.NotNull; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/6/12 + * Time: 7:24 PM + * + */ +public class UsageProjectTreeNode extends ProjectViewNodeWithChildrenList { + private final UsagePresentation myUsagePresentation; + + public UsageProjectTreeNode(Project project, UsageInfo usage, ViewSettings viewSettings) { + super(project, usage, viewSettings); + final UsageInfo2UsageAdapter adapter = new UsageInfo2UsageAdapter(usage); + myUsagePresentation = adapter.getPresentation(); + } + + @Override + public boolean contains(@NotNull VirtualFile file) { + final UsageInfo info = getValue(); + if (info == null) return false; + final PsiElement element = info.getElement(); + return element != null && file.equals(element.getContainingFile().getVirtualFile()); + } + + @Override + public String toString() { + return myUsagePresentation.getPlainText(); + } + + @Override + protected void update(PresentationData presentation) { + presentation.setOpenIcon(myUsagePresentation.getIcon()); + presentation.setClosedIcon(myUsagePresentation.getIcon()); + presentation.setTooltip(myUsagePresentation.getTooltipText()); + final TextChunk[] text = myUsagePresentation.getText(); + updatePresentationWithTextChunks(presentation, text); + } + + public static void updatePresentationWithTextChunks(PresentationData presentation, TextChunk[] text) { + for (TextChunk chunk : text) { + final TextAttributes attributes = chunk.getAttributes(); + presentation.addText(chunk.getText(), new SimpleTextAttributes(attributes.getBackgroundColor(), attributes.getForegroundColor(), + attributes.getEffectColor(), attributes.getFontType())); + } + } + + @Override + public void navigate(boolean requestFocus) { + getValue().navigateTo(requestFocus); + } + + @Override + public boolean canNavigate() { + return getValue().getElement().isValid(); + } + + @Override + public boolean canNavigateToSource() { + return getValue().getElement().isValid(); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageSerializable.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageSerializable.java new file mode 100644 index 000000000000..0e8edac12fed --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/UsageSerializable.java @@ -0,0 +1,165 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.codeInsight.folding.impl.GenericElementSignatureProvider; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.ProperTextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.UsageInfo2UsageAdapter; + +import java.io.File; +import java.io.IOException; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 1:58 PM + */ +public class UsageSerializable implements WorkingSetSerializable { + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.favoritesTreeView.UsageSerializable"); + private final static String separator = "<>"; + + @Override + public String getId() { + return UsageInfo.class.getName(); + } + + @Override + public int getVersion() { + return 0; + } + + @Override + public void serializeMe(UsageInfo info, StringBuilder os) throws IOException { + //final SmartPsiElementPointer pointer = info.getSmartPointer(); + final GenericElementSignatureProvider provider = new GenericElementSignatureProvider(); + final String signature = provider.getSignature(info.getElement()); + append(os, info.getElement().getContainingFile().getVirtualFile().getPath()); + os.append(separator); + append(os, signature); + os.append(separator); + final ProperTextRange rangeInElement = info.getRangeInElement(); + if (rangeInElement == null) { + append(os, "-1"); + os.append(separator); + append(os, "-1"); + os.append(separator); + } else { + append(os, String.valueOf(rangeInElement.getStartOffset())); + os.append(separator); + append(os, String.valueOf(rangeInElement.getEndOffset())); + os.append(separator); + } + append(os, String.valueOf(info.isNonCodeUsage())); + os.append(separator); + append(os, String.valueOf(info.isDynamicUsage())); + os.append(separator); + final String text = new UsageInfo2UsageAdapter(info).getPlainText(); + append(os, text); + os.append(separator); + } + + private void append(final StringBuilder sb, final String s) { + sb.append(StringUtil.escapeXml(s)); + } + + @Override + public UsageInfo deserializeMe(Project project, String is) throws IOException { + return new Reader(is).execute(project); + } + + private static class Reader { + private int idx; + private String is; + + private Reader(String is) { + this.idx = 0; + this.is = is; + } + + private String readNext(final boolean allowEnd) { + int idxNext = is.indexOf(separator, idx); + if (idxNext == -1) { + if (allowEnd) { + return StringUtil.unescapeXml(new String(is.substring(idx))); + } + } + final String s = new String(is.substring(idx, idxNext)); + idx = idxNext + separator.length(); + return s; + } + + public UsageInfo execute(final Project project) { + final GenericElementSignatureProvider provider = new GenericElementSignatureProvider(); + + final String path = readNext(false); + if (path == null) return null; + final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(path)); + if (file == null) return null; + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile == null) return null; + final String signature = readNext(false); + final PsiElement element = provider.restoreBySignature(psiFile, signature, new StringBuilder()); + if (element == null) return null; + final String startStr = readNext(false); + if (startStr == null) return null; + final int start = Integer.parseInt(startStr); + final String endStr = readNext(false); + if (endStr == null) return null; + final int end = Integer.parseInt(endStr); + final String nonCodeUsageStr = readNext(false); + if (nonCodeUsageStr == null) return null; + final boolean nonCodeUsage = Boolean.parseBoolean(nonCodeUsageStr); + final String dynamicUsageStr = readNext(false); + if (dynamicUsageStr == null) return null; + final boolean dynamicUsage = Boolean.parseBoolean(dynamicUsageStr); + + final String text = readNext(true); + if (text == null) return null; + + final UsageInfo info = new UsageInfo(element, start, end, nonCodeUsage); + info.setDynamicUsage(dynamicUsage); + + return info; + /*final String newText = new UsageInfo2UsageAdapter(info).getPlainText(); + if (! Comparing.equal(newText, text)) { + LOG.info("Usage not restored, oldText:\n'" + text + "'\nnew text: '\n" + newText + "'"); + return null; + }*/ + } + } + + @Override + public InvalidUsageNoteNode deserializeMeInvalid(Project project, String is) throws IOException { + /*is.readUTF(); //file + is.readUTF(); + is.readInt(); + is.readInt(); + is.readBoolean(); + is.readBoolean(); + return new InvalidUsageNoteNode(Collections.singletonList(new TextChunk(new TextAttributes(), is.readUTF())));*/ + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/WorkingSetSerializable.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/WorkingSetSerializable.java new file mode 100644 index 000000000000..c8eae474e69d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/WorkingSetSerializable.java @@ -0,0 +1,34 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.openapi.project.Project; + +import java.io.IOException; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/7/12 + * Time: 1:55 PM + */ +public interface WorkingSetSerializable { + String getId(); + int getVersion(); + void serializeMe(final Valid t, final StringBuilder oos) throws IOException; + Valid deserializeMe(Project project, final String ois) throws IOException; + Invalid deserializeMeInvalid(Project project, final String ois) throws IOException; +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/WorkingSetUsageActionProvider.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/WorkingSetUsageActionProvider.java new file mode 100644 index 000000000000..5b2f82393e46 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/WorkingSetUsageActionProvider.java @@ -0,0 +1,45 @@ +/* + * 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.favoritesTreeView; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.project.Project; +import com.intellij.usages.UsageView; +import com.intellij.usages.rules.UsageGroupingRule; +import com.intellij.usages.rules.UsageGroupingRuleProvider; +import org.jetbrains.annotations.NotNull; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/2/12 + * Time: 5:01 PM + */ +public class WorkingSetUsageActionProvider implements UsageGroupingRuleProvider { + private UsageGroupingRule[] myRules = new UsageGroupingRule[0]; + + @NotNull + @Override + public UsageGroupingRule[] getActiveRules(Project project) { + return myRules; + } + + @NotNull + @Override + public AnAction[] createGroupingActions(UsageView view) { + return new AnAction[]{new ImportUsagesAction()}; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddAllToFavoritesActionGroup.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddAllToFavoritesActionGroup.java index e733b277bdfd..ef95d71717e3 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddAllToFavoritesActionGroup.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddAllToFavoritesActionGroup.java @@ -32,7 +32,7 @@ public class AddAllToFavoritesActionGroup extends ActionGroup { if (project == null){ return AnAction.EMPTY_ARRAY; } - final String[] availableFavoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesLists(); + final String[] availableFavoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesListNames(); if (availableFavoritesLists == null) return AnAction.EMPTY_ARRAY; AnAction[] actions = new AnAction[availableFavoritesLists.length + 2]; int idx = 0; diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddNewFavoritesListAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddNewFavoritesListAction.java index 3ddd4a917a01..a3b6d2f988ab 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddNewFavoritesListAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddNewFavoritesListAction.java @@ -50,7 +50,7 @@ public class AddNewFavoritesListAction extends AnAction { } public boolean canClose(String inputString) { - final boolean isNew = ArrayUtil.find(favoritesManager.getAvailableFavoritesLists(), inputString.trim()) == -1; + final boolean isNew = ArrayUtil.find(favoritesManager.getAvailableFavoritesListNames(), inputString.trim()) == -1; if (!isNew) { Messages.showErrorDialog(project, IdeBundle.message("error.favorites.list.already.exists", inputString.trim()), @@ -61,12 +61,12 @@ public class AddNewFavoritesListAction extends AnAction { } }); if (name == null || name.length() == 0) return null; - favoritesManager.createNewList(name); + favoritesManager.createNewList(name, false, false); return name; } private static String getUniqueName(Project project) { - String[] names = FavoritesManager.getInstance(project).getAvailableFavoritesLists(); + String[] names = FavoritesManager.getInstance(project).getAvailableFavoritesListNames(); for (int i = 0; ; i++) { String newName = IdeBundle.message("favorites.list.unnamed", i > 0 ? i : ""); if (ArrayUtil.find(names, newName) > -1) continue; diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesAction.java index bc0a655b3a75..994b10f06c9d 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesAction.java @@ -106,6 +106,7 @@ public class AddToFavoritesAction extends AnAction { final boolean inProjectView = e.getPlace().equals(ActionPlaces.J2EE_VIEW_POPUP) || e.getPlace().equals(ActionPlaces.STRUCTURE_VIEW_POPUP) || e.getPlace().equals(ActionPlaces.PROJECT_VIEW_POPUP); + //com.intellij.openapi.actionSystem.ActionPlaces.USAGE_VIEW_TOOLBAR return getNodesToAdd(dataContext, inProjectView) != null; } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesActionGroup.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesActionGroup.java index c10a4d5ec25e..49f0b8ed7d1c 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesActionGroup.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesActionGroup.java @@ -35,7 +35,7 @@ public class AddToFavoritesActionGroup extends ActionGroup { if (project == null){ return AnAction.EMPTY_ARRAY; } - final String[] availableFavoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesLists(); + final String[] availableFavoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesListNames(); AnAction[] actions = new AnAction[availableFavoritesLists.length + 2]; int idx = 0; for (String favoritesList : availableFavoritesLists) { diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesPopupAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesPopupAction.java index 76339f366b7c..385ea6e1fc55 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesPopupAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/AddToFavoritesPopupAction.java @@ -29,7 +29,7 @@ import com.intellij.openapi.project.Project; public class AddToFavoritesPopupAction extends QuickSwitchSchemeAction { protected void fillActions(Project project, DefaultActionGroup group, DataContext dataContext) { group.removeAll(); - final String[] availableFavoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesLists(); + final String[] availableFavoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesListNames(); for (String favoritesList : availableFavoritesLists) { group.add(new AddToFavoritesAction(favoritesList)); } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteAllFavoritesListsButThisAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteAllFavoritesListsButThisAction.java index bbcd092946ff..e18682915c65 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteAllFavoritesListsButThisAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteAllFavoritesListsButThisAction.java @@ -40,7 +40,7 @@ public class DeleteAllFavoritesListsButThisAction extends AnAction implements Du } FavoritesManager favoritesManager = FavoritesManager.getInstance(project); String listName = FavoritesTreeViewPanel.FAVORITES_LIST_NAME_DATA_KEY.getData(dataContext); - String[] lists = favoritesManager.getAvailableFavoritesLists(); + String[] lists = favoritesManager.getAvailableFavoritesListNames(); for (String list : lists) { if (!list.equals(listName)) { favoritesManager.removeFavoritesList(list); @@ -59,7 +59,7 @@ public class DeleteAllFavoritesListsButThisAction extends AnAction implements Du final String listName = FavoritesTreeViewPanel.FAVORITES_LIST_NAME_DATA_KEY.getData(dataContext); presentation.setEnabled(false); if (listName != null) { - final String[] favoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesLists(); + final String[] favoritesLists = FavoritesManager.getInstance(project).getAvailableFavoritesListNames(); if (listName.equals(project.getName())) { presentation.setEnabled(favoritesLists.length > 1); } else { diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteFromFavoritesAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteFromFavoritesAction.java index c16ba8013970..e3ee3763db5a 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteFromFavoritesAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/DeleteFromFavoritesAction.java @@ -17,12 +17,9 @@ package com.intellij.ide.favoritesTreeView.actions; import com.intellij.ide.IdeBundle; -import com.intellij.ide.favoritesTreeView.FavoritesListNode; -import com.intellij.ide.favoritesTreeView.FavoritesManager; -import com.intellij.ide.favoritesTreeView.FavoritesTreeNodeDescriptor; -import com.intellij.ide.favoritesTreeView.FavoritesTreeViewPanel; +import com.intellij.ide.dnd.aware.DnDAwareTree; +import com.intellij.ide.favoritesTreeView.*; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -31,6 +28,8 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.ui.AnActionButton; +import java.util.List; + /** * @author anna * @author Konstantin Bulenkov @@ -50,6 +49,8 @@ public class DeleteFromFavoritesAction extends AnActionButton implements DumbAwa } FavoritesManager favoritesManager = FavoritesManager.getInstance(project); FavoritesTreeNodeDescriptor[] roots = FavoritesTreeViewPanel.CONTEXT_FAVORITES_ROOTS_DATA_KEY.getData(dataContext); + final DnDAwareTree tree = FavoritesTreeViewPanel.FAVORITES_TREE_KEY.getData(dataContext); + assert roots != null; for (FavoritesTreeNodeDescriptor root : roots) { final AbstractTreeNode node = root.getElement(); @@ -59,10 +60,14 @@ public class DeleteFromFavoritesAction extends AnActionButton implements DumbAwa else { final Object value = node.getValue(); LOG.assertTrue(value != null, node); - final NodeDescriptor parent = root.getParentDescriptor(); - if (parent instanceof FavoritesTreeNodeDescriptor) { - final String name = ((FavoritesTreeNodeDescriptor)parent).getName(); - favoritesManager.removeRoot(name, value); + final FavoritesListNode listNode = FavoritesTreeUtil.extractParentList(root); + LOG.assertTrue(listNode != null); + + //final List pathToSelected = FavoritesTreeUtil.getLogicalPathToSelected(tree); + //favoritesManager.removeRoot(listNode.getName(), pathToSelected); + final List pathTo = FavoritesTreeUtil.getLogicalIndexPathTo(tree.getSelectionPath()); + if (pathTo != null) { + favoritesManager.removeRootByIndexes(listNode.getName(), pathTo); } } } @@ -81,9 +86,10 @@ public class DeleteFromFavoritesAction extends AnActionButton implements DumbAwa return; } + final FavoritesManager fm = FavoritesManager.getInstance(project); if (roots.length == 1 && roots[0].getElement() instanceof FavoritesListNode - && project.getName().equals(roots[0].getElement().getValue())) { + && fm.isReadOnly(((FavoritesListNode) roots[0].getElement()).getName())) { e.getPresentation().setEnabled(false); return; } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/RenameFavoritesListAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/RenameFavoritesListAction.java index 6fdf7b9c400f..00a60a0ea410 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/RenameFavoritesListAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/RenameFavoritesListAction.java @@ -56,7 +56,7 @@ public class RenameFavoritesListAction extends AnAction implements DumbAware { } public boolean canClose(String inputString) { - String[] lists = favoritesManager.getAvailableFavoritesLists(); + String[] lists = favoritesManager.getAvailableFavoritesListNames(); final boolean isNew = ArrayUtil.find(lists, inputString.trim()) == -1; if (!isNew) { Messages.showErrorDialog(project, IdeBundle.message("error.favorites.list.already.exists", inputString.trim()), diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesAction.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesAction.java index 5f9c1834e59a..55fd06221e70 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesAction.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesAction.java @@ -79,7 +79,7 @@ public class SendToFavoritesAction extends AnAction{ if (name == null) { name = root.getFavoritesRoot().getName(); } - favoritesManager.removeRoot(name, rootElement.getValue()); + favoritesManager.removeRoot(name, Collections.singletonList(rootElement)); favoritesManager.addRoots(toName, Collections.singletonList(rootElement)); } } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesGroup.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesGroup.java index 61c0f90d2c85..d06afdbb4e49 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesGroup.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/actions/SendToFavoritesGroup.java @@ -76,7 +76,7 @@ public class SendToFavoritesGroup extends ActionGroup{ } - final String[] allLists = favoritesManager.getAvailableFavoritesLists(); + final String[] allLists = favoritesManager.getAvailableFavoritesListNames(); List actions = new ArrayList(); for (String list : allLists) { diff --git a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java index dea601d8705f..78dc71be077a 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java +++ b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java @@ -50,6 +50,7 @@ import com.intellij.usages.UsageView; import com.intellij.usages.UsageViewManager; import com.intellij.usages.rules.PsiElementUsage; import com.intellij.util.PlatformUtils; +import com.intellij.util.TreeItem; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -353,8 +354,8 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo final FavoritesManager favoritesManager = FavoritesManager.getInstance(project); if (favoritesManager != null) { - for (final String favorite : favoritesManager.getAvailableFavoritesLists()) { - final Collection> rootUrls = favoritesManager.getFavoritesListRootUrls(favorite); + for (final String favorite : favoritesManager.getAvailableFavoritesListNames()) { + final Collection>> rootUrls = favoritesManager.getFavoritesListRootUrls(favorite); if (rootUrls.isEmpty()) continue; // ignore unused root result.add(new GlobalSearchScope(project) { @Override diff --git a/platform/lang-impl/src/com/intellij/ide/util/treeView/AbstractTreeStructureBase.java b/platform/lang-impl/src/com/intellij/ide/util/treeView/AbstractTreeStructureBase.java index bc47efcd5f5f..c1bef72d1519 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/treeView/AbstractTreeStructureBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/treeView/AbstractTreeStructureBase.java @@ -45,7 +45,7 @@ public abstract class AbstractTreeStructureBase extends AbstractTreeStructure { LOG.assertTrue(element instanceof AbstractTreeNode, element != null ? element.getClass().getName() : null); AbstractTreeNode treeNode = (AbstractTreeNode)element; Collection elements = treeNode.getChildren(); - List providers = getProvidersDumbAware(); + List providers = getProvidersDumbAware(); if (providers != null && !providers.isEmpty()) { ViewSettings settings = treeNode instanceof ProjectViewNode ? ((ProjectViewNode) treeNode).getSettings() : ViewSettings.DEFAULT; for (TreeStructureProvider provider : providers) { diff --git a/platform/platform-api/src/com/intellij/ui/PrepareTreeRenderer.java b/platform/platform-api/src/com/intellij/ui/PrepareTreeRenderer.java new file mode 100644 index 000000000000..ad4c0da76105 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/PrepareTreeRenderer.java @@ -0,0 +1,79 @@ +/* + * 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.ui; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/12/12 + * Time: 4:40 PM + */ +public class PrepareTreeRenderer { +/* public static void prepare(final JTree tree, final JComponent component, final boolean selected, final boolean hasFocus) { + final boolean treeFocused = tree.hasFocus(); + // We paint background if and only if tree path is selected and tree has focus. + // If path is selected and tree is not focused then we just paint focused border. + if (UIUtil.isFullRowSelectionLAF()) { + component.setBackground(selected ? UIUtil.getTreeSelectionBackground() : null); + } + else if (UIUtil.isUnderAquaLookAndFeel() && tree.getUI() instanceof MacTreeUI && ((MacTreeUI)tree.getUI()).isWideSelection()) { + component.setPaintFocusBorder(false); + //setBackground(selected ? UIUtil.getTreeSelectionBackground() : null); + } + else { + if (selected) { + component.setPaintFocusBorder(true); + if (treeFocused) { + component.setBackground(UIUtil.getTreeSelectionBackground()); + } + else { + component.setBackground(null); + } + } + else { + component.setBackground(null); + } + } + + component.setForeground(tree.getForeground()); + component.setIcon(null); + + if (UIUtil.isUnderGTKLookAndFeel()){ + component.setOpaque(false); // avoid nasty background + component.setIconOpaque(false); + } + else if (UIUtil.isUnderNimbusLookAndFeel() && selected && hasFocus) { + component.setOpaque(false); // avoid erasing Nimbus focus frame + component.setIconOpaque(false); + } + else if (UIUtil.isUnderAquaLookAndFeel() && tree.getUI() instanceof MacTreeUI && ((MacTreeUI)tree.getUI()).isWideSelection()) { + component.setOpaque(false); // avoid erasing Nimbus focus frame + component.setIconOpaque(false); + } + else { + component.setOpaque(myOpaque || selected && hasFocus || selected && treeFocused); // draw selection background even for non-opaque tree + } + + if (tree.getUI() instanceof MacTreeUI) { + component.setMyBorder(null); + component.setIpad(new Insets(0, 2, 0, 2)); + } + + if (component.getFont() == null) { + component.setFont(tree.getFont()); + } + } */ +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 30b87276a330..2ccff061d3d1 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -230,6 +230,9 @@ + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 0061d237eaf9..37b415652433 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -505,6 +505,7 @@ + diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java index 08b1ff32d64a..fbc86eb37456 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java @@ -24,7 +24,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -1046,6 +1045,24 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra return usages; } + /*public MultiMap getUsagesGroupedByFile() { + final MultiMap result = new MultiMap(); + final ArrayDeque> queue = new ArrayDeque>(); + final Node[] nodes = getSelectedNodes(); + for (Node node : nodes) { + if (node instanceof UsageNode) { + final VirtualFile vf = fileForUsage((UsageNode) node); + if (vf != null) { + result.putValue(vf, ((UsageNode)node).getUsage()); + } + } else if (node instanceof GroupNode) { + if (node instanceof TypeSafeDataProvider) { + ((TypeSafeDataProvider)node).calcData(); + } + } + } + }*/ + @Override @NotNull public Set getUsages() { diff --git a/platform/util/src/com/intellij/util/ProxyComparator.java b/platform/util/src/com/intellij/util/ProxyComparator.java new file mode 100644 index 000000000000..db73ab730248 --- /dev/null +++ b/platform/util/src/com/intellij/util/ProxyComparator.java @@ -0,0 +1,39 @@ +/* + * 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.util; + +import com.intellij.util.containers.Convertor; + +import java.util.Comparator; + +/** + * Created with IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 6/3/12 + * Time: 2:07 AM + */ +public class ProxyComparator,T> implements Comparator { + private final Convertor myConvertor; + + public ProxyComparator(Convertor convertor) { + myConvertor = convertor; + } + + @Override + public int compare(T o1, T o2) { + return myConvertor.convert(o1).compareTo(myConvertor.convert(o2)); + } +} diff --git a/platform/util/src/com/intellij/util/TreeItem.java b/platform/util/src/com/intellij/util/TreeItem.java index d3a8dbf3fdbf..8aa1e339ba7a 100644 --- a/platform/util/src/com/intellij/util/TreeItem.java +++ b/platform/util/src/com/intellij/util/TreeItem.java @@ -19,7 +19,7 @@ import java.util.ArrayList; import java.util.List; public class TreeItem { - private final Data myData; + private Data myData; private TreeItem myParent; private final List> myChildren = new ArrayList>(); @@ -31,6 +31,10 @@ public class TreeItem { return myData; } + public void setData(Data data) { + myData = data; + } + public TreeItem getParent() { return myParent; } @@ -47,4 +51,21 @@ public class TreeItem { child.setParent(this); myChildren.add(child); } + + public void addChildAfter(TreeItem child, TreeItem after) { + child.setParent(this); + int idx = -1; + for (int i = 0; i < myChildren.size(); i++) { + TreeItem item = myChildren.get(i); + if (item.equals(after)) { + idx = i; + break; + } + } + if (idx == -1) { + myChildren.add(child); + } else { + myChildren.add(idx, child); + } + } } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index b5e6933e783d..777b53bc910c 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1003,6 +1003,9 @@ + + +