mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes
'Filter by change type' actions perform actual filtering of the gradle project structure tree
This commit is contained in:
+37
-7
@@ -1,12 +1,16 @@
|
||||
package org.jetbrains.plugins.gradle.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.options.colors.AttributesDescriptor;
|
||||
import com.intellij.util.ui.ColorIcon;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureTreeModel;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleDataKeys;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeFilter;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -17,10 +21,10 @@ import java.awt.*;
|
||||
*/
|
||||
public abstract class GradleAbstractSyncTreeFilterAction extends ToggleAction {
|
||||
|
||||
@NotNull private final AttributesDescriptor myDescriptor;
|
||||
@NotNull private final MyFilter myFilter;
|
||||
|
||||
protected GradleAbstractSyncTreeFilterAction(@NotNull AttributesDescriptor descriptor) {
|
||||
myDescriptor = descriptor;
|
||||
myFilter = new MyFilter(descriptor.getKey());
|
||||
getTemplatePresentation().setText(descriptor.getDisplayName());
|
||||
final Color color = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(descriptor.getKey()).getForegroundColor();
|
||||
getTemplatePresentation().setIcon(new ColorIcon(new JLabel("").getFont().getSize(), color));
|
||||
@@ -28,13 +32,39 @@ public abstract class GradleAbstractSyncTreeFilterAction extends ToggleAction {
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
// TODO den implement
|
||||
return false;
|
||||
final GradleProjectStructureTreeModel model = GradleDataKeys.SYNC_TREE_MODEL.getData(e.getDataContext());
|
||||
if (model == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return model.hasFilter(myFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
// TODO den implement
|
||||
System.out.println("GradleAbstractSyncTreeFilterAction.setSelected(): " + state);
|
||||
final GradleProjectStructureTreeModel treeModel = GradleDataKeys.SYNC_TREE_MODEL.getData(e.getDataContext());
|
||||
if (treeModel == null) {
|
||||
return;
|
||||
}
|
||||
if (state) {
|
||||
treeModel.addFilter(myFilter);
|
||||
}
|
||||
else {
|
||||
treeModel.removeFilter(myFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyFilter implements GradleProjectStructureNodeFilter {
|
||||
|
||||
@NotNull private final TextAttributesKey myKey;
|
||||
|
||||
MyFilter(@NotNull TextAttributesKey key) {
|
||||
myKey = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(@NotNull GradleProjectStructureNode<?> node) {
|
||||
return myKey.equals(node.getDescriptor().getAttributes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-19
@@ -12,13 +12,10 @@ import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.config.GradleToolWindowPanel;
|
||||
import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleDataKeys;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleUiListener;
|
||||
@@ -33,7 +30,6 @@ import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -61,20 +57,6 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
public GradleProjectStructureChangesPanel(@NotNull Project project, @NotNull GradleProjectStructureContext context) {
|
||||
super(project, GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE);
|
||||
myContext = context;
|
||||
context.getChangesModel().addListener(new GradleProjectStructureChangeListener() {
|
||||
@Override
|
||||
public void onChanges(@NotNull final Collection<GradleProjectStructureChange> oldChanges,
|
||||
@NotNull final Collection<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myTreeModel.processObsoleteChanges(ContainerUtil.subtract(oldChanges, currentChanges));
|
||||
myTreeModel.processCurrentChanges(currentChanges);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
myToolbarControls.add(new GradleProjectStructureFiltersPanel());
|
||||
initContent();
|
||||
}
|
||||
@@ -89,7 +71,6 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
protected JComponent buildContent() {
|
||||
JPanel result = new JPanel(new GridBagLayout());
|
||||
myTreeModel = new GradleProjectStructureTreeModel(getProject(), myContext);
|
||||
myTreeModel.processCurrentChanges(myContext.getChangesModel().getChanges());
|
||||
myTree = new Tree(myTreeModel);
|
||||
applyInitialAppearance(myTree, (DefaultMutableTreeNode)myTreeModel.getRoot());
|
||||
|
||||
@@ -265,6 +246,9 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
if (GradleDataKeys.SYNC_TREE.is(dataId)) {
|
||||
return myTree;
|
||||
}
|
||||
else if (GradleDataKeys.SYNC_TREE_MODEL.is(dataId)) {
|
||||
return myTreeModel;
|
||||
}
|
||||
else if (GradleDataKeys.SYNC_TREE_SELECTED_NODE.is(dataId)) {
|
||||
TreePath[] paths = myTree.getSelectionPaths();
|
||||
if (paths == null) {
|
||||
|
||||
+104
-6
@@ -4,17 +4,22 @@ import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.plugins.gradle.config.GradleTextAttributes;
|
||||
import org.jetbrains.plugins.gradle.diff.*;
|
||||
import org.jetbrains.plugins.gradle.model.GradleEntityOwner;
|
||||
import org.jetbrains.plugins.gradle.model.gradle.GradleModule;
|
||||
import org.jetbrains.plugins.gradle.model.id.*;
|
||||
import org.jetbrains.plugins.gradle.model.intellij.ModuleAwareContentRoot;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeComparator;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeComparator;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeDescriptor;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeFilter;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants;
|
||||
import org.jetbrains.plugins.gradle.util.GradleProjectStructureContext;
|
||||
@@ -49,24 +54,57 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
private final Map<String, GradleProjectStructureNode<GradleModuleId>> myModules
|
||||
= new HashMap<String, GradleProjectStructureNode<GradleModuleId>>();
|
||||
|
||||
private final TreeNode[] myNodeHolder = new TreeNode[1];
|
||||
private final int[] myIndexHolder = new int[1];
|
||||
private final NodeListener myNodeListener = new NodeListener();
|
||||
private final ObsoleteChangesDispatcher myObsoleteChangesDispatcher = new ObsoleteChangesDispatcher();
|
||||
private final NewChangesDispatcher myNewChangesDispatcher = new NewChangesDispatcher();
|
||||
private final Set<GradleProjectStructureNodeFilter> myFilters = new HashSet<GradleProjectStructureNodeFilter>();
|
||||
private final TreeNode[] myNodeHolder = new TreeNode[1];
|
||||
private final int[] myIndexHolder = new int[1];
|
||||
private final NodeListener myNodeListener = new NodeListener();
|
||||
private final ObsoleteChangesDispatcher myObsoleteChangesDispatcher = new ObsoleteChangesDispatcher();
|
||||
private final NewChangesDispatcher myNewChangesDispatcher = new NewChangesDispatcher();
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final PlatformFacade myPlatformFacade;
|
||||
@NotNull private final GradleProjectStructureHelper myProjectStructureHelper;
|
||||
@NotNull private final Comparator<GradleProjectStructureNode<?>> myNodeComparator;
|
||||
@NotNull private final GradleProjectStructureChangesModel myChangesModel;
|
||||
|
||||
private Comparator<GradleProjectStructureChange> myChangesComparator;
|
||||
private boolean myProcessChangesAtTheSameThread;
|
||||
|
||||
public GradleProjectStructureTreeModel(@NotNull Project project, @NotNull GradleProjectStructureContext context) {
|
||||
super(null);
|
||||
myProject = project;
|
||||
myPlatformFacade = context.getPlatformFacade();
|
||||
myProjectStructureHelper = context.getProjectStructureHelper();
|
||||
myChangesModel = context.getChangesModel();
|
||||
myNodeComparator = new GradleProjectStructureNodeComparator(context);
|
||||
rebuild();
|
||||
|
||||
context.getChangesModel().addListener(new GradleProjectStructureChangeListener() {
|
||||
@Override
|
||||
public void onChanges(@NotNull final Collection<GradleProjectStructureChange> oldChanges,
|
||||
@NotNull final Collection<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
final Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Collection<GradleProjectStructureChange> c = ContainerUtil.subtract(oldChanges, currentChanges);
|
||||
if (myChangesComparator != null) {
|
||||
List<GradleProjectStructureChange> toSort = new ArrayList<GradleProjectStructureChange>(c);
|
||||
Collections.sort(toSort, myChangesComparator);
|
||||
c = toSort;
|
||||
}
|
||||
processObsoleteChanges(c);
|
||||
processCurrentChanges(currentChanges);
|
||||
}
|
||||
};
|
||||
if (myProcessChangesAtTheSameThread) {
|
||||
task.run();
|
||||
}
|
||||
else {
|
||||
UIUtil.invokeLaterIfNeeded(task);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void rebuild() {
|
||||
@@ -121,10 +159,70 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
dependenciesNode.add(dependency);
|
||||
}
|
||||
}
|
||||
processCurrentChanges(myChangesModel.getChanges());
|
||||
filterNodes(root);
|
||||
|
||||
setRoot(root);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setProcessChangesAtTheSameThread(boolean processChangesAtTheSameThread) {
|
||||
myProcessChangesAtTheSameThread = processChangesAtTheSameThread;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setChangesComparator(@Nullable Comparator<GradleProjectStructureChange> changesComparator) {
|
||||
myChangesComparator = changesComparator;
|
||||
}
|
||||
|
||||
private void filterNodes(@NotNull GradleProjectStructureNode<?> root) {
|
||||
if (myFilters.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Deque<GradleProjectStructureNode<?>> toRemove = new ArrayDeque<GradleProjectStructureNode<?>>();
|
||||
Stack<GradleProjectStructureNode<?>> toProcess = new Stack<GradleProjectStructureNode<?>>();
|
||||
toProcess.push(root);
|
||||
while (!toProcess.isEmpty()) {
|
||||
final GradleProjectStructureNode<?> current = toProcess.pop();
|
||||
toRemove.add(current);
|
||||
for (GradleProjectStructureNodeFilter filter : myFilters) {
|
||||
if (filter.isVisible(current)) {
|
||||
toRemove.remove(current);
|
||||
// Keep all nodes up to the hierarchy.
|
||||
for (GradleProjectStructureNode<?> parent = current.getParent(); parent != null; parent = parent.getParent()) {
|
||||
if (!toRemove.remove(parent)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (GradleProjectStructureNode<?> child : current) {
|
||||
toProcess.push(child);
|
||||
}
|
||||
}
|
||||
for (GradleProjectStructureNode<?> node = toRemove.pollLast(); node != null; node = toRemove.pollLast()) {
|
||||
final GradleProjectStructureNode<?> parent = node.getParent();
|
||||
if (parent != null) {
|
||||
parent.remove(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addFilter(@NotNull GradleProjectStructureNodeFilter filter) {
|
||||
myFilters.add(filter);
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public boolean hasFilter(@NotNull GradleProjectStructureNodeFilter filter) {
|
||||
return myFilters.contains(filter);
|
||||
}
|
||||
|
||||
public void removeFilter(@NotNull GradleProjectStructureNodeFilter filter) {
|
||||
myFilters.remove(filter);
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getContentRootNodeName(@NotNull GradleContentRootId id, boolean singleRoot) {
|
||||
final String name = GradleBundle.message("gradle.import.structure.tree.node.content.root");
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.jetbrains.plugins.gradle.ui;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureTreeModel;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -13,6 +14,9 @@ public class GradleDataKeys {
|
||||
|
||||
/** Key for obtaining 'sync project structure' tree. */
|
||||
public static final DataKey<Tree> SYNC_TREE = DataKey.create("gradle.sync.tree");
|
||||
|
||||
/** Key for obtaining 'sync project structure' tree model. */
|
||||
public static final DataKey<GradleProjectStructureTreeModel> SYNC_TREE_MODEL = DataKey.create("gradle.sync.tree.model");
|
||||
|
||||
/** Key for obtaining currently selected nodes at the gradle 'sync project structure' tree. */
|
||||
public static final DataKey<Collection<GradleProjectStructureNode<?>>> SYNC_TREE_SELECTED_NODE
|
||||
|
||||
@@ -100,8 +100,15 @@ public class GradleProjectStructureNode<T extends GradleEntityId> extends Defaul
|
||||
|
||||
@Override
|
||||
public void remove(MutableTreeNode aChild) {
|
||||
boolean b = mySkipNotification;
|
||||
mySkipNotification = true;
|
||||
final int index = getIndex(aChild);
|
||||
super.remove(aChild);
|
||||
try {
|
||||
super.remove(aChild);
|
||||
}
|
||||
finally {
|
||||
mySkipNotification = b;
|
||||
}
|
||||
onNodeRemoved((GradleProjectStructureNode<?>)aChild, index);
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.plugins.gradle.ui;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 3/11/12 11:40 AM
|
||||
*/
|
||||
public interface GradleProjectStructureNodeFilter {
|
||||
|
||||
boolean isVisible(@NotNull GradleProjectStructureNode<?> node);
|
||||
}
|
||||
+3
-16
@@ -1,19 +1,17 @@
|
||||
package org.jetbrains.plugins.gradle.testutil
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangeListener
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureTreeModel
|
||||
import org.jetbrains.plugins.gradle.util.GradleProjectStructureContext
|
||||
import org.junit.Before
|
||||
import org.picocontainer.MutablePicoContainer
|
||||
import org.picocontainer.defaults.DefaultPicoContainer
|
||||
import org.jetbrains.plugins.gradle.diff.*
|
||||
|
||||
import static org.junit.Assert.fail
|
||||
import org.jetbrains.plugins.gradle.util.GradleProjectStructureContext
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
@@ -28,7 +26,6 @@ public abstract class AbstractGradleTest {
|
||||
def changesBuilder
|
||||
def treeChecker
|
||||
def container
|
||||
private Closure changesComparator
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -61,28 +58,18 @@ public abstract class AbstractGradleTest {
|
||||
@SuppressWarnings("GroovyAssignabilityCheck")
|
||||
protected def init(map = [:]) {
|
||||
treeModel = container.getComponentInstance(GradleProjectStructureTreeModel) as GradleProjectStructureTreeModel
|
||||
changesModel.addListener({ old, current ->
|
||||
treeModel.processObsoleteChanges(sortChanges(ContainerUtil.subtract(old, current)));
|
||||
treeModel.processCurrentChanges(sortChanges(current))
|
||||
} as GradleProjectStructureChangeListener)
|
||||
treeModel.processChangesAtTheSameThread = true;
|
||||
setState(map, false)
|
||||
treeModel.rebuild()
|
||||
changesModel.update(gradle.project)
|
||||
}
|
||||
|
||||
def sortChanges(changes) {
|
||||
if (changesComparator) {
|
||||
return changes.toList().sort(changesComparator)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
protected def setState(map, update = true) {
|
||||
map.intellij?.delegate = intellij
|
||||
map.intellij?.call()
|
||||
map.gradle?.delegate = gradle
|
||||
map.gradle?.call()
|
||||
changesComparator = map.changesSorter
|
||||
treeModel.changesComparator = map.changesSorter as Comparator
|
||||
if (update) {
|
||||
changesModel.update(gradle.project)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user