Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2017-04-14 15:15:10 +03:00
100 changed files with 1735 additions and 690 deletions
@@ -36,11 +36,11 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.ThreeState;
import com.intellij.xdebugger.XExpression;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
@@ -347,10 +347,8 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
@Override
public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception {
final XValueChildrenList children = new XValueChildrenList();
final NodeRenderer renderer = myValueDescriptor.getRenderer(myEvaluationContext.getDebugProcess());
final Ref<Integer> remainingNum = new Ref<>(0);
renderer.buildChildren(myValueDescriptor.getValue(), new ChildrenBuilder() {
myValueDescriptor.getRenderer(myEvaluationContext.getDebugProcess())
.buildChildren(myValueDescriptor.getValue(), new ChildrenBuilder() {
@Override
public NodeDescriptorFactory getDescriptorManager() {
return myNodeManager;
@@ -368,7 +366,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
@Override
public void setRemaining(int remaining) {
remainingNum.set(remaining);
node.tooManyChildren(remaining);
}
@Override
@@ -379,23 +377,38 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
}
@Override
public void setChildren(List<DebuggerTreeNode> nodes) {
for (DebuggerTreeNode node : nodes) {
final NodeDescriptor descriptor = node.getDescriptor();
if (descriptor instanceof ValueDescriptorImpl) {
// Value is calculated already in NodeManagerImpl
children.add(create(JavaValue.this, (ValueDescriptorImpl)descriptor, myEvaluationContext, myNodeManager, false));
}
else if (descriptor instanceof MessageDescriptor) {
children.add(new JavaStackFrame.DummyMessageValueNode(descriptor.getLabel(), null));
}
public void addChildren(List<DebuggerTreeNode> nodes, boolean last) {
if (nodes.isEmpty()) {
node.addChildren(XValueChildrenList.EMPTY, last);
}
else {
nodes.stream().map(DebuggerTreeNode::getDescriptor).forEach(descriptor -> {
if (descriptor instanceof ValueDescriptorImpl) {
// Value is calculated already in NodeManagerImpl
node.addChildren(XValueChildrenList.singleton(
create(JavaValue.this, (ValueDescriptorImpl)descriptor, myEvaluationContext, myNodeManager, false)), last);
}
else if (descriptor instanceof MessageDescriptor) {
node.addChildren(XValueChildrenList.singleton(
new JavaStackFrame.DummyMessageValueNode(descriptor.getLabel(), DebuggerTreeRenderer.getDescriptorIcon(descriptor))), last);
}
});
}
}
@Override
public void setChildren(List<DebuggerTreeNode> nodes) {
addChildren(nodes, true);
}
@Override
public void setMessage(@NotNull String message,
@Nullable Icon icon,
@NotNull SimpleTextAttributes attributes,
@Nullable XDebuggerTreeNodeHyperlink link) {
node.setMessage(message, icon, attributes, link);
}
}, myEvaluationContext);
node.addChildren(children, true);
if (remainingNum.get() > 0) {
node.tooManyChildren(remainingNum.get());
}
}
});
}
@@ -19,6 +19,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.ui.impl.watch.*;
import com.intellij.debugger.ui.tree.NodeDescriptor;
import com.intellij.debugger.ui.tree.ValueDescriptor;
import com.intellij.debugger.ui.tree.render.EnumerationChildrenRenderer;
import com.intellij.icons.AllIcons;
@@ -62,7 +63,7 @@ public class DebuggerTreeRenderer extends ColoredTreeCellRenderer {
}
@Nullable
public static Icon getDescriptorIcon(NodeDescriptorImpl descriptor) {
public static Icon getDescriptorIcon(NodeDescriptor descriptor) {
Icon nodeIcon = null;
if (descriptor instanceof ThreadGroupDescriptorImpl) {
nodeIcon = (((ThreadGroupDescriptorImpl)descriptor).isCurrent() ? AllIcons.Debugger.ThreadGroupCurrent : AllIcons.Debugger.ThreadGroup);
@@ -37,6 +37,7 @@ import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiExpression;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.IncorrectOperationException;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ArrayType;
@@ -45,8 +46,7 @@ import com.sun.jdi.Value;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
/**
* User: lex
@@ -99,7 +99,6 @@ public class ArrayRenderer extends NodeRendererImpl{
public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
DebuggerManagerThreadImpl.assertIsManagerThread();
List<DebuggerTreeNode> children = new ArrayList<>();
NodeManagerImpl nodeManager = (NodeManagerImpl)builder.getNodeManager();
NodeDescriptorFactory descriptorFactory = builder.getDescriptorManager();
@@ -133,7 +132,7 @@ public class ArrayRenderer extends NodeRendererImpl{
continue;
}
children.add(arrayItemNode);
builder.addChildren(Collections.singletonList(arrayItemNode), false);
added++;
if (added > ENTRIES_LIMIT) {
break;
@@ -141,24 +140,26 @@ public class ArrayRenderer extends NodeRendererImpl{
}
}
builder.addChildren(Collections.emptyList(), true);
if (added == 0) {
if (START_INDEX == 0 && array.length() - 1 <= END_INDEX) {
children.add(nodeManager.createMessageNode(ALL_ELEMENTS_IN_RANGE_ARE_NULL));
builder.setMessage(DebuggerBundle.message("message.node.all.elements.null"), null, SimpleTextAttributes.REGULAR_ATTRIBUTES, null);
}
else {
children.add(nodeManager.createMessageNode(DebuggerBundle.message("message.node.all.array.elements.null", START_INDEX, END_INDEX)));
builder.setMessage(DebuggerBundle.message("message.node.all.array.elements.null", START_INDEX, END_INDEX), null,
SimpleTextAttributes.REGULAR_ATTRIBUTES, null);
}
}
else {
if (hiddenNulls) {
children.add(0, nodeManager.createMessageNode(HIDDEN_NULL_ELEMENTS));
builder.setMessage(DebuggerBundle.message("message.node.elements.null.hidden"), null, SimpleTextAttributes.REGULAR_ATTRIBUTES, null);
}
if (!myForced && END_INDEX < array.length() - 1) {
builder.setRemaining(array.length() - 1 - END_INDEX);
}
}
}
builder.setChildren(children);
}
private static boolean elementIsNull(ArrayReference arrayReference, int index) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -16,7 +16,12 @@
package com.intellij.debugger.ui.tree.render;
import com.intellij.debugger.ui.tree.*;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.xdebugger.frame.XDebuggerTreeNodeHyperlink;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.List;
public interface ChildrenBuilder {
@@ -28,6 +33,16 @@ public interface ChildrenBuilder {
void setChildren(List<DebuggerTreeNode> children);
default void addChildren(List<DebuggerTreeNode> children, boolean last) {
setChildren(children);
}
default void setMessage(@NotNull String message,
@Nullable Icon icon,
@NotNull SimpleTextAttributes attributes,
@Nullable XDebuggerTreeNodeHyperlink link) {
}
void setRemaining(int remaining);
void initChildrenArrayRenderer(ArrayRenderer renderer);
@@ -127,14 +127,28 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule {
for (PsiJavaCodeReferenceElement implementationReference : implementationList.getReferenceElements()) {
final PsiElement implementationClass = implementationReference.resolve();
if (implementationClass instanceof PsiClass) {
RefElement refTargetElement = null;
PsiElement targetElement = getProviderMethod((PsiClass)implementationClass);
if (targetElement == null) {
targetElement = getDefaultConstructor((PsiClass)implementationClass);
if (targetElement == null) {
targetElement = implementationClass;
final RefElement refClass = getRefManager().getReference(implementationClass);
if (refClass instanceof RefClassImpl) {
final RefMethod refConstructor = ((RefClassImpl)refClass).getDefaultConstructor();
if (refConstructor != null) {
final PsiModifierListOwner constructorElement = refConstructor.getElement();
if (constructorElement != null && constructorElement.hasModifierProperty(PsiModifier.PUBLIC)) {
refTargetElement = refConstructor;
targetElement = constructorElement;
}
}
}
}
final RefElement refTargetElement = getRefManager().getReference(targetElement);
if (targetElement == null) {
targetElement = implementationClass;
}
if (refTargetElement == null) {
refTargetElement = getRefManager().getReference(targetElement);
}
if (refTargetElement != null) {
((RefJavaElementImpl)refInterface)
.addReference(refTargetElement, targetElement, providerInterface, false, true, null);
@@ -187,11 +201,4 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule {
m.hasModifierProperty(PsiModifier.STATIC) &&
m.getParameterList().getParametersCount() == 0);
}
@Nullable
private static PsiMethod getDefaultConstructor(@NotNull PsiClass psiClass) {
final PsiMethod[] constructors = psiClass.getConstructors();
return ContainerUtil.find(constructors, m -> m.hasModifierProperty(PsiModifier.PUBLIC) &&
m.getParameterList().getParametersCount() == 0);
}
}
@@ -56,16 +56,17 @@ class PreferMostUsedWeigher extends LookupElementWeigher {
if (!(psi instanceof PsiMember)) {
return null;
}
else {
if (OBJECT_METHOD_PATTERN.accepts(psi)) {
return null;
}
if (looksLikeHelperMethodOrConst(psi)) {
return null;
}
final Integer occurrenceCount = myCompilerReferenceService.getCompileTimeOccurrenceCount(psi, myConstructorSuggestion);
return occurrenceCount == null ? null : - occurrenceCount;
if (element.getUserData(JavaGenerateMemberCompletionContributor.GENERATE_ELEMENT) != null) {
return null;
}
if (OBJECT_METHOD_PATTERN.accepts(psi)) {
return null;
}
if (looksLikeHelperMethodOrConst(psi)) {
return null;
}
final Integer occurrenceCount = myCompilerReferenceService.getCompileTimeOccurrenceCount(psi, myConstructorSuggestion);
return occurrenceCount == null ? null : -occurrenceCount;
}
//Objects.requireNonNull is an example
@@ -6,7 +6,16 @@
<package>my.ext</package>
<entry_point TYPE="class" FQNAME="my.ext.MyServiceExt" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>Class is not instantiated.</description>
<description>Class has one instantiation but it is not reachable from entry points.</description>
</problem>
<problem>
<file>MyServiceExt.java</file>
<line>4</line>
<package>my.ext</package>
<entry_point TYPE="class" FQNAME="my.ext.MyServiceExt" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>Class has one instantiation but it is not reachable from entry points.</description>
</problem>
<problem>
@@ -17,4 +26,13 @@
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>&lt;ul&gt;&lt;li&gt;Method owner class is never instantiated OR&lt;/li&gt;&lt;li&gt;An instantiation is not reachable from entry points.&lt;/li&gt;&lt;/ul&gt;</description>
</problem>
<problem>
<file>MyService.java</file>
<line>1</line>
<package>my.api</package>
<entry_point TYPE="class" FQNAME="my.api.MyService" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>&amp;nbsp;Interface has an implementation but &lt;ul&gt;&lt;li&gt;it is never instantiated OR&lt;/li&gt;&lt;li&gt;no instantiations are reachable from entry points.&lt;/li&gt;&lt;/ul&gt;</description>
</problem>
</problems>
@@ -6,7 +6,25 @@
<package>my.impl</package>
<entry_point TYPE="class" FQNAME="my.impl.MyServiceImpl" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>Class is not instantiated.</description>
<description>Class has one instantiation but it is not reachable from entry points.</description>
</problem>
<problem>
<file>MyServiceImpl.java</file>
<line>4</line>
<package>my.impl</package>
<entry_point TYPE="class" FQNAME="my.impl.MyServiceImpl" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>Class has one instantiation but it is not reachable from entry points.</description>
</problem>
<problem>
<file>MyService.java</file>
<line>1</line>
<package>my.api</package>
<entry_point TYPE="class" FQNAME="my.api.MyService" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>&amp;nbsp;Interface has an implementation but &lt;ul&gt;&lt;li&gt;it is never instantiated OR&lt;/li&gt;&lt;li&gt;no instantiations are reachable from entry points.&lt;/li&gt;&lt;/ul&gt;</description>
</problem>
<problem>
@@ -0,0 +1,8 @@
package my.impl;
import my.api.MyService;
public class MyServiceImpl implements MyService {
public MyServiceImpl(Object... objects) {System.out.println(objects);}
@Override
public void foo() {}
}
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>MyServiceImpl.java</file>
<line>5</line>
<package>my.impl</package>
<entry_point TYPE="method" FQNAME="my.impl.MyServiceImpl MyServiceImpl(java.lang.Object... objects)" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>Constructor has usage(s) but they all belong to calls chain that has no members reachable from entry points.</description>
</problem>
<problem>
<file>MyServiceImpl.java</file>
<line>4</line>
<package>my.impl</package>
<entry_point TYPE="class" FQNAME="my.impl.MyServiceImpl" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>Class has one instantiation but it is not reachable from entry points.</description>
</problem>
<problem>
<file>MyService.java</file>
<line>1</line>
<package>my.api</package>
<entry_point TYPE="method" FQNAME="my.api.MyService void foo()" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>&lt;ul&gt;&lt;li&gt;Method owner class is never instantiated OR&lt;/li&gt;&lt;li&gt;An instantiation is not reachable from entry points.&lt;/li&gt;&lt;/ul&gt;</description>
</problem>
<problem>
<file>MyService.java</file>
<line>1</line>
<package>my.api</package>
<entry_point TYPE="class" FQNAME="my.api.MyService" />
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">unused declaration</problem_class>
<description>&amp;nbsp;Interface has an implementation but &lt;ul&gt;&lt;li&gt;it is never instantiated OR&lt;/li&gt;&lt;li&gt;no instantiations are reachable from entry points.&lt;/li&gt;&lt;/ul&gt;</description>
</problem>
</problems>
@@ -0,0 +1,8 @@
package my.impl;
import my.api.MyService;
public class MyServiceImpl implements MyService {
public MyServiceImpl(Object... objects) {System.out.println(objects);}
@Override
public void foo() {}
}
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
</problems>
@@ -48,12 +48,16 @@ class Java9UnusedServiceImplementationsTest : LightJava9ModulesCodeInsightFixtur
fun testProvider() = doTest()
fun testVarargConstructor() = doTest()
fun testUnusedImplementation() = doTest(false)
fun testUnusedConstructor() = doTest(false)
fun testUnusedProvider() = doTest(false)
fun testUnusedVarargConstructor() = doTest(false)
fun testExternalImplementation() = doTest(sameModule = false)
fun testExternalConstructor() = doTest(sameModule = false)
@@ -45,6 +45,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.util.ObjectUtils.chooseNotNull;
public class DiffRequestFactoryImpl extends DiffRequestFactory {
private final DiffContentFactoryEx myContentFactory = DiffContentFactoryEx.getInstanceEx();
@@ -127,7 +129,13 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory {
}
@NotNull
public static String getTitle(@NotNull FilePath path1, @NotNull FilePath path2, @NotNull String separator) {
public static String getTitle(@Nullable FilePath path1, @Nullable FilePath path2, @NotNull String separator) {
assert path1 != null || path2 != null;
if (path1 == null || path2 == null) {
return getContentTitle(chooseNotNull(path1, path2));
}
if ((path1.isDirectory() || path2.isDirectory()) && path1.getPath().equals(path2.getPath())) {
return path1.getPresentableUrl();
}
@@ -19,6 +19,7 @@ import com.intellij.ide.WelcomeWizardUtil
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.*
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.SystemInfo
@@ -264,6 +265,8 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
}
companion object {
private val LOG = Logger.getInstance(UISettings::class.java)
const val ANIMATION_DURATION = 300 // Milliseconds
/** Not tabbed pane. */
@@ -369,14 +372,16 @@ class UISettings : BaseState(), PersistentStateComponent<UISettings> {
@JvmStatic
fun restoreFontSize(readSize: Int, readScale: Float?): Int {
var size = readSize
if (readScale == null || readScale <= 0) {
// Reset font to default on switch from IDE-managed HiDPI to JRE-managed HiDPI. Doesn't affect OSX.
if (UIUtil.isJreHiDPIEnabled() && !SystemInfo.isMac) return UIUtil.DEF_SYSTEM_FONT_SIZE.toInt()
if (UIUtil.isJreHiDPIEnabled() && !SystemInfo.isMac) size = UIUtil.DEF_SYSTEM_FONT_SIZE.toInt()
}
else {
return ((readSize.toFloat() / readScale) * normalizingScale).toInt()
size = ((readSize.toFloat() / readScale) * normalizingScale).toInt()
}
return readSize
LOG.info("Loaded: fontSize=$readSize, fontScale=$readScale; restored: fontSize=$size, fontScale=$normalizingScale")
return size
}
}
@@ -21,7 +21,7 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -0,0 +1,67 @@
/*
* 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.externalSystem.service.project;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Aggregates all {@link ProjectDataService#EP_NAME registered data services}
* and provides entry points for project data management.
*
* @author Vladislav Soroka
* @since 4/16/13 11:38 AM
*/
public interface ProjectDataManager {
static ProjectDataManager getInstance() {
return ServiceManager.getService(ProjectDataManager.class);
}
@SuppressWarnings("unchecked")
void importData(@NotNull Collection<DataNode<?>> nodes,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous);
<T> void importData(@NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous);
<T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous);
<T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
boolean synchronous);
void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode);
@Nullable
ExternalProjectInfo getExternalProjectData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId,
@NotNull String externalProjectPath);
@NotNull
Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId);
}
@@ -0,0 +1,45 @@
/*
* Copyright 2000-2016 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.externalSystem.service.project.manage;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.importing.ImportSpec;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
/**
* @author Vladislav.Soroka
* @since 10/23/2014
*/
public interface ExternalProjectsManager {
static ExternalProjectsManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, ExternalProjectsManager.class);
}
@NotNull
Project getProject();
void refreshProject(@NotNull String externalProjectPath, @NotNull ImportSpec importSpec);
void runWhenInitialized(Runnable runnable);
boolean isIgnored(@NotNull ProjectSystemId systemId, @NotNull String projectPath);
void setIgnored(@NotNull DataNode<?> dataNode, boolean isIgnored);
}
@@ -0,0 +1,28 @@
/*
* 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.externalSystem.service.project.manage;
import com.intellij.util.messages.Topic;
/**
* @author Vladislav Soroka
* @since 4/13/17 11:38 AM
*/
public interface ProjectDataImportListener {
Topic<ProjectDataImportListener> TOPIC = new Topic<>("project data import listener", ProjectDataImportListener.class);
void onImportFinished(String projectPath);
}
@@ -16,6 +16,11 @@
package com.intellij.openapi.externalSystem.settings;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.project.Project;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.messages.Topic;
@@ -138,13 +143,17 @@ public abstract class AbstractExternalSystemSettings<
}
public void setLinkedProjectsSettings(@NotNull Collection<PS> settings) {
setLinkedProjectsSettings(settings, null);
}
private void setLinkedProjectsSettings(@NotNull Collection<PS> settings, @Nullable ExternalSystemSettingsListener listener) {
List<PS> added = ContainerUtilRt.newArrayList();
Map<String, PS> removed = ContainerUtilRt.newHashMap(myLinkedProjectsSettings);
myLinkedProjectsSettings.clear();
for (PS current : settings) {
myLinkedProjectsSettings.put(current.getExternalProjectPath(), current);
}
for (PS current : settings) {
PS old = removed.remove(current.getExternalProjectPath());
if (old == null) {
@@ -152,15 +161,24 @@ public abstract class AbstractExternalSystemSettings<
}
else {
if (current.isUseAutoImport() != old.isUseAutoImport()) {
if (listener != null) {
listener.onUseAutoImportChange(current.isUseAutoImport(), current.getExternalProjectPath());
}
getPublisher().onUseAutoImportChange(current.isUseAutoImport(), current.getExternalProjectPath());
}
checkSettings(old, current);
}
}
if (!added.isEmpty()) {
if (listener != null) {
listener.onProjectsLinked(added);
}
getPublisher().onProjectsLinked(added);
}
if (!removed.isEmpty()) {
if (listener != null) {
listener.onProjectsUnlinked(removed.keySet());
}
getPublisher().onProjectsUnlinked(removed.keySet());
}
}
@@ -192,10 +210,27 @@ public abstract class AbstractExternalSystemSettings<
protected void loadState(@NotNull State<PS> state) {
Set<PS> settings = state.getLinkedExternalProjectsSettings();
if (settings != null) {
myLinkedProjectsSettings.clear();
for (PS projectSettings : settings) {
myLinkedProjectsSettings.put(projectSettings.getExternalProjectPath(), projectSettings);
}
setLinkedProjectsSettings(settings, new ExternalSystemSettingsListenerAdapter() {
@Override
public void onProjectsLinked(@NotNull Collection linked) {
for (Object o : linked) {
final ExternalProjectSettings settings = (ExternalProjectSettings)o;
for (ExternalSystemManager manager : ExternalSystemManager.EP_NAME.getExtensions()) {
AbstractExternalSystemSettings se = (AbstractExternalSystemSettings)manager.getSettingsProvider().fun(myProject);
ProjectSystemId externalSystemId = manager.getSystemId();
if (settings == se.getLinkedProjectSettings(settings.getExternalProjectPath())) {
ExternalProjectsManager.getInstance(myProject).refreshProject(
settings.getExternalProjectPath(),
new ImportSpecBuilder(myProject, externalSystemId)
.useDefaultCallback()
.use(ProgressExecutionMode.IN_BACKGROUND_ASYNC)
.build()
);
}
}
}
}
});
}
}
@@ -16,7 +16,6 @@
package com.intellij.openapi.externalSystem.settings;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,7 +36,7 @@ public abstract class ExternalProjectSettings implements Comparable<ExternalProj
@NotNull
public Set<String> getModules() {
return myModules == null ? Collections.<String>emptySet() : myModules;
return myModules == null ? Collections.emptySet() : myModules;
}
public void setModules(@Nullable Set<String> modules) {
@@ -18,20 +18,17 @@ package com.intellij.openapi.externalSystem.action;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.view.ProjectNode;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfoRt;
import com.intellij.util.containers.ContainerUtilRt;
@@ -87,7 +84,7 @@ public class DetachExternalProjectAction extends ExternalSystemNodeAction<Projec
forgetExternalProjects(Collections.singleton(projectData.getLinkedExternalProjectPath()));
ExternalSystemApiUtil.getSettings(project, projectSystemId).unlinkExternalProject(projectData.getLinkedExternalProjectPath());
ExternalProjectsManager.getInstance(project).forgetExternalProjectData(projectSystemId, projectData.getLinkedExternalProjectPath());
ExternalProjectsManagerImpl.getInstance(project).forgetExternalProjectData(projectSystemId, projectData.getLinkedExternalProjectPath());
// Process orphan modules.
List<Module> orphanModules = ContainerUtilRt.newArrayList();
@@ -102,8 +99,8 @@ public class DetachExternalProjectAction extends ExternalSystemNodeAction<Projec
if (!orphanModules.isEmpty()) {
projectNode.getGroup().remove(projectNode);
ProjectDataManager.getInstance().removeData(
ProjectKeys.MODULE, orphanModules, Collections.<DataNode<ModuleData>>emptyList(), projectData, project, false);
ProjectDataManagerImpl.getInstance().removeData(
ProjectKeys.MODULE, orphanModules, Collections.emptyList(), projectData, project, false);
}
}
}
@@ -20,7 +20,7 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.ui.ExternalProjectDataSelectorDialog;
import com.intellij.openapi.externalSystem.view.ExternalSystemNode;
import com.intellij.openapi.externalSystem.view.ProjectNode;
@@ -24,7 +24,7 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.externalSystem.view.ExternalSystemNode;
@@ -24,7 +24,7 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.model.task.TaskData;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemKeymapExtension;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager;
import com.intellij.openapi.externalSystem.view.ExternalSystemNode;
@@ -55,7 +55,7 @@ public class AssignShortcutAction extends ExternalSystemNodeAction<TaskData> {
@NotNull ProjectSystemId projectSystemId,
@NotNull TaskData taskData,
@NotNull AnActionEvent e) {
final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager();
final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager();
final String actionId = shortcutsManager.getActionId(taskData.getLinkedExternalProjectPath(), taskData.getName());
if (actionId != null) {
AnAction action = ActionManager.getInstance().getAction(actionId);
@@ -22,7 +22,7 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.TaskData;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator;
import com.intellij.openapi.externalSystem.view.ExternalSystemNode;
import com.intellij.openapi.externalSystem.view.RunConfigurationNode;
@@ -108,6 +108,6 @@ public abstract class ToggleTaskActivationAction extends ExternalSystemToggleAct
private ExternalSystemTaskActivator getTaskActivator(AnActionEvent e) {
return ExternalProjectsManager.getInstance(getProject(e)).getTaskActivator();
return ExternalProjectsManagerImpl.getInstance(getProject(e)).getTaskActivator();
}
}
@@ -20,7 +20,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.service.project.ProjectRenameAware;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.service.ui.ExternalToolWindowManager;
import com.intellij.openapi.externalSystem.service.vcs.ExternalSystemVcsRegistrar;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
@@ -62,7 +62,7 @@ public class ExternalSystemStartupActivity implements StartupActivity {
ProjectRenameAware.beAware(project);
};
ExternalProjectsManager.getInstance(project).init();
ExternalProjectsManagerImpl.getInstance(project).init();
DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(task, project));
}
}
@@ -26,13 +26,12 @@ import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.model.task.TaskData;
import com.intellij.openapi.externalSystem.service.execution.cmd.CommandLineCompletionProvider;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.TextAccessor;
import com.intellij.util.BooleanFunction;
import com.intellij.util.containers.ContainerUtil;
import groovyjarjarcommonscli.Options;
import icons.ExternalSystemIcons;
@@ -1,6 +1,5 @@
package com.intellij.openapi.externalSystem.service.internal;
import com.intellij.execution.configurations.ParametersList;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.DataNode;
@@ -15,7 +14,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskState;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType;
import com.intellij.openapi.externalSystem.service.ExternalSystemFacadeManager;
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProjectResolver;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
@@ -139,7 +138,7 @@ public class ExternalSystemResolveProjectTask extends AbstractExternalSystemTask
final long currentTimeMillis = System.currentTimeMillis();
projectInfo.setLastImportTimestamp(currentTimeMillis);
projectInfo.setLastSuccessfulImportTimestamp(state == ExternalSystemTaskState.FAILED ? -1 : currentTimeMillis);
ProjectDataManager.getInstance().updateExternalProjectData(getIdeProject(), projectInfo);
ProjectDataManagerImpl.getInstance().updateExternalProjectData(getIdeProject(), projectInfo);
}
}
}
@@ -28,7 +28,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemConfigurableAware;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.LocationAwareExternalSystemException;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
@@ -156,7 +156,7 @@ public class ExternalSystemNotificationManager implements Disposable {
NotificationGroup group;
if (notificationData.getBalloonGroup() == null) {
ExternalProjectsView externalProjectsView =
ExternalProjectsManager.getInstance(myProject).getExternalProjectsView(externalSystemId);
ExternalProjectsManagerImpl.getInstance(myProject).getExternalProjectsView(externalSystemId);
group = externalProjectsView instanceof ExternalProjectsViewImpl ?
((ExternalProjectsViewImpl)externalProjectsView).getNotificationGroup() : null;
}
@@ -33,7 +33,7 @@ import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMo
import com.intellij.openapi.externalSystem.service.internal.ExternalSystemProcessingManager;
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
@@ -609,22 +609,20 @@ public class ExternalSystemProjectsWatcher extends ExternalSystemTaskNotificatio
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
if (psiFile != null) {
final CRC32 crc32 = new CRC32();
ApplicationManager.getApplication().runReadAction(() -> {
psiFile.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof LeafElement && !(element instanceof PsiWhiteSpace) && !(element instanceof PsiComment)) {
String text = element.getText();
if (!text.trim().isEmpty()) {
for (int i = 0, end = text.length(); i < end; i++) {
crc32.update(text.charAt(i));
}
ApplicationManager.getApplication().runReadAction(() -> psiFile.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof LeafElement && !(element instanceof PsiWhiteSpace) && !(element instanceof PsiComment)) {
String text = element.getText();
if (!text.trim().isEmpty()) {
for (int i = 0, end = text.length(); i < end; i++) {
crc32.update(text.charAt(i));
}
}
super.visitElement(element);
}
});
});
super.visitElement(element);
}
}));
newCrc = crc32.getValue();
}
else {
@@ -176,6 +176,6 @@ public class ExternalModuleStructureExtension extends ModuleStructureExtension {
private static void unlinkProject(@NotNull Project project, ProjectSystemId systemId, String rootProjectPath) {
ExternalSystemApiUtil.getLocalSettings(project, systemId).forgetExternalProjects(Collections.singleton(rootProjectPath));
ExternalSystemApiUtil.getSettings(project, systemId).unlinkExternalProject(rootProjectPath);
ExternalProjectsManager.getInstance(project).forgetExternalProjectData(systemId, rootProjectPath);
ExternalProjectsManagerImpl.getInstance(project).forgetExternalProjectData(systemId, rootProjectPath);
}
}
@@ -19,7 +19,10 @@ import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.project.ExternalConfigPathAware;
@@ -35,7 +38,8 @@ import com.intellij.openapi.module.ModuleTypeId;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.*;
import com.intellij.util.Alarm;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.xmlb.annotations.AbstractCollection;
@@ -105,7 +109,7 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per
final DataNode<ProjectData> projectStructure = externalProjectInfo.getExternalProjectStructure();
if (projectStructure == null) return false;
ProjectDataManager.getInstance().ensureTheDataIsReadyToUse(projectStructure);
ProjectDataManagerImpl.getInstance().ensureTheDataIsReadyToUse(projectStructure);
return externalProjectInfo.getExternalProjectPath().equals(projectStructure.getData().getLinkedExternalProjectPath());
}
catch (Exception e) {
@@ -262,7 +266,7 @@ public class ExternalProjectsDataStorage implements SettingsSavingComponent, Per
if (linkedProjectSettings != null && ContainerUtil.isEmpty(linkedProjectSettings.getModules())) {
final Set<String> modulePaths = ContainerUtil.map2Set(
ExternalSystemApiUtil.findAllRecursively(externalProjectInfo.getExternalProjectStructure(), ProjectKeys.MODULE),
ExternalSystemApiUtil.findAllRecursively(externalProjectInfo.getExternalProjectStructure(), MODULE),
node -> node.getData().getLinkedExternalProjectPath());
linkedProjectSettings.setModules(modulePaths);
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.importing.ImportSpec;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
@@ -54,7 +55,7 @@ import static com.intellij.openapi.externalSystem.model.ProjectKeys.TASK;
* @since 10/23/2014
*/
@State(name = "ExternalProjectsManager", storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)})
public class ExternalProjectsManager implements PersistentStateComponent<ExternalProjectsState>, Disposable {
public class ExternalProjectsManagerImpl implements ExternalProjectsManager, PersistentStateComponent<ExternalProjectsState>, Disposable {
private static final Logger LOG = Logger.getInstance(ExternalProjectsManager.class);
private final AtomicBoolean isInitializationFinished = new AtomicBoolean();
@@ -71,12 +72,7 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
private final List<ExternalProjectsView> myProjectsViews = new SmartList<>();
private ExternalSystemProjectsWatcher myWatcher;
public static ExternalProjectsManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, ExternalProjectsManager.class);
}
public ExternalProjectsManager(@NotNull Project project) {
public ExternalProjectsManagerImpl(@NotNull Project project) {
myProject = project;
myShortcutsManager = new ExternalSystemShortcutsManager(project);
Disposer.register(this, myShortcutsManager);
@@ -84,7 +80,13 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
myRunManagerListener = new ExternalSystemRunManagerListener(this);
}
public static ExternalProjectsManagerImpl getInstance(@NotNull Project project) {
ExternalProjectsManager service = ServiceManager.getService(project, ExternalProjectsManager.class);
return (ExternalProjectsManagerImpl)service;
}
@NotNull
@Override
public Project getProject() {
return myProject;
}
@@ -112,7 +114,7 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
@Nullable
public ExternalProjectsView getExternalProjectsView(@NotNull ProjectSystemId systemId) {
for (ExternalProjectsView projectsView : myProjectsViews) {
if(projectsView.getSystemId().equals(systemId)) return projectsView;
if (projectsView.getSystemId().equals(systemId)) return projectsView;
}
return null;
}
@@ -155,8 +157,14 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
}
}
@Override
public void refreshProject(@NotNull final String externalProjectPath, @NotNull final ImportSpec importSpec) {
ExternalSystemUtil.refreshProject(externalProjectPath, importSpec);
}
@Override
public void runWhenInitialized(Runnable runnable) {
synchronized(isInitializationFinished) {
synchronized (isInitializationFinished) {
if (isInitializationFinished.get()) {
ApplicationManager.getApplication().executeOnPooledThread(runnable);
}
@@ -213,7 +221,7 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
.collect(Collectors.toMap(o -> o.getSystemId().getId(), o -> o.getSystemId()));
for (Map.Entry<String, ExternalProjectsState.State> systemState : myState.getExternalSystemsState().entrySet()) {
ProjectSystemId systemId = systemIds.get(systemState.getKey());
if(systemId == null) continue;
if (systemId == null) continue;
for (Map.Entry<String, TaskActivationState> activationStateEntry : systemState.getValue().getExternalSystemsTaskActivation()
.entrySet()) {
@@ -243,6 +251,7 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
};
}
@Override
public boolean isIgnored(@NotNull ProjectSystemId systemId, @NotNull String projectPath) {
final ExternalProjectInfo projectInfo = ExternalSystemUtil.getExternalProjectInfo(myProject, systemId, projectPath);
if (projectInfo == null) return true;
@@ -250,6 +259,7 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
return ExternalProjectsDataStorage.getInstance(myProject).isIgnored(projectInfo.getExternalProjectPath(), projectPath, MODULE);
}
@Override
public void setIgnored(@NotNull DataNode<?> dataNode, boolean isIgnored) {
ExternalProjectsDataStorage.getInstance(myProject).setIgnored(dataNode, isIgnored);
ExternalSystemKeymapExtension.updateActions(myProject, ExternalSystemApiUtil.findAllRecursively(dataNode, TASK));
@@ -264,7 +274,7 @@ public class ExternalProjectsManager implements PersistentStateComponent<Externa
public void dispose() {
myProjectsViews.clear();
myRunManagerListener.detach();
if(myWatcher != null) {
if (myWatcher != null) {
myWatcher.stop();
}
myWatcher = null;
@@ -88,7 +88,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension {
MultiMap<ProjectSystemId, String> projectToActionsMapping = MultiMap.create();
for (ExternalSystemManager<?, ?, ?, ?, ?> manager : ExternalSystemApiUtil.getAllManagers()) {
projectToActionsMapping.putValues(manager.getSystemId(), ContainerUtil.<String>emptyList());
projectToActionsMapping.putValues(manager.getSystemId(), ContainerUtil.emptyList());
}
ActionManager actionManager = ActionManager.getInstance();
@@ -194,7 +194,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension {
private static void createActions(Project project, Collection<DataNode<TaskData>> taskNodes) {
ActionManager actionManager = ActionManager.getInstance();
final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager();
final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager();
if (actionManager != null) {
for (DataNode<TaskData> each : taskNodes) {
final DataNode<ModuleData> moduleData = ExternalSystemApiUtil.findParent(each, ProjectKeys.MODULE);
@@ -233,7 +233,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension {
}
public static String getActionPrefix(@NotNull Project project, @Nullable String path) {
return ExternalProjectsManager.getInstance(project).getShortcutsManager().getActionId(path, null);
return ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager().getActionId(path, null);
}
public static void updateRunConfigurationActions(Project project, ProjectSystemId systemId) {
@@ -251,7 +251,7 @@ public class ExternalSystemKeymapExtension implements KeymapExtension {
Set<RunnerAndConfigurationSettings> settings = new THashSet<>(
RunManager.getInstance(project).getConfigurationSettingsList(configurationType));
final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManager.getInstance(project).getShortcutsManager();
final ExternalSystemShortcutsManager shortcutsManager = ExternalProjectsManagerImpl.getInstance(project).getShortcutsManager();
for (RunnerAndConfigurationSettings configurationSettings : settings) {
ExternalSystemRunConfigurationAction runConfigurationAction =
new ExternalSystemRunConfigurationAction(project, configurationSettings);
@@ -23,6 +23,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.ExternalProjectsStateProvider;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.util.Pair;
@@ -42,11 +43,11 @@ import static com.intellij.openapi.externalSystem.service.project.manage.Externa
*/
class ExternalSystemRunManagerListener implements RunManagerListener {
private ExternalProjectsManager myManager;
private ExternalProjectsManagerImpl myManager;
private final Map<Integer, Pair<String, RunnerAndConfigurationSettings>> myMap;
public ExternalSystemRunManagerListener(ExternalProjectsManager manager) {
myManager = manager;
myManager = (ExternalProjectsManagerImpl)manager;
myMap = ContainerUtil.newConcurrentMap();
}
@@ -61,7 +62,7 @@ class ExternalSystemRunManagerListener implements RunManagerListener {
final Pair<String, RunnerAndConfigurationSettings> pair = myMap.remove(System.identityHashCode(settings));
if (pair == null) return;
final ExternalProjectsManager.ExternalProjectsStateProvider stateProvider = myManager.getStateProvider();
final ExternalProjectsStateProvider stateProvider = myManager.getStateProvider();
final ExternalSystemTaskExecutionSettings taskExecutionSettings =
((ExternalSystemRunConfiguration)settings.getConfiguration()).getSettings();
@@ -87,7 +88,7 @@ class ExternalSystemRunManagerListener implements RunManagerListener {
if (settings.getConfiguration() instanceof ExternalSystemRunConfiguration) {
final Pair<String, RunnerAndConfigurationSettings> pair = myMap.get(System.identityHashCode(settings));
if (pair != null) {
final ExternalProjectsManager.ExternalProjectsStateProvider stateProvider = myManager.getStateProvider();
final ExternalProjectsStateProvider stateProvider = myManager.getStateProvider();
final ExternalSystemTaskExecutionSettings taskExecutionSettings =
((ExternalSystemRunConfiguration)settings.getConfiguration()).getSettings();
@@ -29,20 +29,18 @@ import com.intellij.openapi.externalSystem.model.task.TaskData;
import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.ExternalProjectsStateProvider;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.ExternalProjectsStateProvider;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.task.TaskCallback;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FactoryMap;
@@ -96,7 +94,7 @@ public class ExternalSystemTaskActivator {
public String getDescription(ProjectSystemId systemId, String projectPath, String taskName) {
List<String> result = new ArrayList<>();
final ExternalProjectsStateProvider stateProvider =
ExternalProjectsManager.getInstance(myProject).getStateProvider();
ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
final TaskActivationState taskActivationState = stateProvider.getTasksActivation(systemId, projectPath);
if (taskActivationState == null) return null;
@@ -133,7 +131,8 @@ public class ExternalSystemTaskActivator {
}
public boolean runTasks(@NotNull Collection<String> modules, @NotNull Phase... phases) {
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider();
final ExternalProjectsStateProvider stateProvider =
ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
final Queue<Pair<ProjectSystemId, ExternalSystemTaskExecutionSettings>> tasksQueue =
new LinkedList<>();
@@ -245,7 +244,7 @@ public class ExternalSystemTaskActivator {
}
public boolean isTaskOfPhase(@NotNull TaskData taskData, @NotNull Phase phase) {
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider();
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
final TaskActivationState taskActivationState =
stateProvider.getTasksActivation(taskData.getOwner(), taskData.getLinkedExternalProjectPath());
if (taskActivationState == null) return false;
@@ -263,7 +262,7 @@ public class ExternalSystemTaskActivator {
public void addTasks(@NotNull Collection<TaskActivationEntry> entries) {
if (entries.isEmpty()) return;
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider();
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
for (TaskActivationEntry entry : entries) {
final TaskActivationState taskActivationState = stateProvider.getTasksActivation(entry.systemId, entry.projectPath);
taskActivationState.getTasks(entry.phase).add(entry.taskName);
@@ -279,7 +278,7 @@ public class ExternalSystemTaskActivator {
public void removeTasks(@NotNull Collection<TaskActivationEntry> entries) {
if (entries.isEmpty()) return;
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider();
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
for (TaskActivationEntry activationEntry : entries) {
final TaskActivationState taskActivationState =
stateProvider.getTasksActivation(activationEntry.systemId, activationEntry.projectPath);
@@ -300,7 +299,7 @@ public class ExternalSystemTaskActivator {
public void moveTasks(@NotNull Collection<TaskActivationEntry> entries, int increment) {
LOG.assertTrue(increment == -1 || increment == 1);
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider();
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
for (TaskActivationEntry activationEntry : entries) {
final TaskActivationState taskActivationState =
stateProvider.getTasksActivation(activationEntry.systemId, activationEntry.projectPath);
@@ -319,7 +318,7 @@ public class ExternalSystemTaskActivator {
int increment) {
LOG.assertTrue(increment == -1 || increment == 1);
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManager.getInstance(myProject).getStateProvider();
final ExternalProjectsStateProvider stateProvider = ExternalProjectsManagerImpl.getInstance(myProject).getStateProvider();
final Map<String, TaskActivationState> activationMap = stateProvider.getProjectsTasksActivationMap(systemId);
final List<String> currentPaths = ContainerUtil.newArrayList(activationMap.keySet());
if (pathsGroup != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* 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.
@@ -15,394 +15,102 @@
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl;
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.util.containers.ContainerUtil.map2Array;
import java.util.Collection;
/**
* Aggregates all {@link ProjectDataService#EP_NAME registered data services} and provides entry points for project data management.
*
* @author Denis Zhdanov
* @since 4/16/13 11:38 AM
* @deprecated use {@link com.intellij.openapi.externalSystem.service.project.ProjectDataManager} instead
*/
public class ProjectDataManager {
private static final Logger LOG = Logger.getInstance("#" + ProjectDataManager.class.getName());
private static final com.intellij.openapi.util.Key<Boolean> DATA_READY =
com.intellij.openapi.util.Key.create("externalSystem.data.ready");
@NotNull private final NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>> myServices;
public class ProjectDataManager extends ProjectDataManagerImpl {
public static ProjectDataManager getInstance() {
return ServiceManager.getService(ProjectDataManager.class);
return new ProjectDataManager(ProjectDataManagerImpl.getInstance());
}
public ProjectDataManager() {
myServices = new NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>>() {
@NotNull
@Override
protected Map<Key<?>, List<ProjectDataService<?, ?>>> compute() {
Map<Key<?>, List<ProjectDataService<?, ?>>> result = ContainerUtilRt.newHashMap();
for (ProjectDataService<?, ?> service : ProjectDataService.EP_NAME.getExtensions()) {
List<ProjectDataService<?, ?>> services = result.get(service.getTargetDataKey());
if (services == null) {
result.put(service.getTargetDataKey(), services = ContainerUtilRt.newArrayList());
}
services.add(service);
}
private final ProjectDataManagerImpl delegate;
for (List<ProjectDataService<?, ?>> services : result.values()) {
ExternalSystemApiUtil.orderAwareSort(services);
}
return result;
}
};
}
public ProjectDataManager(ProjectDataManagerImpl delegate) {this.delegate = delegate;}
@SuppressWarnings("unchecked")
@Override
public void importData(@NotNull Collection<DataNode<?>> nodes,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
if (project.isDisposed()) return;
MultiMap<Key<?>, DataNode<?>> grouped = ExternalSystemApiUtil.recursiveGroup(nodes);
for (Key<?> key : myServices.getValue().keySet()) {
if (!grouped.containsKey(key)) {
grouped.put(key, Collections.<DataNode<?>>emptyList());
}
}
final Collection<DataNode<?>> projects = grouped.get(ProjectKeys.PROJECT);
// only one project(can be multi-module project) expected for per single import
assert projects.size() == 1 || projects.isEmpty();
final DataNode<ProjectData> projectNode = (DataNode<ProjectData>)ContainerUtil.getFirstItem(projects);
final ProjectData projectData;
ProjectSystemId projectSystemId;
if (projectNode != null) {
projectData = projectNode.getData();
projectSystemId = projectNode.getData().getOwner();
ExternalProjectsDataStorage.getInstance(project).saveInclusionSettings(projectNode);
}
else {
projectData = null;
DataNode<ModuleData> aModuleNode = (DataNode<ModuleData>)ContainerUtil.getFirstItem(grouped.get(ProjectKeys.MODULE));
projectSystemId = aModuleNode != null ? aModuleNode.getData().getOwner() : null;
}
if (projectSystemId != null) {
ExternalSystemUtil.scheduleExternalViewStructureUpdate(project, projectSystemId);
}
List<Runnable> onSuccessImportTasks = ContainerUtil.newSmartList();
try {
final Set<Map.Entry<Key<?>, Collection<DataNode<?>>>> entries = grouped.entrySet();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.setIndeterminate(false);
}
final int size = entries.size();
int count = 0;
List<Runnable> postImportTasks = ContainerUtil.newSmartList();
for (Map.Entry<Key<?>, Collection<DataNode<?>>> entry : entries) {
if (indicator != null) {
String message = ExternalSystemBundle.message(
"progress.update.text", projectSystemId != null ? projectSystemId.getReadableName() : "",
"Refresh " + getReadableText(entry.getKey()));
indicator.setText(message);
indicator.setFraction((double)count++ / size);
}
doImportData(entry.getKey(), entry.getValue(), projectData, project, modelsProvider, postImportTasks, onSuccessImportTasks);
}
for (Runnable postImportTask : postImportTasks) {
postImportTask.run();
}
commit(modelsProvider, project, synchronous, "Imported data");
if (indicator != null) {
indicator.setIndeterminate(true);
}
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
for (Runnable onSuccessImportTask : ContainerUtil.reverse(onSuccessImportTasks)) {
onSuccessImportTask.run();
}
delegate.importData(nodes, project, modelsProvider, synchronous);
}
@NotNull
private static String getReadableText(@NotNull Key key) {
StringBuilder buffer = new StringBuilder();
String s = key.toString();
for (int i = 0; i < s.length(); i++) {
char currChar = s.charAt(i);
if (Character.isUpperCase(currChar)) {
if (i != 0) {
buffer.append(' ');
}
buffer.append(StringUtil.toLowerCase(currChar));
}
else {
buffer.append(currChar);
}
}
return buffer.toString();
}
public <T> void importData(@NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
for (DataNode<T> node : nodes) {
dummy.add(node);
}
importData(dummy, project, new IdeModifiableModelsProviderImpl(project), synchronous);
@Override
public <T> void importData(@NotNull Collection<DataNode<T>> nodes,
@NotNull Project project, boolean synchronous) {
delegate.importData(nodes, project, synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
dummy.add(node);
importData(dummy, project, modelsProvider, synchronous);
delegate.importData(node, project, modelsProvider, synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
boolean synchronous) {
importData(node, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
@SuppressWarnings("unchecked")
private <T> void doImportData(@NotNull Key<T> key,
@NotNull Collection<DataNode<?>> nodes,
@Nullable final ProjectData projectData,
@NotNull final Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull final List<Runnable> postImportTasks,
@NotNull final List<Runnable> onSuccessImportTasks) {
if (project.isDisposed()) return;
if (project instanceof ProjectImpl) {
assert ((ProjectImpl)project).isComponentsCreated();
}
final List<DataNode<T>> toImport = ContainerUtil.newSmartList();
final List<DataNode<T>> toIgnore = ContainerUtil.newSmartList();
for (DataNode node : nodes) {
if (!key.equals(node.getKey())) continue;
if (node.isIgnored()) {
toIgnore.add(node);
}
else {
toImport.add(node);
}
}
ensureTheDataIsReadyToUse((Collection)toImport);
final List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
if (services == null) {
LOG.warn(String.format(
"Can't import data nodes '%s'. Reason: no service is registered for key %s. Available services for %s",
toImport, key, myServices.getValue().keySet()
));
}
else {
for (ProjectDataService<?, ?> service : services) {
final long importStartTime = System.currentTimeMillis();
((ProjectDataService)service).importData(toImport, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long importTimeInMs = (System.currentTimeMillis() - importStartTime);
LOG.debug(String.format("Service %s imported data in %d ms", service.getClass().getSimpleName(), importTimeInMs));
}
if(projectData != null) {
ensureTheDataIsReadyToUse((Collection)toIgnore);
final long removeStartTime = System.currentTimeMillis();
final Computable<Collection<?>> orphanIdeDataComputable =
((ProjectDataService)service).computeOrphanData(toImport, projectData, project, modelsProvider);
((ProjectDataService)service).removeData(orphanIdeDataComputable, toIgnore, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long removeTimeInMs = (System.currentTimeMillis() - removeStartTime);
LOG.debug(String.format("Service %s computed and removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
}
}
if (services != null && projectData != null) {
postImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).postProcess(toImport, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
onSuccessImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).onSuccessImport(project);
if(LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
}
@NotNull Project project, boolean synchronous) {
delegate.importData(node, project, synchronous);
}
@Override
public void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode) {
if (dataNode == null) return;
if (Boolean.TRUE.equals(dataNode.getUserData(DATA_READY))) return;
ExternalSystemApiUtil.visit(dataNode, dataNode1 -> {
prepareDataToUse(dataNode1);
dataNode1.putUserData(DATA_READY, Boolean.TRUE);
});
delegate.ensureTheDataIsReadyToUse(dataNode);
}
@SuppressWarnings("unchecked")
@Override
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Collection<DataNode<E>> toIgnore,
@NotNull ProjectData projectData,
@NotNull Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
try {
List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
for (ProjectDataService service : services) {
final long removeStartTime = System.currentTimeMillis();
service.removeData(new Computable.PredefinedValueComputable<Collection>(toRemove), toIgnore, projectData, project, modelsProvider);
if(LOG.isDebugEnabled()) {
final long removeTimeInMs = System.currentTimeMillis() - removeStartTime;
LOG.debug(String.format("Service %s removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
commit(modelsProvider, project, synchronous, "Removed data");
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
delegate.removeData(key, toRemove, toIgnore, projectData, project, modelsProvider, synchronous);
}
@Override
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Project project,
boolean synchronous) {
removeData(key, toRemove, toIgnore, projectData, project, new IdeModifiableModelsProviderImpl(project), synchronous);
@NotNull Collection<DataNode<E>> toIgnore,
@NotNull ProjectData projectData,
@NotNull Project project, boolean synchronous) {
delegate.removeData(key, toRemove, toIgnore, projectData, project, synchronous);
}
public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) {
if (!project.isDisposed()) {
ExternalProjectsManager.getInstance(project).updateExternalProjectData(externalProjectInfo);
}
@Override
public void updateExternalProjectData(@NotNull Project project,
@NotNull ExternalProjectInfo externalProjectInfo) {
delegate.updateExternalProjectData(project, externalProjectInfo);
}
@Nullable
@Override
public ExternalProjectInfo getExternalProjectData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId,
@NotNull String externalProjectPath) {
return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null;
return delegate.getExternalProjectData(project, projectSystemId, externalProjectPath);
}
@NotNull
public Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) {
if (!project.isDisposed()) {
return ExternalProjectsDataStorage.getInstance(project).list(projectSystemId);
}
else {
return ContainerUtil.emptyList();
}
}
private void ensureTheDataIsReadyToUse(@NotNull Collection<DataNode<?>> nodes) {
for (DataNode<?> node : nodes) {
ensureTheDataIsReadyToUse(node);
}
}
private void prepareDataToUse(@NotNull DataNode dataNode) {
final Map<Key<?>, List<ProjectDataService<?, ?>>> servicesByKey = myServices.getValue();
List<ProjectDataService<?, ?>> services = servicesByKey.get(dataNode.getKey());
if (services != null) {
try {
dataNode.prepareData(map2Array(services, ClassLoader.class, service -> service.getClass().getClassLoader()));
}
catch (Exception e) {
LOG.debug(e);
dataNode.clear(true);
}
}
}
private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous,
@NotNull final String commitDesc) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
final long startTime = System.currentTimeMillis();
modelsProvider.commit();
final long timeInMs = System.currentTimeMillis() - startTime;
LOG.debug(String.format("%s committed in %d ms", commitDesc, timeInMs));
}
});
}
private static void dispose(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
modelsProvider.dispose();
}
});
@Override
public Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId) {
return delegate.getExternalProjectsData(project, projectSystemId);
}
}
@@ -0,0 +1,416 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.service.project.manage;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.*;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.util.containers.ContainerUtil.map2Array;
/**
* Aggregates all {@link ProjectDataService#EP_NAME registered data services} and provides entry points for project data management.
*
* @author Denis Zhdanov
* @since 4/16/13 11:38 AM
*/
public class ProjectDataManagerImpl implements ProjectDataManager {
private static final Logger LOG = Logger.getInstance("#" + ProjectDataManagerImpl.class.getName());
private static final com.intellij.openapi.util.Key<Boolean> DATA_READY =
com.intellij.openapi.util.Key.create("externalSystem.data.ready");
@NotNull private final NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>> myServices;
public static ProjectDataManagerImpl getInstance() {
ProjectDataManager service = ServiceManager.getService(ProjectDataManager.class);
return (ProjectDataManagerImpl)service;
}
public ProjectDataManagerImpl() {
myServices = new NotNullLazyValue<Map<Key<?>, List<ProjectDataService<?, ?>>>>() {
@NotNull
@Override
protected Map<Key<?>, List<ProjectDataService<?, ?>>> compute() {
Map<Key<?>, List<ProjectDataService<?, ?>>> result = ContainerUtilRt.newHashMap();
for (ProjectDataService<?, ?> service : ProjectDataService.EP_NAME.getExtensions()) {
List<ProjectDataService<?, ?>> services = result.get(service.getTargetDataKey());
if (services == null) {
result.put(service.getTargetDataKey(), services = ContainerUtilRt.newArrayList());
}
services.add(service);
}
for (List<ProjectDataService<?, ?>> services : result.values()) {
ExternalSystemApiUtil.orderAwareSort(services);
}
return result;
}
};
}
@SuppressWarnings("unchecked")
@Override
public void importData(@NotNull Collection<DataNode<?>> nodes,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
if (project.isDisposed()) return;
MultiMap<Key<?>, DataNode<?>> grouped = ExternalSystemApiUtil.recursiveGroup(nodes);
for (Key<?> key : myServices.getValue().keySet()) {
if (!grouped.containsKey(key)) {
grouped.put(key, Collections.emptyList());
}
}
final Collection<DataNode<?>> projects = grouped.get(ProjectKeys.PROJECT);
// only one project(can be multi-module project) expected for per single import
assert projects.size() == 1 || projects.isEmpty();
final DataNode<ProjectData> projectNode = (DataNode<ProjectData>)ContainerUtil.getFirstItem(projects);
final ProjectData projectData;
ProjectSystemId projectSystemId;
if (projectNode != null) {
projectData = projectNode.getData();
projectSystemId = projectNode.getData().getOwner();
ExternalProjectsDataStorage.getInstance(project).saveInclusionSettings(projectNode);
}
else {
projectData = null;
DataNode<ModuleData> aModuleNode = (DataNode<ModuleData>)ContainerUtil.getFirstItem(grouped.get(ProjectKeys.MODULE));
projectSystemId = aModuleNode != null ? aModuleNode.getData().getOwner() : null;
}
if (projectSystemId != null) {
ExternalSystemUtil.scheduleExternalViewStructureUpdate(project, projectSystemId);
}
List<Runnable> onSuccessImportTasks = ContainerUtil.newSmartList();
try {
final Set<Map.Entry<Key<?>, Collection<DataNode<?>>>> entries = grouped.entrySet();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.setIndeterminate(false);
}
final int size = entries.size();
int count = 0;
List<Runnable> postImportTasks = ContainerUtil.newSmartList();
for (Map.Entry<Key<?>, Collection<DataNode<?>>> entry : entries) {
if (indicator != null) {
String message = ExternalSystemBundle.message(
"progress.update.text", projectSystemId != null ? projectSystemId.getReadableName() : "",
"Refresh " + getReadableText(entry.getKey()));
indicator.setText(message);
indicator.setFraction((double)count++ / size);
}
doImportData(entry.getKey(), entry.getValue(), projectData, project, modelsProvider, postImportTasks, onSuccessImportTasks);
}
for (Runnable postImportTask : postImportTasks) {
postImportTask.run();
}
commit(modelsProvider, project, synchronous, "Imported data");
if (indicator != null) {
indicator.setIndeterminate(true);
}
project.getMessageBus().syncPublisher(ProjectDataImportListener.TOPIC)
.onImportFinished(projectData != null ? projectData.getLinkedExternalProjectPath() : null);
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
for (Runnable onSuccessImportTask : ContainerUtil.reverse(onSuccessImportTasks)) {
onSuccessImportTask.run();
}
}
@NotNull
private static String getReadableText(@NotNull Key key) {
StringBuilder buffer = new StringBuilder();
String s = key.toString();
for (int i = 0; i < s.length(); i++) {
char currChar = s.charAt(i);
if (Character.isUpperCase(currChar)) {
if (i != 0) {
buffer.append(' ');
}
buffer.append(StringUtil.toLowerCase(currChar));
}
else {
buffer.append(currChar);
}
}
return buffer.toString();
}
@Override
public <T> void importData(@NotNull Collection<DataNode<T>> nodes, @NotNull Project project, boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
dummy.addAll(nodes);
importData(dummy, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
@NotNull IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
Collection<DataNode<?>> dummy = ContainerUtil.newSmartList();
dummy.add(node);
importData(dummy, project, modelsProvider, synchronous);
}
@Override
public <T> void importData(@NotNull DataNode<T> node,
@NotNull Project project,
boolean synchronous) {
importData(node, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
@SuppressWarnings("unchecked")
private <T> void doImportData(@NotNull Key<T> key,
@NotNull Collection<DataNode<?>> nodes,
@Nullable final ProjectData projectData,
@NotNull final Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull final List<Runnable> postImportTasks,
@NotNull final List<Runnable> onSuccessImportTasks) {
if (project.isDisposed()) return;
if (project instanceof ProjectImpl) {
assert ((ProjectImpl)project).isComponentsCreated();
}
final List<DataNode<T>> toImport = ContainerUtil.newSmartList();
final List<DataNode<T>> toIgnore = ContainerUtil.newSmartList();
for (DataNode node : nodes) {
if (!key.equals(node.getKey())) continue;
if (node.isIgnored()) {
toIgnore.add(node);
}
else {
toImport.add(node);
}
}
ensureTheDataIsReadyToUse((Collection)toImport);
final List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
if (services == null) {
LOG.warn(String.format(
"Can't import data nodes '%s'. Reason: no service is registered for key %s. Available services for %s",
toImport, key, myServices.getValue().keySet()
));
}
else {
for (ProjectDataService<?, ?> service : services) {
final long importStartTime = System.currentTimeMillis();
((ProjectDataService)service).importData(toImport, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long importTimeInMs = (System.currentTimeMillis() - importStartTime);
LOG.debug(String.format("Service %s imported data in %d ms", service.getClass().getSimpleName(), importTimeInMs));
}
if (projectData != null) {
ensureTheDataIsReadyToUse((Collection)toIgnore);
final long removeStartTime = System.currentTimeMillis();
final Computable<Collection<?>> orphanIdeDataComputable =
((ProjectDataService)service).computeOrphanData(toImport, projectData, project, modelsProvider);
((ProjectDataService)service).removeData(orphanIdeDataComputable, toIgnore, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long removeTimeInMs = (System.currentTimeMillis() - removeStartTime);
LOG.debug(String.format("Service %s computed and removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
}
}
if (services != null && projectData != null) {
postImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).postProcess(toImport, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
onSuccessImportTasks.add(() -> {
for (ProjectDataService<?, ?> service : services) {
if (service instanceof AbstractProjectDataService) {
final long taskStartTime = System.currentTimeMillis();
((AbstractProjectDataService)service).onSuccessImport(project);
if (LOG.isDebugEnabled()) {
final long taskTimeInMs = (System.currentTimeMillis() - taskStartTime);
LOG.debug(String.format("Service %s run post import task in %d ms", service.getClass().getSimpleName(), taskTimeInMs));
}
}
}
});
}
}
@Override
public void ensureTheDataIsReadyToUse(@Nullable DataNode dataNode) {
if (dataNode == null) return;
if (Boolean.TRUE.equals(dataNode.getUserData(DATA_READY))) return;
ExternalSystemApiUtil.visit(dataNode, dataNode1 -> {
prepareDataToUse(dataNode1);
dataNode1.putUserData(DATA_READY, Boolean.TRUE);
});
}
@SuppressWarnings("unchecked")
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Project project,
@NotNull final IdeModifiableModelsProvider modelsProvider,
boolean synchronous) {
try {
List<ProjectDataService<?, ?>> services = myServices.getValue().get(key);
for (ProjectDataService service : services) {
final long removeStartTime = System.currentTimeMillis();
service.removeData(new Computable.PredefinedValueComputable<Collection>(toRemove), toIgnore, projectData, project, modelsProvider);
if (LOG.isDebugEnabled()) {
final long removeTimeInMs = System.currentTimeMillis() - removeStartTime;
LOG.debug(String.format("Service %s removed data in %d ms", service.getClass().getSimpleName(), removeTimeInMs));
}
}
commit(modelsProvider, project, synchronous, "Removed data");
}
catch (Throwable t) {
dispose(modelsProvider, project, synchronous);
ExceptionUtil.rethrowAllAsUnchecked(t);
}
}
public <E, I> void removeData(@NotNull Key<E> key,
@NotNull Collection<I> toRemove,
@NotNull final Collection<DataNode<E>> toIgnore,
@NotNull final ProjectData projectData,
@NotNull Project project,
boolean synchronous) {
removeData(key, toRemove, toIgnore, projectData, project, new IdeModifiableModelsProviderImpl(project), synchronous);
}
public void updateExternalProjectData(@NotNull Project project, @NotNull ExternalProjectInfo externalProjectInfo) {
if (!project.isDisposed()) {
ExternalProjectsManagerImpl.getInstance(project).updateExternalProjectData(externalProjectInfo);
}
}
@Nullable
@Override
public ExternalProjectInfo getExternalProjectData(@NotNull Project project,
@NotNull ProjectSystemId projectSystemId,
@NotNull String externalProjectPath) {
return !project.isDisposed() ? ExternalProjectsDataStorage.getInstance(project).get(projectSystemId, externalProjectPath) : null;
}
@NotNull
@Override
public Collection<ExternalProjectInfo> getExternalProjectsData(@NotNull Project project, @NotNull ProjectSystemId projectSystemId) {
if (!project.isDisposed()) {
return ExternalProjectsDataStorage.getInstance(project).list(projectSystemId);
}
else {
return ContainerUtil.emptyList();
}
}
private void ensureTheDataIsReadyToUse(@NotNull Collection<DataNode<?>> nodes) {
for (DataNode<?> node : nodes) {
ensureTheDataIsReadyToUse(node);
}
}
private void prepareDataToUse(@NotNull DataNode dataNode) {
final Map<Key<?>, List<ProjectDataService<?, ?>>> servicesByKey = myServices.getValue();
List<ProjectDataService<?, ?>> services = servicesByKey.get(dataNode.getKey());
if (services != null) {
try {
dataNode.prepareData(map2Array(services, ClassLoader.class, service -> service.getClass().getClassLoader()));
}
catch (Exception e) {
LOG.debug(e);
dataNode.clear(true);
}
}
}
private static void commit(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous,
@NotNull final String commitDesc) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
final long startTime = System.currentTimeMillis();
modelsProvider.commit();
final long timeInMs = System.currentTimeMillis() - startTime;
LOG.debug(String.format("%s committed in %d ms", commitDesc, timeInMs));
}
});
}
private static void dispose(@NotNull final IdeModifiableModelsProvider modelsProvider,
@NotNull Project project,
boolean synchronous) {
ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) {
@Override
public void execute() {
modelsProvider.dispose();
}
});
}
}
@@ -13,11 +13,7 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl;
import com.intellij.openapi.externalSystem.service.project.IdeUIModifiableModelsProvider;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.*;
import com.intellij.openapi.externalSystem.service.settings.AbstractImportFromExternalSystemControl;
import com.intellij.openapi.externalSystem.service.ui.ExternalProjectDataSelectorDialog;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
@@ -71,6 +67,15 @@ public abstract class AbstractExternalProjectImportBuilder<C extends AbstractImp
private DataNode<ProjectData> myExternalProjectNode;
/**
* @deprecated use {@link AbstractExternalProjectImportBuilder#AbstractExternalProjectImportBuilder(ProjectDataManager, AbstractImportFromExternalSystemControl, ProjectSystemId)}
*/
public AbstractExternalProjectImportBuilder(@NotNull com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager projectDataManager,
@NotNull C control,
@NotNull ProjectSystemId externalSystemId) {
this((ProjectDataManager)projectDataManager, control, externalSystemId);
}
public AbstractExternalProjectImportBuilder(@NotNull ProjectDataManager projectDataManager,
@NotNull C control,
@NotNull ProjectSystemId externalSystemId)
@@ -16,7 +16,7 @@
package com.intellij.openapi.externalSystem.service.task.ui;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.view.ExternalProjectsViewImpl;
import com.intellij.openapi.project.DumbAware;
@@ -45,7 +45,7 @@ public abstract class AbstractExternalSystemToolWindowFactory implements ToolWin
toolWindow.setTitle(myExternalSystemId.getReadableName());
ContentManager contentManager = toolWindow.getContentManager();
final ExternalProjectsViewImpl projectsView = new ExternalProjectsViewImpl(project, (ToolWindowEx)toolWindow, myExternalSystemId);
ExternalProjectsManager.getInstance(project).registerView(projectsView);
ExternalProjectsManagerImpl.getInstance(project).registerView(projectsView);
ContentImpl tasksContent = new ContentImpl(projectsView, ExternalSystemBundle.message("tool.window.title.projects"), true);
contentManager.addContent(tasksContent);
}
@@ -27,9 +27,10 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.ExternalProjectsStateProvider;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.Phase;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.TaskActivationState;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
@@ -67,8 +68,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import static com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.ExternalProjectsStateProvider;
import static com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager.getInstance;
import static com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl.getInstance;
import static com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator.TaskActivationEntry;
/**
@@ -31,7 +31,8 @@ import com.intellij.openapi.externalSystem.model.project.Identifiable;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ModuleDependencyData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
@@ -123,7 +124,7 @@ public class ExternalProjectDataSelectorDialog extends DialogWrapper {
}
private void init(@NotNull ExternalProjectInfo projectInfo) {
ProjectDataManager.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure());
ProjectDataManagerImpl.getInstance().ensureTheDataIsReadyToUse(projectInfo.getExternalProjectStructure());
myProjectInfo = projectInfo;
myExternalSystemUiAware = ExternalSystemUiUtil.getUiAware(myProjectInfo.getProjectSystemId());
myTree = createTree();
@@ -37,28 +37,22 @@ public class ExternalToolWindowManager {
settings.subscribe(new ExternalSystemSettingsListenerAdapter() {
@Override
public void onProjectsLinked(@NotNull Collection linked) {
if (settings.getLinkedProjectsSettings().size() != 1) {
return;
}
ToolWindow toolWindow = getToolWindow(project, manager.getSystemId());
if (toolWindow != null) {
toolWindow.setAvailable(true, null);
}
else {
StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() {
@Override
public void run() {
if (project.isDisposed()) return;
StartupManager.getInstance(project).runWhenProjectIsInitialized((DumbAwareRunnable)() -> {
if (project.isDisposed()) return;
ExternalSystemUtil.ensureToolWindowInitialized(project, manager.getSystemId());
ToolWindowManager.getInstance(project).invokeLater(() -> {
if (project.isDisposed()) return;
ToolWindow toolWindow1 = getToolWindow(project, manager.getSystemId());
if (toolWindow1 != null) {
toolWindow1.setAvailable(true, null);
}
});
}
ExternalSystemUtil.ensureToolWindowInitialized(project, manager.getSystemId());
ToolWindowManager.getInstance(project).invokeLater(() -> {
if (project.isDisposed()) return;
ToolWindow toolWindow1 = getToolWindow(project, manager.getSystemId());
if (toolWindow1 != null) {
toolWindow1.setAvailable(true, null);
}
});
});
}
}
@@ -19,8 +19,8 @@ import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.view.ExternalProjectsStructure;
import com.intellij.openapi.externalSystem.view.ExternalProjectsView;
import com.intellij.openapi.externalSystem.view.ExternalProjectsViewAdapter;
@@ -32,7 +32,6 @@ import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.treeStructure.SimpleNode;
import com.intellij.ui.treeStructure.SimpleNodeVisitor;
import com.intellij.ui.treeStructure.SimpleTree;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.tree.TreeUtil;
@@ -81,7 +80,7 @@ public class SelectExternalSystemNodeDialog extends DialogWrapper {
myTree = new SimpleTree();
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
final ExternalProjectsView projectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(systemId);
final ExternalProjectsView projectsView = ExternalProjectsManagerImpl.getInstance(project).getExternalProjectsView(systemId);
if(projectsView != null) {
final ExternalProjectsStructure treeStructure = new ExternalProjectsStructure(project, myTree) {
@SuppressWarnings("unchecked")
@@ -52,10 +52,11 @@ import com.intellij.openapi.externalSystem.service.internal.ExternalSystemResolv
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager;
import com.intellij.openapi.externalSystem.service.notification.NotificationSource;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ContentRootDataService;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.task.TaskCallback;
@@ -405,7 +406,7 @@ public class ExternalSystemUtil {
.clearNotifications(null, NotificationSource.PROJECT_SYNC, externalSystemId);
}
final ExternalSystemTaskActivator externalSystemTaskActivator = ExternalProjectsManager.getInstance(project).getTaskActivator();
final ExternalSystemTaskActivator externalSystemTaskActivator = ExternalProjectsManagerImpl.getInstance(project).getTaskActivator();
if (!isPreviewMode && !externalSystemTaskActivator.runTasks(externalProjectPath, ExternalSystemTaskActivator.Phase.BEFORE_SYNC)) {
return;
}
@@ -785,7 +786,7 @@ public class ExternalSystemUtil {
}
public static void scheduleExternalViewStructureUpdate(@NotNull final Project project, @NotNull final ProjectSystemId systemId) {
ExternalProjectsView externalProjectsView = ExternalProjectsManager.getInstance(project).getExternalProjectsView(systemId);
ExternalProjectsView externalProjectsView = ExternalProjectsManagerImpl.getInstance(project).getExternalProjectsView(systemId);
if (externalProjectsView instanceof ExternalProjectsViewImpl) {
((ExternalProjectsViewImpl)externalProjectsView).scheduleStructureUpdate();
}
@@ -799,7 +800,7 @@ public class ExternalSystemUtil {
ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectSettings(externalProjectPath);
if (linkedProjectSettings == null) return null;
return ProjectDataManager.getInstance().getExternalProjectData(
return ProjectDataManagerImpl.getInstance().getExternalProjectData(
project, projectSystemId, linkedProjectSettings.getExternalProjectPath());
}
@@ -31,10 +31,10 @@ import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecution
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.model.task.TaskData;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemTaskLocation;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemShortcutsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalSystemTaskActivator;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
@@ -77,7 +77,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D
@NotNull
private final Project myProject;
@NotNull
private final ExternalProjectsManager myProjectsManager;
private final ExternalProjectsManagerImpl myProjectsManager;
@NotNull
private final ToolWindowEx myToolWindow;
@NotNull
@@ -101,7 +101,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D
myToolWindow = toolWindow;
myExternalSystemId = externalSystemId;
myUiAware = ExternalSystemUiUtil.getUiAware(externalSystemId);
myProjectsManager = ExternalProjectsManager.getInstance(myProject);
myProjectsManager = ExternalProjectsManagerImpl.getInstance(myProject);
String toolWindowId =
toolWindow instanceof ToolWindowImpl ? ((ToolWindowImpl)toolWindow).getId() : myExternalSystemId.getReadableName();
@@ -527,7 +527,7 @@ public class ExternalProjectsViewImpl extends SimpleToolWindowPanel implements D
}
private <T extends ExternalSystemNode> List<T> getSelectedNodes(Class<T> aClass) {
return myStructure != null ? myStructure.getSelectedNodes(myTree, aClass) : ContainerUtil.<T>emptyList();
return myStructure != null ? myStructure.getSelectedNodes(myTree, aClass) : ContainerUtil.emptyList();
}
private List<ProjectNode> getSelectedProjectNodes() {
@@ -14,19 +14,17 @@
* limitations under the License.
*/
package com.intellij.openapi.externalSystem.test
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.extensions.ExtensionPoint
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.externalSystem.ExternalSystemManager
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager
import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
import com.intellij.openapi.util.io.FileUtil
import com.intellij.testFramework.PlatformTestCase
import com.intellij.testFramework.SkipInHeadlessEnvironment
import com.intellij.testFramework.UsefulTestCase
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture
@@ -37,6 +35,7 @@ import org.jetbrains.annotations.Nullable
import java.lang.reflect.Field
import java.lang.reflect.Modifier
/**
* @author Denis Zhdanov
* @since 8/7/13 2:04 PM
@@ -15,8 +15,6 @@
*/
package com.intellij.openapi.externalSystem.test;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
@@ -26,7 +24,8 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
@@ -45,14 +44,12 @@ import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactManager;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.util.BooleanFunction;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
@@ -162,7 +159,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
List<String> actual = new ArrayList<>();
for (ContentEntry contentRoot : contentRoots) {
for (SourceFolder f : contentRoot.getSourceFolders(rootType)) {
rootUrl = rootUrl == null ? VirtualFileManager.extractPath(contentRoot.getUrl()) : VirtualFileManager.extractPath(rootUrl);
rootUrl = VirtualFileManager.extractPath(rootUrl == null ? contentRoot.getUrl() : rootUrl);
String folderUrl = VirtualFileManager.extractPath(f.getUrl());
if (folderUrl.startsWith(rootUrl)) {
int length = rootUrl.length() + 1;
@@ -215,7 +212,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
}
private static String getAbsolutePath(String path) {
path = VfsUtil.urlToPath(path);
path = VfsUtilCore.urlToPath(path);
path = PathUtil.getCanonicalPath(path);
return FileUtil.toSystemIndependentName(path);
}
@@ -364,28 +361,12 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
protected void assertArtifacts(String... expectedNames) {
final List<String> actualNames = ContainerUtil.map(
ArtifactManager.getInstance(myProject).getAllArtifactsIncludingInvalid(), new Function<Artifact, String>() {
@Override
public String fun(Artifact artifact) {
return artifact.getName();
}
});
ArtifactManager.getInstance(myProject).getAllArtifactsIncludingInvalid(),
(Function<Artifact, String>)artifact -> artifact.getName());
assertUnorderedElementsAreEqual(actualNames, expectedNames);
}
protected Module getModule(final String name) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
assertNotNull("Module " + name + " not found", m);
return m;
}
finally {
accessToken.finish();
}
}
private ContentEntry getContentRoot(String moduleName) {
ContentEntry[] ee = getContentRoots(moduleName);
List<String> roots = new ArrayList<>();
@@ -415,7 +396,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
}
protected void ignoreData(BooleanFunction<DataNode<?>> booleanFunction, final boolean ignored) {
final ExternalProjectInfo externalProjectInfo = ProjectDataManager.getInstance().getExternalProjectData(
final ExternalProjectInfo externalProjectInfo = ProjectDataManagerImpl.getInstance().getExternalProjectData(
myProject, getExternalSystemId(), getCurrentExternalProjectSettings().getExternalProjectPath());
assertNotNull(externalProjectInfo);
@@ -462,9 +462,13 @@ public abstract class ExternalSystemTestCase extends UsefulTestCase {
}
protected Module getModule(final String name) {
return getModule(myProject, name);
}
protected Module getModule(Project project, String name) {
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
try {
Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
Module m = ModuleManager.getInstance(project).findModuleByName(name);
assertNotNull("Module " + name + " not found", m);
return m;
}
@@ -152,6 +152,13 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
preferredScrollPaneSize.width = Math.max(myTextFieldPanel.getWidth(), preferredScrollPaneSize.width);
// in 'focus follows mouse' mode, to avoid focus escaping to editor, don't reduce popup size when list size is reduced
if (myDropdownPopup != null && !isCloseByFocusLost()) {
Dimension currentSize = myDropdownPopup.getSize();
if (preferredScrollPaneSize.width < currentSize.width) preferredScrollPaneSize.width = currentSize.width;
if (preferredScrollPaneSize.height < currentSize.height) preferredScrollPaneSize.height = currentSize.height;
}
Rectangle preferredBounds = new Rectangle(bounds.x, bounds.y, preferredScrollPaneSize.width, preferredScrollPaneSize.height);
Rectangle original = new Rectangle(preferredBounds);
@@ -190,13 +197,7 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
}
else {
myDropdownPopup.setLocation(preferredBounds.getLocation());
// in 'focus follows mouse' mode, to avoid focus escaping to editor, don't reduce popup size when list size is reduced
final Dimension currentSize = myDropdownPopup.getSize();
if (UISettings.getInstance().getHideNavigationOnFocusLoss() ||
preferredBounds.width > currentSize.width || preferredBounds.height > currentSize.height) {
myDropdownPopup.setSize(preferredBounds.getSize());
}
myDropdownPopup.setSize(preferredBounds.getSize());
}
}
@@ -35,6 +35,7 @@ import com.intellij.ui.FontComboBox;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -198,9 +199,11 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
settings.setAllowMergeButtons(myComponent.myAllowMergeButtons.isSelected());
update |= settings.getCycleScrolling() != myComponent.myCycleScrollingCheckBox.isSelected();
settings.setCycleScrolling(myComponent.myCycleScrollingCheckBox.isSelected());
boolean shouldResetLafFonts = false;
if (settings.getOverrideLafFonts() != myComponent.myOverrideLAFFonts.isSelected()) {
shouldUpdateUI = true;
update = true;
shouldResetLafFonts = !myComponent.myOverrideLAFFonts.isSelected();
}
settings.setOverrideLafFonts(myComponent.myOverrideLAFFonts.isSelected());
settings.setMoveMouseOnDefaultButton(myComponent.myMoveMouseOnDefaultButtonCheckBox.isSelected());
@@ -253,6 +256,14 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
if (shouldUpdateUI) {
lafManager.updateUI();
if (shouldResetLafFonts) {
int defSize = JBUI.Fonts.label().getSize();
settings.setFontSize(defSize);
myComponent.myFontSizeCombo.getModel().setSelectedItem(String.valueOf(defSize));
String defName = JBUI.Fonts.label().getFontName();
settings.setFontFace(defName);
myComponent.myFontCombo.setFontName(defName);
}
}
if (WindowManagerEx.getInstanceEx().isAlphaModeSupported()) {
@@ -1314,7 +1314,7 @@ public class AbstractPopup implements JBPopup {
}
}
size = computeWindowSize(size);
size.height += getAdComponentHeight();
final Window window = getContentWindow(myContent);
if (window != null) {
@@ -1590,27 +1590,27 @@ public class AbstractPopup implements JBPopup {
}
else {
if (adjustByContent) {
toSet = computeWindowSize(toSet);
toSet.height += getAdComponentHeight();
}
updateMaskAndAlpha(setSize(myContent, toSet));
}
}
private Dimension computeWindowSize(Dimension size) {
if (myAdComponent != null && myAdComponent.isShowing()) {
size.height += myAdComponent.getPreferredSize().height + 1;
}
return size;
private int getAdComponentHeight() {
return myAdComponent != null && myAdComponent.isShowing() ? myAdComponent.getPreferredSize().height + 1 : 0;
}
@Override
public Dimension getSize() {
if (myPopup != null) {
final Window popupWindow = getContentWindow(myContent);
return (popupWindow == null) ? myForcedSize : popupWindow.getSize();
} else {
return myForcedSize;
if (popupWindow != null) {
Dimension size = popupWindow.getSize();
size.height -= getAdComponentHeight();
return size;
}
}
return myForcedSize;
}
@Override
@@ -19,8 +19,11 @@
<externalSystemNotificationExtension implementation="com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationExtensionImpl" />
<!--Project structure management services-->
<applicationService serviceImplementation="com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager"/>
<projectService serviceImplementation="com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager" order="first"/>
<applicationService serviceInterface="com.intellij.openapi.externalSystem.service.project.ProjectDataManager"
serviceImplementation="com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManagerImpl"/>
<projectService serviceInterface="com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager"
serviceImplementation="com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl"
order="first"/>
<projectService serviceImplementation="com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsDataStorage"/>
<externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.ProjectDataServiceImpl"/>
<externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.LibraryDataService"/>
@@ -291,7 +291,7 @@ public class GeneralCommandLineTest {
if (argument.trim().isEmpty()) continue; // would report "ECHO is on"
GeneralCommandLine commandLine = createCommandLine(ExecUtil.getWindowsShellName(), "/D", "/C", "echo", argument);
String output = execAndGetOutput(commandLine);
assertEquals(commandLine.getPreparedCommandLine(), argument + "\n", output);
assertEquals(commandLine.getPreparedCommandLine(), filterExpectedOutput(argument) + "\n", output);
}
}
@@ -305,7 +305,7 @@ public class GeneralCommandLineTest {
for (String argument : ARGUMENTS) {
GeneralCommandLine commandLine = createCommandLine(cygwinPrintf.getPath(), "[%s]\\\\n", argument);
String output = execAndGetOutput(commandLine);
assertEquals(commandLine.getPreparedCommandLine(), filterExpectedOutput("[" + argument + "]\n"), output);
assertEquals(commandLine.getPreparedCommandLine(), filterExpectedOutput("[" + argument + "]") + "\n", output);
}
}
@@ -32,7 +32,7 @@ public class PtyCommandLineTest extends GeneralCommandLineTest {
@NotNull
@Override
protected String filterExpectedOutput(@NotNull String output) {
if (SystemInfo.isWindows) output = expandTabs(output, 8);
if (SystemInfo.isWindows) output = StringUtil.trimTrailing(expandTabs(output, 8));
return output;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* 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.
@@ -1560,6 +1560,20 @@ public class ContainerUtil extends ContainerUtilRt {
return result.isEmpty() ? ContainerUtil.<T>emptyList() : result;
}
@NotNull
@Contract(pure=true)
public static <E extends Enum<E>> EnumSet<E> intersection(@NotNull EnumSet<E> collection1, @NotNull EnumSet<E> collection2) {
if (collection1.isEmpty()) return collection1;
if (collection2.isEmpty()) return collection2;
EnumSet<E> smallerCollection = collection1.size() < collection2.size() ? collection1 : collection2;
EnumSet<E> biggerCollection = collection1.size() < collection2.size() ? collection2 : collection1;
EnumSet<E> result = EnumSet.copyOf(smallerCollection);
result.removeAll(EnumSet.complementOf(biggerCollection));
return result;
}
@Nullable
@Contract(pure=true)
public static <T> T getFirstItem(@Nullable Collection<T> items) {
@@ -152,6 +152,8 @@ public class JBUI {
static {
setUserScaleFactor(UIUtil.isJreHiDPIEnabled() ? 1f : SYSTEM_SCALE_FACTOR);
LOG.info("System scale factor: " + SYSTEM_SCALE_FACTOR + " (" +
(UIUtil.isJreHiDPIEnabled() ? "JRE-managed" : "IDE-managed") + " HiDPI)");
}
/**
@@ -315,7 +317,7 @@ public class JBUI {
private static void setUserScaleFactorProperty(float scale) {
PCS.firePropertyChange(USER_SCALE_FACTOR_PROPERTY, userScaleFactor, userScaleFactor = scale);
LOG.info("UI scale factor: " + userScaleFactor);
LOG.info("User scale factor: " + userScaleFactor);
}
/**
@@ -0,0 +1,54 @@
/*
* 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.vcs.log;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Enables showing diff between revisions and comparing file or directory state between a revision and a local version in log-based file history.
* Methods of this class could be called from EDT, so it should deal with it appropriately by starting a background task for long operations,
* eg for loading revisions content.
*/
public interface VcsLogDiffHandler {
/**
* Show diff between (the after-state of) two revisions in the specified files or directories.
*
* @param root repository root.
* @param leftPath path to the file on the left, null means file is missing in this revision.
* @param leftHash hash of the revision on the left.
* @param rightPath path to the file on the right, null means file is missing in this revision.
* @param rightHash hash of the revision on the right.
*/
void showDiff(@NotNull VirtualFile root,
@Nullable FilePath leftPath, @NotNull Hash leftHash,
@Nullable FilePath rightPath, @NotNull Hash rightHash);
/**
* Show diff between (the after-state of) specified revision and local version for the specified file or directory.
*
* @param root repository root.
* @param revisionPath path to the file in the specified revision, null means file is not present in the revision.
* @param hash hash of the revision.
* @param localPath local path to the file.
*/
void showDiffWithLocal(@NotNull VirtualFile root,
@Nullable FilePath revisionPath,
@NotNull Hash hash, @NotNull FilePath localPath);
}
@@ -147,6 +147,14 @@ public interface VcsLogProvider {
@Nullable
String getCurrentBranch(@NotNull VirtualFile root);
/**
* Returns {@link VcsLogDiffHandler} for this provider in order to support comparing commits and with local version from log-based file history.
*
* @return diff handler or null if unsupported.
*/
@Nullable
VcsLogDiffHandler getDiffHandler();
interface Requirements {
/**
@@ -22,6 +22,7 @@ import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
@@ -35,6 +36,7 @@ import com.intellij.vcs.log.ui.frame.DetailsPanel;
import com.intellij.vcs.log.ui.table.VcsLogGraphTable;
import com.intellij.vcs.log.util.VcsLogUiUtil;
import com.intellij.vcs.log.visible.VisiblePack;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,6 +53,7 @@ public class FileHistoryPanel extends JPanel implements DataProvider, Disposable
@NotNull private final JBSplitter myDetailsSplitter;
@NotNull private final FilePath myFilePath;
@NotNull private final FileHistoryUi myUi;
@NotNull private final VirtualFile myRoot;
public FileHistoryPanel(@NotNull FileHistoryUi ui,
@NotNull VcsLogData logData,
@@ -58,6 +61,7 @@ public class FileHistoryPanel extends JPanel implements DataProvider, Disposable
@NotNull FilePath filePath) {
myUi = ui;
myFilePath = filePath;
myRoot = notNull(VcsUtil.getVcsRootFor(logData.getProject(), myFilePath));
myGraphTable = new VcsLogGraphTable(myUi, logData, visiblePack) {
@Override
protected boolean isSpeedSearchEnabled() {
@@ -150,6 +154,9 @@ public class FileHistoryPanel extends JPanel implements DataProvider, Disposable
else if (VcsDataKeys.VCS_NON_LOCAL_HISTORY_SESSION.is(dataId)) {
return false;
}
else if (VcsLogInternalDataKeys.LOG_DIFF_HANDLER.is(dataId)) {
return myUi.getLogData().getLogProvider(myRoot).getDiffHandler();
}
return null;
}
@@ -130,6 +130,21 @@ public class FileHistoryUi extends AbstractVcsLogUi {
return null;
}
@Nullable
public FilePath getPath(@NotNull VcsFullCommitDetails details) {
if (myPath.isDirectory()) return myPath;
List<Change> changes = collectRelevantChanges(details);
for (Change change : changes) {
ContentRevision revision = change.getAfterRevision();
if (revision != null) {
return revision.getFile();
}
}
return null;// file was deleted
}
@NotNull
public List<Change> collectRelevantChanges(@NotNull VcsFullCommitDetails details) {
Set<FilePath> fileNames = getFileNames(details);
@@ -16,6 +16,7 @@
package com.intellij.vcs.log.ui;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.vcs.log.VcsLogDiffHandler;
import com.intellij.vcs.log.history.FileHistoryUi;
import com.intellij.vcs.log.impl.VcsLogManager;
import com.intellij.vcs.log.impl.VcsLogUiProperties;
@@ -24,4 +25,5 @@ public class VcsLogInternalDataKeys {
public static final DataKey<VcsLogManager> LOG_MANAGER = DataKey.create("Vcs.Log.Manager");
public static final DataKey<VcsLogUiProperties> LOG_UI_PROPERTIES = DataKey.create("Vcs.Log.Ui.Properties");
public static final DataKey<FileHistoryUi> FILE_HISTORY_UI = DataKey.create("Vcs.FileHistory.Ui");
public static final DataKey<VcsLogDiffHandler> LOG_DIFF_HANDLER = DataKey.create("Vcs.Log.Diff.Handler");
}
@@ -18,22 +18,25 @@ package com.intellij.vcs.log.ui.actions.history;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction;
import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffContext;
import com.intellij.openapi.vcs.history.DiffFromHistoryHandler;
import com.intellij.openapi.vcs.history.StandardDiffFromHistoryHandler;
import com.intellij.openapi.vcs.history.VcsDiffUtil;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.util.ObjectUtils;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.CommitId;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.data.LoadingDetails;
import com.intellij.vcs.log.VcsLogDiffHandler;
import com.intellij.vcs.log.history.FileHistoryUi;
import com.intellij.vcs.log.impl.VcsLogUtil;
import com.intellij.vcs.log.ui.VcsLogInternalDataKeys;
@@ -43,12 +46,13 @@ import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.List;
import static com.intellij.util.ObjectUtils.notNull;
public class CompareRevisionsFromHistoryAction extends AnAction implements DumbAware {
private static final String COMPARE_TEXT = "Compare";
private static final String COMPARE_DESCRIPTION = "Compare selected versions";
private static final String DIFF_TEXT = "Show Diff";
private static final String DIFF_DESCRIPTION = "Show diff with previous version";
@NotNull private final DiffFromHistoryHandler myDiffHandler = new StandardDiffFromHistoryHandler();
public void update(@NotNull AnActionEvent e) {
Project project = e.getProject();
@@ -61,31 +65,20 @@ public class CompareRevisionsFromHistoryAction extends AnAction implements DumbA
e.getPresentation().setVisible(true);
List<VcsFullCommitDetails> details = ui.getVcsLog().getSelectedDetails();
List<CommitId> commits = ui.getVcsLog().getSelectedCommits();
if (e.getInputEvent() instanceof KeyEvent) {
e.getPresentation().setEnabled(true);
}
else {
if (details.size() == 2) {
VcsFullCommitDetails detail0 = details.get(0);
VcsFullCommitDetails detail1 = details.get(1);
if (detail0 != null && !(detail0 instanceof LoadingDetails) &&
detail1 != null && !(detail1 instanceof LoadingDetails)) {
VcsFileRevision newestRevision = ui.createRevision(detail0);
VcsFileRevision olderRevision = ui.createRevision(detail1);
e.getPresentation().setEnabled(newestRevision != null && olderRevision != null && !filePath.isDirectory());
}
else {
e.getPresentation().setEnabled(!filePath.isDirectory());
}
if (commits.size() == 2) {
e.getPresentation().setEnabled(e.getData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER) != null);
}
else {
e.getPresentation().setEnabled(details.size() == 1);
e.getPresentation().setEnabled(commits.size() == 1);
}
}
if (details.size() == 2) {
if (commits.size() == 2) {
e.getPresentation().setText(COMPARE_TEXT);
e.getPresentation().setDescription(COMPARE_DESCRIPTION);
}
@@ -109,24 +102,25 @@ public class CompareRevisionsFromHistoryAction extends AnAction implements DumbA
VcsLogUtil.triggerUsage(e);
List<CommitId> commits = ui.getVcsLog().getSelectedCommits();
if (filePath.isDirectory()) {
if (commits.size() != 1) return;
}
else {
if (commits.size() != 1 && commits.size() != 2) return;
}
if (commits.size() != 1 && commits.size() != 2) return;
VcsLogDiffHandler handler = e.getData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER);
// this check is needed here since we may come on key event without performing proper checks
if (commits.size() == 2 && handler == null) return;
List<Integer> commitIds = ContainerUtil.map(commits, c -> ui.getLogData().getCommitIndex(c.getHash(), c.getRoot()));
ui.getLogData().getCommitDetailsGetter().loadCommitsData(commitIds, details -> {
if (details.size() == 2) {
VcsFileRevision newestRevision = ui.createRevision(details.get(0));
VcsFileRevision olderRevision = ui.createRevision(details.get(1));
if (olderRevision != null && newestRevision != null) {
myDiffHandler.showDiffForTwo(project, filePath, olderRevision, newestRevision);
}
// we only need details here to get file names for each revision
// in order to fix this FileNamesData should be refactored
// so that it could return a single file path for each revision
VcsFullCommitDetails newestDetail = details.get(0);
VcsFullCommitDetails olderDetail = details.get(1);
notNull(handler).showDiff(olderDetail.getRoot(), ui.getPath(olderDetail), olderDetail.getId(),
ui.getPath(newestDetail), newestDetail.getId());
}
else if (details.size() == 1) {
VcsFullCommitDetails detail = ObjectUtils.notNull(ContainerUtil.getFirstItem(details));
VcsFullCommitDetails detail = notNull(ContainerUtil.getFirstItem(details));
List<Change> changes = ui.collectRelevantChanges(detail);
if (filePath.isDirectory()) {
VcsDiffUtil.showChangesDialog(project, "Changes in " + detail.getId().toShortString() + " for " + filePath.getName(),
@@ -20,33 +20,21 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.history.CurrentRevision;
import com.intellij.openapi.vcs.history.StandardDiffFromHistoryHandler;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLogDiffHandler;
import com.intellij.vcs.log.history.FileHistoryUi;
import com.intellij.vcs.log.ui.VcsLogInternalDataKeys;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.util.ObjectUtils.notNull;
public class ShowDiffWithLocalFromHistoryAction extends FileHistorySingleCommitAction {
@Override
protected boolean isEnabled(@NotNull FileHistoryUi ui, @Nullable VcsFullCommitDetails detail, @NotNull AnActionEvent e) {
FilePath filePath = e.getData(VcsDataKeys.FILE_PATH);
if (filePath == null || filePath.isDirectory() || filePath.getVirtualFile() == null) {
// currently not working for directories, to be fixed later
return false;
}
VcsLogDiffHandler handler = e.getData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER);
if (detail != null) {
VcsFileRevision fileRevision = ui.createRevision(detail);
if (fileRevision == null) return false;
}
return true;
return filePath != null && filePath.getVirtualFile() != null && handler != null;
}
@Override
@@ -57,11 +45,8 @@ public class ShowDiffWithLocalFromHistoryAction extends FileHistorySingleCommitA
if (ChangeListManager.getInstance(project).isFreezedWithNotification(null)) return;
FilePath path = e.getRequiredData(VcsDataKeys.FILE_PATH);
VcsFileRevision revision = ui.createRevision(detail);
VcsLogDiffHandler handler = e.getRequiredData(VcsLogInternalDataKeys.LOG_DIFF_HANDLER);
if (revision != null) {
StandardDiffFromHistoryHandler handler = new StandardDiffFromHistoryHandler();
handler.showDiffForTwo(project, path, revision, new CurrentRevision(notNull(path.getVirtualFile()), VcsRevisionNumber.NULL));
}
handler.showDiffWithLocal(detail.getRoot(), ui.getPath(detail), detail.getId(), path);
}
}
@@ -234,6 +234,12 @@ public class TestVcsLogProvider implements VcsLogProvider {
return null;
}
@Nullable
@Override
public VcsLogDiffHandler getDiffHandler() {
return null;
}
private static class MockRefManager implements VcsLogRefManager {
public static final Comparator<VcsRef> FAKE_COMPARATOR = (o1, o2) -> 0;
@@ -0,0 +1,203 @@
/*
* 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 git4idea.log;
import com.intellij.diff.DiffContentFactoryEx;
import com.intellij.diff.DiffManager;
import com.intellij.diff.contents.DiffContent;
import com.intellij.diff.contents.EmptyContent;
import com.intellij.diff.requests.DiffRequest;
import com.intellij.diff.requests.SimpleDiffRequest;
import com.intellij.diff.util.DiffUserDataKeysEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.history.VcsDiffUtil;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogDiffHandler;
import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitRevisionNumber;
import git4idea.changes.GitChangeUtils;
import git4idea.util.GitFileUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Collections;
import static com.intellij.diff.DiffRequestFactoryImpl.getTitle;
import static com.intellij.util.ObjectUtils.chooseNotNull;
public class GitLogDiffHandler implements VcsLogDiffHandler {
private static final Logger LOG = Logger.getInstance(GitLogDiffHandler.class);
@NotNull private final Project myProject;
@NotNull private final DiffContentFactoryEx myDiffContentFactory;
public GitLogDiffHandler(@NotNull Project project) {
myProject = project;
myDiffContentFactory = DiffContentFactoryEx.getInstanceEx();
}
@Override
public void showDiff(@NotNull VirtualFile root,
@Nullable FilePath leftPath,
@NotNull Hash leftHash,
@Nullable FilePath rightPath,
@NotNull Hash rightHash) {
if (leftPath == null && rightPath == null) return;
if (chooseNotNull(leftPath, rightPath).isDirectory()) {
showDiffForDirectory(root, chooseNotNull(leftPath, rightPath), leftHash, rightHash);
}
else {
loadDiffAndShow(new ThrowableComputable<DiffRequest, VcsException>() {
@Override
public DiffRequest compute() throws VcsException {
DiffContent leftDiffContent = createDiffContent(root, leftPath, leftHash);
DiffContent rightDiffContent = createDiffContent(root, rightPath, rightHash);
return new SimpleDiffRequest(getTitle(leftPath, rightPath, " -> "),
leftDiffContent, rightDiffContent,
leftHash.asString(), rightHash.asString());
}
},
request -> DiffManager.getInstance().showDiff(myProject, request),
"Calculating Diff for " + chooseNotNull(rightPath, leftPath).getName());
}
}
@Override
public void showDiffWithLocal(@NotNull VirtualFile root, @Nullable FilePath revisionPath, @NotNull Hash revisionHash,
@NotNull FilePath localPath) {
if (localPath.isDirectory()) {
showDiffForDirectory(root, localPath, revisionHash, null);
}
else {
loadDiffAndShow(new ThrowableComputable<DiffRequest, VcsException>() {
@Override
public DiffRequest compute() throws VcsException {
DiffContent leftDiffContent = createDiffContent(root, revisionPath, revisionHash);
VirtualFile file = localPath.getVirtualFile();
LOG.assertTrue(file != null);
DiffContent rightDiffContent = myDiffContentFactory.create(myProject, file);
return new SimpleDiffRequest(getTitle(revisionPath, localPath, " -> "),
leftDiffContent, rightDiffContent,
revisionHash.asString(), "(Local)");
}
},
request -> DiffManager.getInstance().showDiff(myProject, request), "Calculating Diff for " + localPath.getName());
}
}
private void showDiffForDirectory(@NotNull VirtualFile root,
@NotNull FilePath directoryPath,
@NotNull Hash leftRevision, @Nullable Hash rightRevision) {
loadDiffAndShow(() -> GitChangeUtils.getDiff(myProject, root,
leftRevision.asString(), rightRevision == null ? null : rightRevision.asString(),
Collections.singleton(directoryPath)),
(diff) -> {
String dialogTitle = "Changes between " +
leftRevision.asString() +
" and " +
(rightRevision == null ? "current revision" : rightRevision.asString()) +
" in " +
getTitle(directoryPath, directoryPath, " -> ");
VcsDiffUtil.showChangesDialog(myProject, dialogTitle, ContainerUtil.newArrayList(diff));
}, "Calculating Diff for " + directoryPath.getName());
}
private <T> void loadDiffAndShow(@NotNull ThrowableComputable<T, VcsException> load,
@NotNull Consumer<T> show,
@NotNull @Nls(capitalization = Nls.Capitalization.Title) String title) {
if (ApplicationManager.getApplication().isDispatchThread()) {
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, title + "...", false) {
@Nullable private T myResult;
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
myResult = load.compute();
}
catch (VcsException e) {
throw new RuntimeException(e);
}
}
@Override
public void onSuccess() {
if (myResult != null) {
show.consume(myResult);
}
}
@Override
public void onThrowable(@NotNull Throwable error) {
VcsBalloonProblemNotifier.showOverVersionControlView(myProject, title + " failed\n" +
error.getMessage(), MessageType.ERROR);
}
});
}
else {
try {
T result = load.compute();
ApplicationManager.getApplication().invokeLater(() -> show.consume(result));
}
catch (VcsException e) {
VcsBalloonProblemNotifier.showOverVersionControlView(myProject, title + " failed\n" +
e.getMessage(), MessageType.ERROR);
}
}
}
@NotNull
private DiffContent createDiffContent(@NotNull VirtualFile root,
@Nullable FilePath path,
@NotNull Hash hash) throws VcsException {
DiffContent diffContent;
if (path == null) {
diffContent = new EmptyContent();
}
else {
try {
byte[] content = GitFileUtils.getFileContent(myProject, root, hash.asString(), VcsFileUtil.relativePath(root, path));
diffContent = myDiffContentFactory.createFromBytes(myProject, content, path);
}
catch (IOException e) {
throw new VcsException(e);
}
}
diffContent.putUserData(DiffUserDataKeysEx.REVISION_INFO, new Pair<>(path, new GitRevisionNumber(hash.asString())));
return diffContent;
}
}
@@ -529,6 +529,12 @@ public class GitLogProvider implements VcsLogProvider {
return currentBranchName;
}
@Nullable
@Override
public VcsLogDiffHandler getDiffHandler() {
return new GitLogDiffHandler(myProject);
}
@SuppressWarnings("unchecked")
@Nullable
@Override
@@ -32,8 +32,8 @@ import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.autoimport.CachingExternalSystemAutoImportAware;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware;
import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
@@ -53,7 +53,6 @@ import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.PathsList;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.execution.ParametersListUtil;
import com.intellij.util.messages.MessageBusConnection;
import icons.GradleIcons;
import org.jetbrains.annotations.NotNull;
@@ -193,7 +193,7 @@ public class GradleResourceCompilerConfigurationGenerator {
final ExternalProject externalRootProject = lazyExternalProjectMap.get(gradleProjectPath);
if (externalRootProject == null) {
context.addMessage(CompilerMessageCategory.ERROR,
context.addMessage(CompilerMessageCategory.WARNING,
String.format("Unable to make the module: %s, related gradle configuration was not found. " +
"Please, re-import the Gradle project and try again.",
module.getName()), VfsUtilCore.pathToUrl(gradleProjectPath), -1, -1);
@@ -20,7 +20,7 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.text.StringUtil;
@@ -28,8 +28,8 @@ import com.intellij.openapi.compiler.CompileTask;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManager;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -25,7 +25,7 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.ui.ExternalProjectPathField;
import com.intellij.openapi.externalSystem.service.ui.SelectExternalProjectDialog;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
@@ -24,7 +24,7 @@ import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjec
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil;
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.wizard.AbstractExternalProjectImportBuilder;
import com.intellij.openapi.externalSystem.service.ui.ExternalProjectDataSelectorDialog;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
@@ -54,6 +54,13 @@ import java.util.List;
*/
public class GradleProjectImportBuilder extends AbstractExternalProjectImportBuilder<ImportFromGradleControl> {
/**
* @deprecated use {@link GradleProjectImportBuilder#GradleProjectImportBuilder(ProjectDataManager)}
*/
public GradleProjectImportBuilder(@NotNull com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager dataManager) {
this((ProjectDataManager)dataManager);
}
public GradleProjectImportBuilder(@NotNull ProjectDataManager dataManager) {
super(dataManager, new ImportFromGradleControl(), GradleConstants.SYSTEM_ID);
}
@@ -22,7 +22,7 @@ import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager;
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -22,6 +22,8 @@ import com.intellij.ide.impl.ProjectUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
@@ -31,12 +33,17 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.profile.codeInspection.InspectionProfileManager;
import com.intellij.profile.codeInspection.ProjectInspectionProfileManager;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.SmartList;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.junit.Test;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -94,6 +101,81 @@ public class GradleProjectOpenProcessorTest extends GradleImportingTestCase {
}
}
@Test
public void testGradleSettingsFileModification() throws IOException {
VirtualFile foo = createProjectSubDir("foo");
createProjectSubFile("foo/build.gradle", "apply plugin: 'java'");
createProjectSubFile("foo/.idea/modules.xml",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<project version=\"4\">\n" +
" <component name=\"ProjectModuleManager\">\n" +
" <modules>\n" +
" <module fileurl=\"file://$PROJECT_DIR$/foo.iml\" filepath=\"$PROJECT_DIR$/foo.iml\" />\n" +
" <module fileurl=\"file://$PROJECT_DIR$/bar.iml\" filepath=\"$PROJECT_DIR$/bar.iml\" />\n" +
" </modules>\n" +
" </component>\n" +
"</project>");
createProjectSubFile("foo/foo.iml",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<module type=\"JAVA_MODULE\" version=\"4\">\n" +
" <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n" +
" <content url=\"file://$MODULE_DIR$\">\n" +
" </content>\n" +
" </component>\n" +
"</module>");
createProjectSubFile("foo/bar.iml",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<module type=\"JAVA_MODULE\" version=\"4\">\n" +
" <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n" +
" </component>\n" +
"</module>");
Project fooProject = executeOnEdt(() -> ProjectUtil.openProject(foo.getPath(), null, true));
try {
assertTrue(fooProject.isOpen());
edt(() -> UIUtil.dispatchAllInvocationEvents());
assertModules(fooProject, "foo", "bar");
Semaphore semaphore = new Semaphore(1);
final MessageBusConnection myBusConnection = fooProject.getMessageBus().connect();
myBusConnection.subscribe(ProjectDataImportListener.TOPIC, path -> semaphore.up());
createProjectSubFile("foo/.idea/gradle.xml",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<project version=\"4\">\n" +
" <component name=\"GradleSettings\">\n" +
" <option name=\"linkedExternalProjectsSettings\">\n" +
" <GradleProjectSettings>\n" +
" <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n" +
" <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n" +
" <option name=\"gradleJvm\" value=\"" + GRADLE_JDK_NAME + "\" />\n" +
" <option name=\"modules\">\n" +
" <set>\n" +
" <option value=\"$PROJECT_DIR$\" />\n" +
" </set>\n" +
" </option>\n" +
" <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n" +
" </GradleProjectSettings>\n" +
" </option>\n" +
" </component>\n" +
"</project>");
edt(() -> UIUtil.dispatchAllInvocationEvents());
edt(() -> PlatformTestUtil.saveProject(fooProject));
assert semaphore.waitFor(100000);
assertTrue("The module has not been linked",
ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, getModule(fooProject, "foo")));
}
finally {
edt(() -> closeProject(fooProject));
}
assertFalse(fooProject.isOpen());
assertTrue(fooProject.isDisposed());
//edt(() -> PlatformTestUtil.saveProject(myProject));
//importProject("apply plugin: 'java'");
//assertModules("project", "project_main", "project_test");
}
@Test
public void testOpenAndImportProjectInHeadlessMode() throws Exception {
VirtualFile foo = createProjectSubDir("foo");
@@ -61,20 +61,4 @@ public class Annotation {
annMarker.done(GroovyElementTypes.ANNOTATION);
return true;
}
public static void parseAnnotationOptional(PsiBuilder builder, GroovyParser parser) {
PsiBuilder.Marker annOptMarker = builder.mark();
boolean hasAnnotations = false;
while (parse(builder, parser)) {
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
hasAnnotations = true;
}
if (hasAnnotations) {
annOptMarker.done(GroovyElementTypes.MODIFIERS);
} else {
annOptMarker.rollbackTo();
}
}
}
@@ -35,7 +35,12 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
*/
public class Modifiers {
public static boolean parse(PsiBuilder builder, GroovyParser parser) {
return parse(builder, parser, false);
}
public static boolean parse(PsiBuilder builder, GroovyParser parser, boolean annotationsOnly) {
PsiBuilder.Marker modifiersMarker = builder.mark();
boolean hasModifiers = false;
@@ -44,7 +49,7 @@ public class Modifiers {
final PsiBuilder.Marker modifierListItem = builder.mark();
if (hasModifiers) ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
final boolean parsed = Annotation.parse(builder, parser) || parseModifier(builder);
final boolean parsed = Annotation.parse(builder, parser) || (!annotationsOnly && parseModifier(builder));
if (parsed) {
if (PathExpression.isQualificationDot(builder)) {
@@ -21,7 +21,7 @@ import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParser;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.annotations.Annotation;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.modifiers.Modifiers;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arguments.ArgumentList;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.typeDefinitions.TypeDefinition;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
@@ -35,7 +35,7 @@ public class EnumConstant {
PsiBuilder.Marker ecMarker = builder.mark();
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
Annotation.parseAnnotationOptional(builder, parser);
Modifiers.parse(builder, parser, true);
if (!ParserUtils.getToken(builder, GroovyTokenTypes.mIDENT)) {
ecMarker.rollbackTo();
@@ -55,6 +55,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplements
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAnnotationMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList;
@@ -228,6 +229,11 @@ public class GroovyIndentProcessor extends GroovyElementVisitor {
myResult = Indent.getContinuationWithoutFirstIndent();
}
@Override
public void visitEnumConstant(@NotNull GrEnumConstant enumConstant) {
Indent.getNoneIndent();
}
@Override
public void visitDocComment(@NotNull GrDocComment comment) {
if (myChildType != GroovyDocTokenTypes.mGDOC_COMMENT_START) {
@@ -317,7 +317,11 @@ public class GroovySpacingProcessor extends GroovyElementVisitor {
@Override
public void visitEnumConstant(@NotNull GrEnumConstant enumConstant) {
manageSpaceBeforeCallLParenth();
if (myType1 == GroovyElementTypes.MODIFIERS) {
createSpaceInCode(true);
} else {
manageSpaceBeforeCallLParenth();
}
}
@Override
@@ -688,6 +688,36 @@ def foooo(
''')
}
void testEnumAnnotations() {
checkFormatting('''\
enum GroovyEnum {
FOO,
@Deprecated
BAR(""),
DAR
}
''', '''\
enum GroovyEnum {
FOO,
@Deprecated
BAR(""),
DAR
}
''')
}
void testEnumAnnotationsSingleLine() {
checkFormatting('''\
enum GroovyEnum {
@Deprecated BAR("")
}
''', '''\
enum GroovyEnum {
@Deprecated BAR("")
}
''')
}
void testAlignFor() {
groovySettings.ALIGN_MULTILINE_FOR = true
checkFormatting('''\
@@ -18,6 +18,8 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('CONST')
PsiElement(new line)('\n ')
Variable definitions
@@ -20,15 +20,21 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('Const1')
PsiElement(new line)('\n ')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('Const2')
PsiElement(,)(',')
Enumeration constant
PsiElement(new line)('\n ')
Modifiers
<empty list>
PsiElement(identifier)('Const3')
PsiElement(new line)('\n ')
Variable definitions
@@ -17,6 +17,8 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('Const')
PsiElement(;)(';')
PsiWhiteSpace(' ')
@@ -14,5 +14,7 @@ Groovy script
PsiElement({)('{')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('CONST')
PsiElement(})('}')
@@ -19,6 +19,8 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('foo')
PsiWhiteSpace(' ')
Arguments
@@ -17,6 +17,8 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('foo')
PsiElement(new line)('\n')
PsiElement(})('}')
@@ -18,11 +18,15 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('CONST1')
PsiElement(new line)('\n ')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('CONST2')
PsiElement(new line)('\n')
PsiElement(})('}')
@@ -17,6 +17,8 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('CONST1')
PsiErrorElement:';', '}' or new line expected
<empty list>
@@ -37,30 +37,44 @@ Groovy script
PsiWhiteSpace('\n ')
Enumeration constants
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('SUNDAY')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('MONDAY')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('TUESDAY')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('WEDNESDAY')
PsiElement(,)(',')
Enumeration constant
PsiElement(new line)('\n ')
Modifiers
<empty list>
PsiElement(identifier)('THURSDAY')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('FRIDAY')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Enumeration constant
Modifiers
<empty list>
PsiElement(identifier)('SATURDAY')
PsiElement(new line)('\n ')
PsiElement(})('}')
@@ -335,6 +335,12 @@ public class HgLogProvider implements VcsLogProvider {
return repository.getCurrentBranchName();
}
@Nullable
@Override
public VcsLogDiffHandler getDiffHandler() {
return null;
}
@Nullable
@Override
public <T> T getPropertyValue(VcsLogProperties.VcsLogProperty<T> property) {
@@ -0,0 +1,82 @@
/*
* 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.lang.properties.psi.impl;
import com.intellij.lang.properties.parsing.PropertiesTokenTypes;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
import com.intellij.psi.impl.PsiTreeChangePreprocessorBase;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class PropertiesPsiTreeChangePreprocessor extends PsiTreeChangePreprocessorBase {
private static final TokenSet CODE_BLOCK_ELEMENTS = TokenSet.create(PropertiesTokenTypes.VALUE_CHARACTERS,
PropertiesTokenTypes.END_OF_LINE_COMMENT,
PropertiesTokenTypes.WHITE_SPACE,
PropertiesTokenTypes.KEY_VALUE_SEPARATOR);
public PropertiesPsiTreeChangePreprocessor(@NotNull PsiManager psiManager) {
super(psiManager);
}
@Override
protected void onTreeChanged(@NotNull PsiTreeChangeEventImpl event) {
if (event.isGenericChange()) return;
switch (event.getCode()) {
case BEFORE_PROPERTY_CHANGE:
case BEFORE_CHILD_REMOVAL:
case BEFORE_CHILD_ADDITION:
case BEFORE_CHILD_MOVEMENT:
case BEFORE_CHILDREN_CHANGE:
case BEFORE_CHILD_REPLACEMENT:
return;
case CHILD_ADDED:
if (isCodeBlock(event.getChild())) return;
break;
case CHILD_REMOVED:
if (isCodeBlock(event.getChild())) return;
break;
case CHILD_REPLACED:
if (isCodeBlock(event.getOldChild()) || isCodeBlock(event.getNewChild())) return;
break;
case CHILD_MOVED:
if (isCodeBlock(event.getChild())) return;
break;
case CHILDREN_CHANGED:
if (isCodeBlock(event.getParent())) return;
case PROPERTY_CHANGED:
break;
}
doIncOutOfCodeBlockCounter();
}
@Override
protected boolean acceptsEvent(@NotNull PsiTreeChangeEventImpl event) {
return event.getFile() instanceof PropertiesFile;
}
@Override
protected boolean isOutOfCodeBlock(@NotNull PsiElement element) {
throw new IllegalStateException();
}
private static boolean isCodeBlock(@NotNull PsiElement element) {
return CODE_BLOCK_ELEMENTS.contains(PsiUtilCore.getElementType(element));
}
}
@@ -123,6 +123,8 @@
<lang.inspectionSuppressor language="Properties" implementationClass="com.intellij.codeInspection.PropertiesInspectionSuppressor"/>
<qualifiedNameProvider implementation="com.intellij.ide.actions.PropertiesQualifiedNameProvider"/>
<psi.treeChangePreprocessor implementation="com.intellij.lang.properties.psi.impl.PropertiesPsiTreeChangePreprocessor"/>
</extensions>
<project-components>
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.formatter.FormattingDocumentModelImpl;
import com.intellij.psi.formatter.PsiBasedFormattingModel;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.impl.source.tree.TreeUtil;
@@ -34,10 +35,10 @@ import org.jetbrains.annotations.Nullable;
public class PropertiesFormattingModelBuilder implements FormattingModelBuilder {
@NotNull
@Override
public PropertiesFormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
final ASTNode root = TreeUtil.getFileElement((TreeElement)SourceTreeToPsiMap.psiElementToTree(element));
final FormattingDocumentModelImpl documentModel = FormattingDocumentModelImpl.createOn(element.getContainingFile());
return new PropertiesFormattingModel(root, documentModel, settings);
return new PsiBasedFormattingModel(element.getContainingFile(), new PropertiesRootBlock(root, settings), documentModel);
}
@Nullable
@@ -45,41 +46,4 @@ public class PropertiesFormattingModelBuilder implements FormattingModelBuilder
public TextRange getRangeAffectingIndent(PsiFile file, int offset, ASTNode elementAtOffset) {
return null;
}
private static class PropertiesFormattingModel implements FormattingModel {
private final FormattingDocumentModelImpl myDocumentModel;
private PropertiesRootBlock myRoot;
public PropertiesFormattingModel(ASTNode root, FormattingDocumentModelImpl documentModel, CodeStyleSettings settings) {
myRoot = new PropertiesRootBlock(root, settings);
myDocumentModel = documentModel;
}
@NotNull
@Override
public Block getRootBlock() {
return myRoot;
}
@NotNull
@Override
public FormattingDocumentModel getDocumentModel() {
return myDocumentModel;
}
@Override
public TextRange replaceWhiteSpace(TextRange textRange, String whiteSpace) {
return textRange;
}
@Override
public TextRange shiftIndentInsideRange(ASTNode node, TextRange range, int indent) {
return null;
}
@Override
public void commitChanges() {
}
}
}
@@ -0,0 +1,90 @@
/*
* 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.lang.properties;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
public class PropertiesModificationTest extends LightCodeInsightFixtureTestCase {
public void testValueEditing() {
doTestEditing(" # comment<caret>", false);
}
public void testKeyEditing() {
doTestEditing("key<caret> = value", true);
}
public void testCommentEditing() {
doTestEditing("key = value<caret>", false);
}
public void testKeyReplacement() {
doTestReplacement("<selection>key</selection> = value", true);
}
public void testValueReplacement() {
doTestReplacement("key = <selection>value</selection>", false);
}
public void testCommentReplacement() {
doTestReplacement("key = value \n# <selection>comment</selection> \n key2 = value2", false);
}
public void testKeyDeletion() {
doTestDeletion("<selection>key</selection> = value", true);
}
public void testPropertiesDeletion() {
doTestDeletion("ke<selection>y1 = value1 \n" +
"key2 = value2 \n" +
"key3 = value3 \n" +
"key4 = value4 \n" +
"key5 = val</selection>ue5 \n", true);
}
private void doTestEditing(@NotNull String text, boolean isOutOfBlockModificationExpected) {
doTest(text, () -> myFixture.type("xxx"), isOutOfBlockModificationExpected);
}
private void doTestReplacement(@NotNull String text, boolean isOutOfBlockModificationExpected) {
doTest(text, () -> WriteCommandAction.runWriteCommandAction(getProject(), () -> {
SelectionModel sel = getEditor().getSelectionModel();
getEditor().getDocument().replaceString(sel.getSelectionStart(), sel.getSelectionEnd(), "xxx");
}), isOutOfBlockModificationExpected);
}
private void doTestDeletion(@NotNull String text, boolean isOutOfBlockModificationExpected) {
doTest(text, () -> WriteCommandAction.runWriteCommandAction(getProject(), () -> {
SelectionModel sel = getEditor().getSelectionModel();
getEditor().getDocument().deleteString(sel.getSelectionStart(), sel.getSelectionEnd());
}), isOutOfBlockModificationExpected);
}
private void doTest(@NotNull String text, Runnable modificationAction, boolean isOutOfBlockModificationExpected) {
myFixture.configureByText("test.properties", text);
PsiModificationTracker tracker = myFixture.getPsiManager().getModificationTracker();
long oldMod = tracker.getOutOfCodeBlockModificationCount();
modificationAction.run();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
long newMod = tracker.getOutOfCodeBlockModificationCount();
assertTrue(isOutOfBlockModificationExpected ^ oldMod == newMod);
}
}