diff --git a/source/com/intellij/cyclicDependencies/CyclicDependenciesBuilder.java b/source/com/intellij/cyclicDependencies/CyclicDependenciesBuilder.java index 023ff0b0d508..cc6c5ba00b61 100644 --- a/source/com/intellij/cyclicDependencies/CyclicDependenciesBuilder.java +++ b/source/com/intellij/cyclicDependencies/CyclicDependenciesBuilder.java @@ -2,24 +2,19 @@ package com.intellij.cyclicDependencies; import com.intellij.analysis.AnalysisScope; import com.intellij.compiler.Chunk; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ContentIterator; -import com.intellij.openapi.roots.FileIndex; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.util.Pair; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Pair; import com.intellij.packageDependencies.ForwardDependenciesBuilder; -import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.psi.*; import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.Graph; import com.intellij.util.graph.GraphGenerator; -import com.intellij.refactoring.typeCook.deductive.PsiTypeVariable; import java.util.*; @@ -33,6 +28,7 @@ public class CyclicDependenciesBuilder{ private Map myPackages = new HashMap(); private Graph myGraph; private Map>> myFilesInDependentPackages = new HashMap>>(); + private Map>> myBackwardFilesInDependentPackages = new HashMap>>(); private Map> myPackageDependencies = new HashMap>(); private HashMap>> myCyclicDependencies = new HashMap>>(); private int myFileCount = 0; @@ -108,45 +104,32 @@ public class CyclicDependenciesBuilder{ myPackageDependencies.put(pack, pack2Packages); } for (Iterator it = psiFiles.iterator(); it.hasNext();) { - PsiFile psiFile = it.next(); //bounded scope - package scope for files + PsiFile psiFile = it.next(); if (!(psiFile instanceof PsiJavaFile) || !projectFileIndex.isInSourceContent(psiFile.getVirtualFile()) || !getScope().contains(psiFile)) { continue; } - //construct all dependencies - Set wholeDependencies = myForwardBuilder.getDependencies().get(psiJavaFile); - if (wholeDependencies == null) { - wholeDependencies = new HashSet(); - myForwardBuilder.getDependencies().put(psiJavaFile, wholeDependencies); - } - wholeDependencies.add(psiFile); - // construct dependent packages final String packageName = ((PsiJavaFile)psiFile).getPackageName(); //do not depend on parent packages if (packageName == null || packageName.startsWith(pack.getQualifiedName())) { continue; } - final PsiPackage depPackage = findPackage(packageName); - if (depPackage == null) { //not from analyze scope + final Set depPackages = getPackageHierarhy(packageName); + if (depPackages.isEmpty()) { //not from analyze scope continue; } - pack2Packages.add(depPackage); + pack2Packages.addAll(depPackages); - //construct files in dependent packages - Map> dependentPackages2Files = myFilesInDependentPackages.get(pack); - if (dependentPackages2Files == null) { - dependentPackages2Files = new HashMap>(); - myFilesInDependentPackages.put(pack, dependentPackages2Files); + for (Iterator depIt = depPackages.iterator(); depIt.hasNext();) { + PsiPackage depPackage = depIt.next(); + constractFilesInDependenciesPackagesMap(pack, depPackage, psiFile, myFilesInDependentPackages); + constractFilesInDependenciesPackagesMap(depPackage, pack, psiJavaFile, myBackwardFilesInDependentPackages); } - Set depFiles = dependentPackages2Files.get(depPackage); - if (depFiles == null) { - depFiles = new HashSet(); - dependentPackages2Files.put(depPackage, depFiles); - } - depFiles.add(psiFile); + + constractWholeDependenciesMap(psiJavaFile, psiFile); } } } @@ -164,18 +147,135 @@ public class CyclicDependenciesBuilder{ myCyclicDependencies = getCycles(myPackages.values(), myPerPackageCycleCount); } + private void constractFilesInDependenciesPackagesMap(final PsiPackage pack, + final PsiPackage depPackage, + final PsiFile file, + final Map>> filesInDependentPackages) { + Map> dependentPackages2Files = filesInDependentPackages.get(pack); + if (dependentPackages2Files == null) { + dependentPackages2Files = new HashMap>(); + filesInDependentPackages.put(pack, dependentPackages2Files); + } + Set depFiles = dependentPackages2Files.get(depPackage); + if (depFiles == null) { + depFiles = new HashSet(); + dependentPackages2Files.put(depPackage, depFiles); + } + depFiles.add(file); + } + +//construct all dependencies for usage view + private void constractWholeDependenciesMap(final PsiJavaFile psiJavaFile, final PsiFile psiFile) { + Set wholeDependencies = myForwardBuilder.getDependencies().get(psiJavaFile); + if (wholeDependencies == null) { + wholeDependencies = new HashSet(); + myForwardBuilder.getDependencies().put(psiJavaFile, wholeDependencies); + } + wholeDependencies.add(psiFile); + } + public int getPerPackageCycleCount() { return myPerPackageCycleCount; } public Set getDependentFilesInPackage(PsiPackage pack, PsiPackage depPack) { - Set psiFiles = myFilesInDependentPackages.get(pack).get(depPack); + Set psiFiles = new HashSet(); + final Map> map = myFilesInDependentPackages.get(pack); + if (map != null){ + psiFiles = map.get(depPack); + } if (psiFiles == null) { psiFiles = new HashSet(); } return psiFiles; } + public Set getDependentFilesInPackage(PsiPackage firstPack, PsiPackage middlePack, PsiPackage lastPack) { + Set result = new HashSet(); + final Map> forwardMap = myFilesInDependentPackages.get(middlePack); + if (forwardMap != null && forwardMap.get(lastPack) != null){ + result.addAll(forwardMap.get(lastPack)); + } + final Map> backwardMap = myBackwardFilesInDependentPackages.get(middlePack); + if (backwardMap != null && backwardMap.get(firstPack) != null){ + result.addAll(backwardMap.get(firstPack)); + } + return result; + } + + /*public Set getDependentFilesInPackage(PsiPackage pack, PsiPackage depPack) { + final Set result = new HashSet(); + final Map> dependencies = myForwardBuilder.getDependencies(); + final Set allPsiPackageFiles = getAllPsiPackageFiles(pack); + for (Iterator it = allPsiPackageFiles.iterator(); it.hasNext();) { + PsiFile file = it.next(); + final Set psiFiles = dependencies.get(file); + if (psiFiles == null){ + continue; + } + for (Iterator iterator = psiFiles.iterator(); iterator.hasNext();) { + PsiFile psiFile = iterator.next(); + if (psiFile.getContainingDirectory().getPackage().getQualifiedName().startsWith(depPack.getQualifiedName())){ + result.add(psiFile); + } + } + } + return result; + } + + public Set getDependentFilesInPackage(PsiPackage firstPack, PsiPackage middlePack, PsiPackage lastPack) { + Set result = new HashSet(); + + final Map> dependencies = myForwardBuilder.getDependencies(); + final Set allPsiPackageFiles = getAllPsiPackageFiles(middlePack); + + for (Iterator it = allPsiPackageFiles.iterator(); it.hasNext();) { + PsiFile file = it.next(); + final Set psiFiles = dependencies.get(file); + if (psiFiles == null){ + continue; + } + for (Iterator iterator = psiFiles.iterator(); iterator.hasNext();) { + PsiFile psiFile = iterator.next(); + if (psiFile.getContainingDirectory().getPackage().getQualifiedName().startsWith(lastPack.getQualifiedName())){ + result.add(file); + } + } + } + result.addAll(getDependentFilesInPackage(firstPack, middlePack)); + return result; + } + + private Set getAllPsiPackageFiles(PsiPackage aPackage){ + Set result = new HashSet(); + final PsiDirectory[] directories = aPackage.getDirectories(); + if (directories == null){ + return result; + } + for (int i = 0; i < directories.length; i++) { + PsiDirectory directory = directories[i]; + final PsiFile[] files = directory.getFiles(); + if (files == null){ + continue; + } + for (int j = 0; j < files.length; j++) { + PsiFile file = files[j]; + if (getScope().contains(file)){ + result.add(file); + } + } + final PsiDirectory[] subdirectories = directory.getSubdirectories(); + if (subdirectories == null){ + continue; + } + for (int j = 0; j < subdirectories.length; j++) { + PsiDirectory subdirectory = subdirectories[j]; + result.addAll(getAllPsiPackageFiles(subdirectory.getPackage())); + } + } + return result; + } +*/ public HashMap>> getCyclicDependencies() { return myCyclicDependencies; } @@ -188,6 +288,9 @@ public class CyclicDependenciesBuilder{ final List> chunksByPackage = findChunksByPackage(psiPackage, chunks); for (Iterator> it = chunksByPackage.iterator(); it.hasNext();) { Chunk chunk = it.next(); + if (chunk.getNodes().size() == 1){ + continue; + } Set> paths2Pack = result.get(psiPackage); if (paths2Pack == null) { paths2Pack = new HashSet>(); diff --git a/source/com/intellij/cyclicDependencies/ui/CyclicDependenciesPanel.java b/source/com/intellij/cyclicDependencies/ui/CyclicDependenciesPanel.java index 8e13675d2b64..fbbd68b638ac 100644 --- a/source/com/intellij/cyclicDependencies/ui/CyclicDependenciesPanel.java +++ b/source/com/intellij/cyclicDependencies/ui/CyclicDependenciesPanel.java @@ -10,7 +10,9 @@ import com.intellij.openapi.util.IconLoader; import com.intellij.packageDependencies.DependencyUISettings; import com.intellij.packageDependencies.DependencyValidationManager; import com.intellij.packageDependencies.ui.*; -import com.intellij.psi.*; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiPackage; import com.intellij.ui.*; import com.intellij.ui.content.Content; import com.intellij.util.EditSourceOnDoubleClickHandler; @@ -20,7 +22,10 @@ import com.intellij.util.ui.tree.TreeUtil; import javax.swing.*; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; import java.awt.*; import java.util.*; @@ -87,12 +92,18 @@ public class CyclicDependenciesPanel extends JPanel { return; } final PackageDependenciesNode nextPackageNode = getNextPackageNode(selectedPackageNode); - Set searchFor = myBuilder.getDependentFilesInPackage((PsiPackage)selectedPackageNode.getPsiElement(), ((PsiPackage)nextPackageNode.getPsiElement())); + Set searchFor = new HashSet(); + Set packNodes = new HashSet(); + getPackageNodesHierarchy(selectedPackageNode, packNodes); + for (Iterator iterator = packNodes.iterator(); iterator.hasNext();) { + PackageNode packageNode = iterator.next(); + searchFor.addAll(myBuilder.getDependentFilesInPackage((PsiPackage)packageNode.getPsiElement(), ((PsiPackage)nextPackageNode.getPsiElement()))); + } if (searchIn.isEmpty() || searchFor.isEmpty()) { myUsagesPanel.setToInitialPosition(); } else { - myBuilder.setRootNodeNameInUsageView("Usages of package \'" + nextPackageNode.toString() + "\' classes in package \'" + selectedPackageNode.toString() + "\' classes"); + myBuilder.setRootNodeNameInUsageView("Usages of package \'" + ((PsiPackage)nextPackageNode.getPsiElement()).getQualifiedName() + "\' in package \'" + ((PsiPackage)selectedPackageNode.getPsiElement()).getQualifiedName() + "\'"); myUsagesPanel.findUsages(searchIn, searchFor); } } @@ -104,10 +115,23 @@ public class CyclicDependenciesPanel extends JPanel { initTree(myRightTree); mySettings.UI_FILTER_LEGALS = false; - mySettings.UI_FLATTEN_PACKAGES = true; + mySettings.UI_FLATTEN_PACKAGES = false; TreeUtil.selectFirstNode(myLeftTree); } + private void getPackageNodesHierarchy(PackageNode node, Set result){ + result.add(node); + for (int i = 0; i < node.getChildCount(); i++){ + final TreeNode child = node.getChildAt(i); + if (child instanceof PackageNode){ + final PackageNode packNode = (PackageNode)child; + if (!result.contains(packNode)){ + getPackageNodesHierarchy(packNode, result); + } + } + } + } + private PackageDependenciesNode getNextPackageNode(DefaultMutableTreeNode node) { DefaultMutableTreeNode child = node; while (node != null) { @@ -128,6 +152,29 @@ public class CyclicDependenciesPanel extends JPanel { return null; } + private PackageDependenciesNode hideEmptyMiddlePackages(PackageDependenciesNode node, StringBuffer result){ + if (node.getChildCount() > 1 || (node.getChildCount() == 1 && node.getChildAt(0) instanceof FileNode)){ + result.append((result.length() != 0 ? ".":"") + (node.toString().equals("") ? "" : node.toString()));//toString() + } else { + if (node.getChildCount() == 1){ + PackageDependenciesNode child = (PackageDependenciesNode)node.getChildAt(0); + if (!(node instanceof PackageNode)){ + node.removeAllChildren(); + child = hideEmptyMiddlePackages(child, result); + node.add(child); + } else { + if (node.getChildAt(0) instanceof PackageNode){ + node.removeAllChildren(); + result.append((result.length() != 0 ? ".":"") + (node.toString().equals("") ? "" : node.toString())); + node = hideEmptyMiddlePackages(child, result); + ((PackageNode)node).setPackageName(result.toString());//toString() + } + } + } + } + return node; + } + private JComponent createToolbar() { DefaultActionGroup group = new DefaultActionGroup(); group.add(new CloseAction()); @@ -171,6 +218,9 @@ public class CyclicDependenciesPanel extends JPanel { PsiPackage psiPackage = iterator.next(); psiFiles.addAll(getPackageFiles(psiPackage)); } + boolean showFiles = mySettings.UI_SHOW_FILES; //do not show files in the left tree + mySettings.UI_FLATTEN_PACKAGES = true; + mySettings.UI_SHOW_FILES = false; myLeftTreeExpantionMonitor.freeze(); myLeftTree.setModel(TreeModelBuilder.createTreeModel(myProject, false, psiFiles, new TreeModelBuilder.Marker() { public boolean isMarked(PsiFile file) { @@ -179,6 +229,8 @@ public class CyclicDependenciesPanel extends JPanel { }, mySettings)); myLeftTreeExpantionMonitor.restore(); expandFirstLevel(myLeftTree); + mySettings.UI_SHOW_FILES = showFiles; + mySettings.UI_FLATTEN_PACKAGES = false; } private ActionGroup createTreePopupActions() { @@ -202,14 +254,15 @@ public class CyclicDependenciesPanel extends JPanel { for (int i = 0; i < packCycle.size(); i++) { final PsiPackage psiPackage = packCycle.get(i); PsiPackage nextPackage = packCycle.get(i == packCycle.size() - 1 ? 0 : i + 1); - final Set dependentFilesInPackage = myBuilder.getDependentFilesInPackage(psiPackage, nextPackage); + PsiPackage prevPackage = packCycle.get(i == 0 ? packCycle.size() - 1 : i - 1); + final Set dependentFilesInPackage = myBuilder.getDependentFilesInPackage(prevPackage, psiPackage, nextPackage); final PackageDependenciesNode pack = (PackageDependenciesNode)TreeModelBuilder.createTreeModel(myProject, false, dependentFilesInPackage, new TreeModelBuilder.Marker() { public boolean isMarked(PsiFile file) { return false; } }, mySettings).getRoot(); - nodes[i] = (PackageDependenciesNode)pack.getChildAt(0); + nodes[i] = hideEmptyMiddlePackages((PackageDependenciesNode)pack.getChildAt(0), new StringBuffer()); } PackageDependenciesNode cycleNode = new CycleNode(); @@ -280,7 +333,7 @@ public class CyclicDependenciesPanel extends JPanel { PackageDependenciesNode node = (PackageDependenciesNode)paths[0].getLastPathComponent(); if (node.isRoot()) return EMPTY_FILE_SET; Set result = new HashSet(); - node.fillFiles(result, !DependencyUISettings.getInstance().UI_FLATTEN_PACKAGES); + node.fillFiles(result, true); return result; } diff --git a/source/com/intellij/packageDependencies/FindDependencyUtil.java b/source/com/intellij/packageDependencies/FindDependencyUtil.java index b6670ce92107..8f7b222c5ce0 100644 --- a/source/com/intellij/packageDependencies/FindDependencyUtil.java +++ b/source/com/intellij/packageDependencies/FindDependencyUtil.java @@ -26,7 +26,8 @@ public class FindDependencyUtil { indicator.setText("Searching for usages: " + psiFile.getVirtualFile().getPresentableUrl()); } - final Set deps = new HashSet(builder.getDependencies().get(psiFile)); + final Set depsByFile = builder.getDependencies().get(psiFile); + final Set deps = depsByFile != null ? new HashSet(depsByFile) : new HashSet(); deps.retainAll(searchFor); if (deps.isEmpty()) continue; diff --git a/source/com/intellij/packageDependencies/ui/PackageNode.java b/source/com/intellij/packageDependencies/ui/PackageNode.java index c158450da971..81683f51b358 100644 --- a/source/com/intellij/packageDependencies/ui/PackageNode.java +++ b/source/com/intellij/packageDependencies/ui/PackageNode.java @@ -44,6 +44,10 @@ public class PackageNode extends PackageDependenciesNode { return myPackageName; } + public void setPackageName(final String packageName) { + myPackageName = packageName; + } + public String getPackageQName() { return myPackageQName; }