project structure: delete unused 'Analyze' action

It was never enabled, works very inefficiently in big projects and we now have module dependencies diagram instead.
This commit is contained in:
nik
2018-11-30 17:55:24 +03:00
parent 35d8e8d420
commit 0d64c3658b
7 changed files with 1 additions and 1512 deletions
@@ -37,7 +37,6 @@ import com.intellij.openapi.roots.ui.OrderEntryAppearanceService;
import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider;
import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState;
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
import com.intellij.openapi.roots.ui.configuration.dependencyAnalysis.AnalyzeDependenciesDialog;
import com.intellij.openapi.roots.ui.configuration.libraries.LibraryEditingUtil;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.EditExistingLibraryDialog;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ConvertModuleLibraryToRepositoryLibraryAction;
@@ -86,8 +85,8 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
import java.util.*;
import static com.intellij.openapi.wm.IdeFocusManager.getGlobalInstance;
@@ -366,8 +365,6 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel {
private JComponent createTableWithButtons() {
final boolean isAnalyzeShown = false;
final ClasspathPanelAction removeAction = new ClasspathPanelAction(this) {
@Override
public void run() {
@@ -375,13 +372,6 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel {
}
};
final AnActionButton analyzeButton = new AnActionButton(ProjectBundle.message("classpath.panel.analyze"), null, IconUtil.getAnalyzeIcon()) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
AnalyzeDependenciesDialog.show(getRootModel().getModule());
}
};
//addButton.setShortcut(CustomShortcutSet.fromString("alt A", "INSERT"));
//removeButton.setShortcut(CustomShortcutSet.fromString("alt DELETE"));
//upButton.setShortcut(CustomShortcutSet.fromString("alt UP"));
@@ -466,9 +456,6 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel {
.setMoveDownActionUpdater(moveUpDownUpdater)
.setMoveDownActionName("Move Down (disabled if items are shown in sorted order)")
.addExtraAction(myEditButton);
if (isAnalyzeShown) {
decorator.addExtraAction(analyzeButton);
}
final JPanel panel = decorator.createPanel();
myRemoveButton = ToolbarDecorator.findRemoveButton(panel);
@@ -1,799 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.roots.ui.configuration.dependencyAnalysis;
import com.intellij.ProjectTopics;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.ModuleSourceOrderEntry;
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.ui.CellAppearanceEx;
import com.intellij.openapi.roots.ui.OrderEntryAppearanceService;
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
import com.intellij.openapi.ui.MasterDetailsComponent;
import com.intellij.openapi.ui.NamedConfigurable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.PathUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* The classpath details component
*/
public class AnalyzeDependenciesComponent extends MasterDetailsComponent {
/**
* Data key for order path element
*/
public static final DataKey<ModuleDependenciesAnalyzer.OrderPathElement> ORDER_PATH_ELEMENT_KEY = DataKey.create("ORDER_PATH_ELEMENT");
/**
* The module being analyzed
*/
private final Module myModule;
/**
* The settings for UI mode
*/
private final AnalyzeDependenciesSettings mySettings;
/**
* The cached analyzed classpaths for this module
*/
private final HashMap<Pair<ClasspathType, Boolean>, ModuleDependenciesAnalyzer> myClasspaths =
new HashMap<>();
/**
* The message bus connection to use
*/
private final MessageBusConnection myMessageBusConnection;
/**
* The constructor
*
* @param module the module to analyze
*/
public AnalyzeDependenciesComponent(Module module) {
myModule = module;
mySettings = AnalyzeDependenciesSettings.getInstance(myModule.getProject());
initTree();
init();
getSplitter().setProportion(0.3f);
myMessageBusConnection = myModule.getProject().getMessageBus().connect();
myMessageBusConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
@Override
public void rootsChanged(@NotNull ModuleRootEvent event) {
myClasspaths.clear();
updateTree();
}
});
}
/**
* {@inheritDoc}
*/
@Override
public void disposeUIResources() {
if (myMessageBusConnection != null) {
myMessageBusConnection.disconnect();
}
}
/**
* Initialize components
*/
private void init() {
myTree.setCellRenderer(new ColoredTreeCellRenderer() {
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
//if(getBackground() == null) {
// setBackground(UIUtil.getTreeTextBackground());
//}
if (value instanceof MyNode && !(value instanceof MyRootNode)) {
final MyNode node = (MyNode)value;
PathNode<?> n = (PathNode<?>)node.getUserObject();
CellAppearanceEx a = n.getAppearance(selected, node.isDisplayInBold());
a.customize(this);
}
}
});
myTree.setShowsRootHandles(false);
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
reloadTree();
}
/**
* {@inheritDoc}
*/
@Override
protected List<AnAction> createActions(boolean fromPopup) {
if (fromPopup) {
return super.createActions(true);
}
List<AnAction> rc = new ArrayList<>();
rc.add(new ClasspathTypeAction());
rc.add(new SdkFilterAction());
rc.add(new UrlModeAction());
return rc;
}
/**
* {@inheritDoc}
*/
@Nls
@Override
public String getDisplayName() {
return "Classpath Details";
}
/**
* Reload tree
*/
public void reloadTree() {
myRoot.removeAllChildren();
ModuleDependenciesAnalyzer a = getAnalyzer();
if (mySettings.isUrlMode()) {
for (ModuleDependenciesAnalyzer.UrlExplanation urlExplanation : a.getUrls()) {
myRoot.add(new MyNode(new UrlNode(urlExplanation)));
}
}
else {
for (ModuleDependenciesAnalyzer.OrderEntryExplanation explanation : a.getOrderEntries()) {
myRoot.add(new MyNode(new OrderEntryNode(explanation)));
}
}
((DefaultTreeModel)myTree.getModel()).reload(myRoot);
}
/**
* @return the analyzer for the current settings
*/
public ModuleDependenciesAnalyzer getAnalyzer() {
final Pair<ClasspathType, Boolean> key = Pair.create(getClasspathType(), mySettings.isSdkIncluded());
ModuleDependenciesAnalyzer a = myClasspaths.get(key);
if (a == null) {
a = new ModuleDependenciesAnalyzer(myModule, !mySettings.isTest(), !mySettings.isRuntime(), mySettings.isSdkIncluded());
myClasspaths.put(key, a);
}
return a;
}
/**
* @return the current classpath type from settings
*/
private ClasspathType getClasspathType() {
return mySettings.isRuntime() ?
(mySettings.isTest() ? ClasspathType.TEST_RUNTIME : ClasspathType.PRODUCTION_RUNTIME) :
(mySettings.isTest() ? ClasspathType.TEST_COMPILE : ClasspathType.PRODUCTION_COMPILE);
}
/**
* Schedule updating the tree
*/
void updateTree() {
// TODO make loading in the background if there will be significant delays on big projects
reloadTree();
}
/**
* The action that allows navigating to the path element
*/
static class NavigateAction extends DumbAwareAction {
/**
* The constructor
*/
NavigateAction() {
super("Navigate to ...", "Navigate to place where path element is defined", null);
}
/**
* {@inheritDoc}
*/
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
final Module module = e.getData(LangDataKeys.MODULE);
if (module == null) {
return;
}
final ModuleDependenciesAnalyzer.OrderPathElement element = e.getData(ORDER_PATH_ELEMENT_KEY);
if (element instanceof ModuleDependenciesAnalyzer.OrderEntryPathElement) {
final ModuleDependenciesAnalyzer.OrderEntryPathElement o = (ModuleDependenciesAnalyzer.OrderEntryPathElement)element;
final OrderEntry entry = o.entry();
final Module m = entry.getOwnerModule();
ProjectStructureConfigurable.getInstance(module.getProject()).selectOrderEntry(m, entry);
}
}
}
/**
* Base class for nodes
*
* @param <T> the actual explanation type
*/
abstract class PathNode<T extends ModuleDependenciesAnalyzer.Explanation> extends NamedConfigurable<T> implements DataProvider {
/**
* The cut off length, after which URLs are not shown (only suffix)
*/
public static final int CUTOFF_LENGTH = 80;
/**
* The explanation
*/
protected final T myExplanation;
/**
* The tree with explanation
*/
private Tree myExplanationTree;
/**
* The constructor
*
* @param explanation the wrapped explanation
*/
PathNode(T explanation) {
myExplanation = explanation;
}
/**
* {@inheritDoc}
*/
@Override
public T getEditableObject() {
return myExplanation;
}
/**
* @return a created tree component (to be used as
*/
private JComponent createTreeComponent() {
myExplanationTree = new Tree(new DefaultTreeModel(buildTree()));
myExplanationTree.setRootVisible(false);
myExplanationTree.setCellRenderer(new ExplanationTreeRenderer());
DataManager.registerDataProvider(myExplanationTree, this);
TreeUtil.expandAll(myExplanationTree);
final NavigateAction navigateAction = new NavigateAction();
navigateAction.registerCustomShortcutSet(new CustomShortcutSet(CommonShortcuts.DOUBLE_CLICK_1.getShortcuts()[0]), myExplanationTree);
DefaultActionGroup group = new DefaultActionGroup();
group.addAction(navigateAction);
PopupHandler.installUnknownPopupHandler(myExplanationTree, group, ActionManager.getInstance());
return new JBScrollPane(myExplanationTree);
}
/**
* {@inheritDoc}
*/
@Override
public Object getData(@NotNull @NonNls String dataId) {
if (CommonDataKeys.PROJECT.is(dataId)) {
return myModule.getProject();
}
if (LangDataKeys.MODULE.is(dataId)) {
return myModule;
}
TreePath selectionPath = myExplanationTree.getSelectionPath();
DefaultMutableTreeNode node = selectionPath == null ? null : (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
Object o = node == null ? null : node.getUserObject();
if (o instanceof ModuleDependenciesAnalyzer.OrderPathElement) {
if (ORDER_PATH_ELEMENT_KEY.is(dataId)) {
return o;
}
}
return null;
}
/**
* Build tree for the dependencies
*
* @return a tree model
*/
private DefaultMutableTreeNode buildTree() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("ROOT");
for (ModuleDependenciesAnalyzer.OrderPath orderPath : myExplanation.paths()) {
addDependencyPath(root, orderPath, 0);
}
return root;
}
/**
* Add the dependency path
*
* @param parent the parent to which path is added
* @param orderPath the order entry path
* @param i the position in the path
*/
private void addDependencyPath(DefaultMutableTreeNode parent,
ModuleDependenciesAnalyzer.OrderPath orderPath,
int i) {
if (i >= orderPath.entries().size()) {
return;
}
ModuleDependenciesAnalyzer.OrderPathElement e = orderPath.entries().get(i);
int sz = parent.getChildCount();
DefaultMutableTreeNode n;
if (sz == 0) {
n = null;
}
else {
n = (DefaultMutableTreeNode)parent.getChildAt(sz - 1);
if (!n.getUserObject().equals(e)) {
n = null;
}
}
if (n == null) {
n = new DefaultMutableTreeNode(e);
parent.add(n);
}
addDependencyPath(n, orderPath, i + 1);
}
/**
* {@inheritDoc}
*/
@Override
public void setDisplayName(String name) {
// do nothing
}
/**
* {@inheritDoc}
*/
@Override
public JComponent createOptionsPanel() {
final JComponent tree = createTreeComponent();
JPanel panel = new JPanel(new BorderLayout());
JLabel paths = new JLabel("Available Through Paths:");
paths.setDisplayedMnemonic('P');
paths.setLabelFor(tree);
panel.add(paths, BorderLayout.NORTH);
panel.add(tree, BorderLayout.CENTER);
return panel;
}
/**
* {@inheritDoc}
*/
@Override
public String getHelpTopic() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isModified() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public void apply() throws ConfigurationException {
// Do nothing
}
/**
* Get appearance for rendering in master list
*
* @param selected true if selected
* @param bold true if bold
* @return the result appearance
*/
public abstract CellAppearanceEx getAppearance(boolean selected, boolean bold);
/**
* @retrun the string cut so it would fit the banner (the prefix is dropped)
*/
protected String suffixForBanner(String p) {
if (p.length() > CUTOFF_LENGTH) {
p = "..." + p.substring(p.length() - CUTOFF_LENGTH);
}
return p;
}
/**
* @retrun the string cut so it would fit the banner (the suffix is dropped)
*/
protected String prefixForBanner(String p) {
if (p.length() > CUTOFF_LENGTH) {
p = p.substring(0, CUTOFF_LENGTH) + "...";
}
return p;
}
}
/**
* Cell renderer for explanation tree
*/
static class ExplanationTreeRenderer extends ColoredTreeCellRenderer {
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode n = (DefaultMutableTreeNode)value;
final Object userObject = n.getUserObject();
if (!(userObject instanceof ModuleDependenciesAnalyzer.OrderPathElement)) {
return;
}
ModuleDependenciesAnalyzer.OrderPathElement e = (ModuleDependenciesAnalyzer.OrderPathElement)userObject;
final CellAppearanceEx appearance = e.getAppearance(selected);
appearance.customize(this);
}
}
/**
* The entry node in URL node
*/
class UrlNode extends PathNode<ModuleDependenciesAnalyzer.UrlExplanation> {
/**
* The constructor
*
* @param url the wrapped explanation
*/
UrlNode(ModuleDependenciesAnalyzer.UrlExplanation url) {
super(url);
setNameFieldShown(false);
}
/**
* {@inheritDoc}
*/
@Override
public CellAppearanceEx getAppearance(boolean selected, final boolean isBold) {
return new CellAppearanceEx() {
@Override
public void customize(@NotNull SimpleColoredComponent component) {
component.setIcon(getIcon());
final Font font = UIUtil.getTreeFont();
if (isBold) {
component.setFont(font.deriveFont(Font.BOLD));
}
else {
component.setFont(font.deriveFont(Font.PLAIN));
}
final String p = PathUtil.toPresentableUrl(getEditableObject().url());
component.append(PathUtil.getFileName(p),
isBold ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES);
component.append(" (" + PathUtil.getParentPath(p) + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
@Override
public void customize(@NotNull final HtmlListCellRenderer renderer) {
throw new UnsupportedOperationException("Rendering in combo box not supported yet.");
}
@NotNull
@Override
public String getText() {
return getDisplayName();
}
};
}
/**
* {@inheritDoc}
*/
@Override
public String getBannerSlogan() {
final VirtualFile f = myExplanation.getLocalFile();
String p = f == null ? myExplanation.url() : f.getPath();
p = suffixForBanner(p);
return p;
}
/**
* {@inheritDoc}
*/
private Icon getIcon() {
return myExplanation.getIcon();
}
/**
* {@inheritDoc}
*/
@Nls
@Override
public String getDisplayName() {
return myExplanation.url();
}
}
/**
* The wrapper for order entries
*/
class OrderEntryNode extends PathNode<ModuleDependenciesAnalyzer.OrderEntryExplanation> {
/**
* The constructor
*
* @param orderEntryExplanation the explanation to wrap
*/
OrderEntryNode(ModuleDependenciesAnalyzer.OrderEntryExplanation orderEntryExplanation) {
super(orderEntryExplanation);
setNameFieldShown(false);
}
/**
* {@inheritDoc}
*/
@Override
public CellAppearanceEx getAppearance(boolean selected, final boolean isBold) {
if (myExplanation.entry() instanceof ModuleSourceOrderEntry) {
ModuleSourceOrderEntry e = (ModuleSourceOrderEntry)myExplanation.entry();
if (e.getOwnerModule() == myModule) {
return new CellAppearanceEx() {
@Override
public void customize(@NotNull SimpleColoredComponent component) {
component.setIcon(ModuleType.get(myModule).getIcon());
component.append("<This Module>", SimpleTextAttributes.SYNTHETIC_ATTRIBUTES);
}
@Override
public void customize(@NotNull final HtmlListCellRenderer renderer) {
throw new UnsupportedOperationException("Rendering in combo box not supported yet.");
}
@NotNull
@Override
public String getText() {
return "<This Module>";
}
};
}
else {
return OrderEntryAppearanceService.getInstance().forModule(e.getOwnerModule());
}
}
return OrderEntryAppearanceService.getInstance().forOrderEntry(myModule.getProject(), myExplanation.entry(), selected);
}
/**
* {@inheritDoc}
*/
@Override
public String getBannerSlogan() {
if (myExplanation.entry() instanceof ModuleSourceOrderEntry) {
ModuleSourceOrderEntry e = (ModuleSourceOrderEntry)myExplanation.entry();
return prefixForBanner("Module " + e.getOwnerModule().getName());
}
else {
final String p = myExplanation.entry().getPresentableName() + " in module " + myExplanation.entry().getOwnerModule().getName();
return suffixForBanner(p);
}
}
/**
* {@inheritDoc}
*/
@Nls
@Override
public String getDisplayName() {
return myExplanation.entry().getPresentableName();
}
}
/**
* The action that allows including and excluding SDK entries from analysis
*/
private class SdkFilterAction extends ToggleAction {
/**
* The constructor
*/
SdkFilterAction() {
super("Include SDK", "If selected, the SDK classes are included", AllIcons.Nodes.PpJdk);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSelected(@NotNull AnActionEvent e) {
return mySettings.isSdkIncluded();
}
/**
* {@inheritDoc}
*/
@Override
public void setSelected(@NotNull AnActionEvent e, boolean state) {
mySettings.setIncludeSdk(state);
updateTree();
}
}
/**
* The action that allows switching class path between URL and order entry modes
*/
private class UrlModeAction extends ToggleAction {
/**
* The constructor
*/
UrlModeAction() {
super("Use URL mode", "If selected, the URLs are displayed, otherwise order entries", AllIcons.Nodes.Folder);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSelected(@NotNull AnActionEvent e) {
return mySettings.isUrlMode();
}
/**
* {@inheritDoc}
*/
@Override
public void setSelected(@NotNull AnActionEvent e, boolean state) {
mySettings.setUrlMode(state);
updateTree();
}
}
/**
* Classpath type action for the analyze classpath
*/
private class ClasspathTypeAction extends ComboBoxAction {
/**
* The filter action group
*/
DefaultActionGroup myItems;
/**
* {@inheritDoc}
*/
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
if (myItems == null) {
myItems = new DefaultActionGroup(null, true);
for (final ClasspathType classpathType : ClasspathType.values()) {
myItems.addAction(new DumbAwareAction(classpathType.getDescription()) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
mySettings.setRuntime(classpathType.isRuntime());
mySettings.setTest(classpathType.isTest());
updateTree();
}
});
}
}
return myItems;
}
/**
* {@inheritDoc}
*/
@Override
public void update(@NotNull AnActionEvent e) {
final Presentation presentation = e.getPresentation();
updateText(presentation);
}
/**
* Update the text for the combobox
*
* @param presentation the presentaiton to update
*/
private void updateText(Presentation presentation) {
final ClasspathType classpathType = getClasspathType();
String t = classpathType.getDescription();
presentation.setText(t);
}
}
/**
* The enumeration type that represents classpath entry filter
*/
private enum ClasspathType {
/**
* The production compile mode
*/
PRODUCTION_COMPILE(false, false, "Production Compile"),
/**
* The production runtime mode
*/
PRODUCTION_RUNTIME(false, true, "Production Runtime"),
/**
* The test runtime mode
*/
TEST_RUNTIME(true, true, "Test Runtime"),
/**
* The test compile mode
*/
TEST_COMPILE(true, false, "Test Compile");
/**
* true, if test mode
*/
final private boolean myIsTest;
/**
* true, if runtime mode
*/
final private boolean myIsRuntime;
/**
* The description text
*/
final private String myDescription;
/**
* The constructor
*
* @param isTest true if the test mode
* @param isRuntime true if the runtime ode
* @param description the description text
*/
ClasspathType(boolean isTest, boolean isRuntime, String description) {
myIsTest = isTest;
myIsRuntime = isRuntime;
myDescription = description;
}
/**
* @return true if the test mode
*/
public boolean isTest() {
return myIsTest;
}
/**
* @return true if the runtime mode
*/
public boolean isRuntime() {
return myIsRuntime;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return myDescription;
}
/**
* @return the description for the entry
*/
public String getDescription() {
return myDescription;
}
}
}
@@ -1,88 +0,0 @@
/*
* Copyright 2000-2010 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.openapi.roots.ui.configuration.dependencyAnalysis;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* The dialog that allows examining dependencies
*/
public class AnalyzeDependenciesDialog extends DialogWrapper {
/**
* The analyzer component
*/
private final AnalyzeDependenciesComponent myComponent;
/**
* The constructor
*
* @param module the dialog that allows analyzing dependencies
*/
protected AnalyzeDependenciesDialog(Module module) {
super(module.getProject(), true);
setTitle("Analyze Dependencies for " + module.getName());
setModal(false);
myComponent = new AnalyzeDependenciesComponent(module);
Disposer.register(myDisposable, new Disposable() {
@Override
public void dispose() {
myComponent.disposeUIResources();
}
});
setOKButtonText("Close");
init();
}
/**
* {@inheritDoc}
*/
@NotNull
@Override
protected Action[] createActions() {
return new Action[]{getOKAction()};
}
/**
* {@inheritDoc}
*/
@Override
protected JComponent createCenterPanel() {
return myComponent.createComponent();
}
/**
* {@inheritDoc}
*/
@Override
protected String getDimensionServiceKey() {
return getClass().getName();
}
/**
* Show the dialog
*
* @param module the module to use
*/
public static void show(Module module) {
new AnalyzeDependenciesDialog(module).show();
}
}
@@ -1,133 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.roots.ui.configuration.dependencyAnalysis;
import com.intellij.openapi.components.*;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
* The default mode for classpath details settings
*/
@State(name = "AnalyzeDependenciesSettings", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
public class AnalyzeDependenciesSettings implements PersistentStateComponent<AnalyzeDependenciesSettings.State> {
/**
* The current state
*/
private State myState = new State();
/**
* {@inheritDoc}
*/
@Override
public State getState() {
return myState;
}
/**
* {@inheritDoc}
*/
@Override
public void loadState(@NotNull State state) {
if (state == null) {
state = new State();
}
myState = state;
}
/**
* Set runtime flag
*
* @param value the value to se
*/
public void setRuntime(boolean value) {
myState.IS_RUNTIME = value;
}
/**
* Set test flag
*
* @param value the value to se
*/
public void setTest(boolean value) {
myState.IS_TEST = value;
}
/**
* Set include sdk flag
*
* @param value the value to se
*/
public void setIncludeSdk(boolean value) {
myState.INCLUDE_SDK = value;
}
/**
* @return true, if runtime classpath should be analyzed
*/
public boolean isRuntime() {
return myState.IS_RUNTIME;
}
/**
* @return true, if sdk classes should be also checked
*/
public boolean isSdkIncluded() {
return myState.INCLUDE_SDK;
}
/**
* @return true, if test classes should be included
*/
public boolean isTest() {
return myState.IS_TEST;
}
/**
* @return true, if classpath analysis is done in term or urls. false if in term of order entries
*/
public boolean isUrlMode() {
return myState.IS_URL_MODE;
}
/**
* Set url mode
*
* @param value true, if classpath analysis is done in term or urls. false if in term of order entries
*/
public void setUrlMode(boolean value) {
myState.IS_URL_MODE = value;
}
/**
* Get project instance
*
* @param project the context project
* @return the created instance
*/
public static AnalyzeDependenciesSettings getInstance(Project project) {
return ServiceManager.getService(project, AnalyzeDependenciesSettings.class);
}
/**
* The state object for settings
*/
public static class State {
/**
* If true, runtime dependencies are shown, otherwise compile-time
*/
boolean IS_RUNTIME = true;
/**
* If true, test dependencies are shown, otherwise production dependencies only
*/
boolean IS_TEST = true;
/**
* If true, the JDK entries are included as well
*/
boolean INCLUDE_SDK = false;
/**
* Are urls or order entry used
*/
boolean IS_URL_MODE = true;
}
}
@@ -1,475 +0,0 @@
/*
* Copyright 2000-2017 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.openapi.roots.ui.configuration.dependencyAnalysis;
import com.intellij.icons.AllIcons;
import com.intellij.ide.presentation.VirtualFilePresentation;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.ui.CellAppearanceEx;
import com.intellij.openapi.roots.ui.OrderEntryAppearanceService;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
/**
* Analyzer for module classpath. It uses order enumerator to get classpath details.
*/
public class ModuleDependenciesAnalyzer {
/**
* The current module
*/
private final Module myModule;
/**
* If true production classpath is analyzed. If false, the test classpath.
*/
private final boolean myProduction;
/**
* If true the compilation classpath is analyzed. If false, the test classpath.
*/
private final boolean myCompile;
/**
* If true, SDK classes are included in the classpath.
*/
private final boolean mySdk;
/**
* The order entry explanations
*/
private final List<OrderEntryExplanation> myOrderEntries = new ArrayList<>();
/**
* The url explanations
*/
private final List<UrlExplanation> myUrls = new ArrayList<>();
/**
* The constructor (it creates explanations immediately
*
* @param module the context module
* @param production the production/test flag
* @param compile the compile/runtime flag
* @param sdk the include sdk paths
*/
public ModuleDependenciesAnalyzer(Module module, boolean production, boolean compile, boolean sdk) {
myModule = module;
myProduction = production;
myCompile = compile;
mySdk = sdk;
analyze();
}
/**
* @return url explanations
*/
public List<UrlExplanation> getUrls() {
return Collections.unmodifiableList(myUrls);
}
/**
* @return order entry explanations
*/
public List<OrderEntryExplanation> getOrderEntries() {
return Collections.unmodifiableList(myOrderEntries);
}
/**
* Analyze module classpath
*/
private void analyze() {
OrderEnumerator e = ModuleRootManager.getInstance(myModule).orderEntries();
e.recursively();
if (!mySdk) {
e.withoutSdk();
}
if (myCompile) {
e.compileOnly();
}
else {
e.runtimeOnly();
}
if (myProduction) {
e.productionOnly();
}
final Map<String, List<OrderPath>> urlExplanations = new LinkedHashMap<>();
final OrderRootsEnumerator classes = e.classes();
if (myCompile) {
classes.withoutSelfModuleOutput();
}
for (String url : classes.getUrls()) {
if (!urlExplanations.containsKey(url)) {
urlExplanations.put(url, new ArrayList<>());
}
}
final Map<OrderEntry, List<OrderPath>> orderExplanations = new LinkedHashMap<>();
new PathWalker(urlExplanations, orderExplanations).examine(myModule, 0);
for (Map.Entry<OrderEntry, List<OrderPath>> entry : orderExplanations.entrySet()) {
myOrderEntries.add(new OrderEntryExplanation(entry.getKey(), entry.getValue()));
}
for (Map.Entry<String, List<OrderPath>> entry : urlExplanations.entrySet()) {
myUrls.add(new UrlExplanation(entry.getKey(), entry.getValue()));
}
}
/**
* The walker for the class paths. It walks the entire module classpath
*/
private class PathWalker {
/**
* The explanations for urls
*/
private final Map<String, List<OrderPath>> myUrlExplanations;
/**
* The explanations for order entries
*/
private final Map<OrderEntry, List<OrderPath>> myOrderExplanations;
/**
* The current stack
*/
private final ArrayList<OrderPathElement> myStack = new ArrayList<>();
/**
* Visited modules (in order to detect cyclic dependencies)
*/
private final HashSet<Module> myVisited = new HashSet<>();
/**
* The constructor
*
* @param urlExplanations the url explanations to accumulate
* @param orderExplanations the explanations for order entries
*/
PathWalker(Map<String, List<OrderPath>> urlExplanations,
Map<OrderEntry, List<OrderPath>> orderExplanations) {
myUrlExplanations = urlExplanations;
myOrderExplanations = orderExplanations;
}
/**
* Examine the specified module
*
* @param m the module to examine
* @param level the level of the examination
*/
void examine(final Module m, final int level) {
if (myVisited.contains(m)) {
return;
}
myVisited.add(m);
try {
final OrderEnumerator e = ModuleRootManager.getInstance(m).orderEntries();
if (!mySdk || level != 0) {
e.withoutSdk();
}
if (myCompile && level != 0) {
e.exportedOnly();
}
if (myProduction) {
e.productionOnly();
}
if (myCompile) {
e.compileOnly();
}
else {
e.runtimeOnly();
}
e.forEach(orderEntry -> {
myStack.add(new OrderEntryPathElement(orderEntry));
try {
if (orderEntry instanceof ModuleOrderEntry) {
ModuleOrderEntry o = (ModuleOrderEntry)orderEntry;
examine(o.getModule(), level + 1);
}
else if (orderEntry instanceof ModuleSourceOrderEntry) {
if (!myProduction || !myCompile) {
CompilerModuleExtension e1 = CompilerModuleExtension.getInstance(m);
final OrderPath p = new OrderPath(myStack);
for (String u : e1.getOutputRootUrls(!myCompile ? !myProduction : level > 0 && !myProduction)) {
addUrlPath(p, u);
}
addEntryPath(orderEntry, p);
}
}
else {
final OrderPath p = new OrderPath(myStack);
for (String u : orderEntry.getUrls(OrderRootType.CLASSES)) {
addUrlPath(p, u);
}
addEntryPath(orderEntry, p);
}
}
finally {
myStack.remove(myStack.size() - 1);
}
return true;
});
}
finally {
myVisited.remove(m);
}
}
/**
* Add url path
*
* @param p the path to add
* @param u the url to update
*/
private void addUrlPath(OrderPath p, String u) {
final List<OrderPath> orderPaths = myUrlExplanations.get(u);
if (orderPaths != null) {
orderPaths.add(p);
}
}
/**
* Add order entry explanation
*
* @param orderEntry the order entry to explain
* @param p the path that explain order entry
*/
private void addEntryPath(OrderEntry orderEntry, OrderPath p) {
List<OrderPath> paths = myOrderExplanations.get(orderEntry);
if (paths == null) {
paths = new ArrayList<>();
myOrderExplanations.put(orderEntry, paths);
}
paths.add(p);
}
}
/**
* The path consisting of order entry path.
*/
public static class OrderPath {
/**
* The immutable list of path elements. The first element in the list is an order entry actually included in the current module.
*/
private final List<OrderPathElement> myEntries;
/**
* The constructor
*
* @param entries the list of entries (will be copied and wrapped)
*/
public OrderPath(List<OrderPathElement> entries) {
this.myEntries = Collections.unmodifiableList(new ArrayList<>(entries));
}
/**
* @return the immutable list of path elements. The first element in the list is an order entry actually included in the current module.
*/
public List<OrderPathElement> entries() {
return myEntries;
}
@Override
public int hashCode() {
return myEntries.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OrderPath)) {
return false;
}
return myEntries.equals(((OrderPath)obj).myEntries);
}
}
/**
* The a entry in the path. The implementation should support {@link #equals(Object)} and {@link #hashCode()} methods.
*/
public static abstract class OrderPathElement {
/**
* Get appearance for path element
*
* @param isSelected true if the element is selected
* @return the appearance to use for rendering
*/
@NotNull
public abstract CellAppearanceEx getAppearance(boolean isSelected);
}
/**
* The order entry path element
*/
public static class OrderEntryPathElement extends OrderPathElement {
/**
* The order entry
*/
private final OrderEntry myEntry;
/**
* The constructor
*
* @param entry the order entry
*/
public OrderEntryPathElement(OrderEntry entry) {
this.myEntry = entry;
}
/**
* @return the order entry
*/
public OrderEntry entry() {
return myEntry;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return myEntry.hashCode();
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OrderEntryPathElement)) {
return false;
}
OrderEntryPathElement o = (OrderEntryPathElement)obj;
return o.myEntry == myEntry;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return myEntry.getPresentableName();
}
/**
* {@inheritDoc}
*/
@NotNull
@Override
public CellAppearanceEx getAppearance(boolean isSelected) {
return OrderEntryAppearanceService.getInstance().forOrderEntry(myEntry.getOwnerModule().getProject(), myEntry, isSelected);
}
}
/**
* The base class for explanations
*/
public static class Explanation {
/**
* The paths that refer to the path element
*/
public final List<OrderPath> myPaths;
/**
* The explanation for the path
*
* @param paths the paths to analyze (the list is wrapped)
*/
Explanation(List<OrderPath> paths) {
this.myPaths = Collections.unmodifiableList(paths);
}
/**
* @return the paths that refer to the path element
*/
public List<OrderPath> paths() {
return myPaths;
}
}
/**
* The explanation for
*/
public static class OrderEntryExplanation extends Explanation {
/**
* The URL in the path
*/
private final OrderEntry myEntry;
/**
* The explanation for the path
*
* @param entry the explained order entry
* @param paths the paths to analyze
*/
OrderEntryExplanation(OrderEntry entry, List<OrderPath> paths) {
super(paths);
myEntry = entry;
}
/**
* @return the explained entry
*/
public OrderEntry entry() {
return myEntry;
}
}
/**
* The explanation for url
*/
public static class UrlExplanation extends Explanation {
/**
* The URL in the path
*/
private final String myUrl;
/**
* The explanation for the path
*
* @param url the url for the order entry
* @param paths the paths to analyze
*/
UrlExplanation(String url, List<OrderPath> paths) {
super(paths);
myUrl = url;
}
/**
* @return the explained url
*/
public String url() {
return myUrl;
}
/**
* @return icon for the classpath
*/
@Nullable
public Icon getIcon() {
VirtualFile file = getLocalFile();
return file == null ? AllIcons.General.Error : VirtualFilePresentation.getIcon(file);
}
/**
* @return the local file
*/
@Nullable
public VirtualFile getLocalFile() {
VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(myUrl);
if (file != null) {
file = VfsUtil.getLocalFile(file);
}
return file;
}
}
}
@@ -327,7 +327,6 @@ find.usages.action.text=Find Usages
dependencies.used.in.popup.title=Used in
project.language.level=<html><b>Project language level:</b><br>This language level is default for all project modules.<br>\
A module specific language level can be configured for each of the modules as required.</html>
classpath.panel.analyze=Analyze
classpath.panel.navigate.action.text=Navigate
output.tab.title=Output
project.roots.module.banner.text=Module ''{0}''
@@ -204,8 +204,6 @@
<applicationService serviceInterface="com.intellij.openapi.roots.ui.configuration.libraries.LibraryPresentationManager"
serviceImplementation="com.intellij.openapi.roots.ui.configuration.libraries.impl.LibraryPresentationManagerImpl"/>
<projectService serviceInterface="com.intellij.openapi.roots.ui.configuration.dependencyAnalysis.AnalyzeDependenciesSettings"
serviceImplementation="com.intellij.openapi.roots.ui.configuration.dependencyAnalysis.AnalyzeDependenciesSettings"/>
<projectService serviceImplementation="com.intellij.ide.bookmarks.BookmarkManager"/>
<daemon.highlightInfoFilter implementation="com.intellij.debugger.engine.evaluation.DebuggerHighlightFilter"/>