Merge remote-tracking branch 'origin/master'

This commit is contained in:
Maxim.Medvedev
2012-01-27 16:19:02 +04:00
256 changed files with 7079 additions and 2057 deletions
+2 -2
View File
@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="Netty">
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/netty-3.2.5.Final.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/netty-3.3.0.Final.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$PROJECT_DIR$/lib/src/netty-3.2.5.Final-sources.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/src/netty-3.3.0.Final-sources.jar!/" />
</SOURCES>
</library>
</component>
@@ -16,6 +16,7 @@
package org.intellij.images.util;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.io.UnsyncByteArrayInputStream;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -65,7 +66,7 @@ public class ImageInfoReader {
@Nullable
private static Info read(@NotNull final byte[] data) {
final DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
final DataInputStream is = new DataInputStream(new UnsyncByteArrayInputStream(data));
try {
return readFileData(is);
}
@@ -966,7 +966,8 @@ public class CompileDriver {
boolean didSomething = false;
final CompilerManager compilerManager = CompilerManager.getInstance(myProject);
GenericCompilerRunner runner = new GenericCompilerRunner(context, myCompilerFilter, compilerManager, isRebuild, onlyCheckStatus);
GenericCompilerRunner runner = new GenericCompilerRunner(context, isRebuild, onlyCheckStatus,
compilerManager.getCompilers(GenericCompiler.class, myCompilerFilter));
try {
didSomething |= generateSources(compilerManager, context, forceCompile, onlyCheckStatus);
@@ -53,14 +53,12 @@ public class GenericCompilerRunner {
private final Project myProject;
public GenericCompilerRunner(CompileContext context,
CompilerFilter compilerFilter,
CompilerManager compilerManager,
boolean forceCompile,
boolean onlyCheckStatus) {
boolean onlyCheckStatus, final GenericCompiler[] compilers) {
myContext = context;
myForceCompile = forceCompile;
myOnlyCheckStatus = onlyCheckStatus;
myCompilers = compilerManager.getCompilers(GenericCompiler.class, compilerFilter);
myCompilers = compilers;
myProject = myContext.getProject();
}
@@ -69,7 +67,7 @@ public class GenericCompilerRunner {
try {
for (GenericCompiler<?,?,?> compiler : myCompilers) {
if (compiler.getOrderPlace().equals(place)) {
didSomething = invokeCompiler(compiler);
didSomething |= invokeCompiler(compiler);
}
}
}
@@ -1,48 +0,0 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.compiler.generic;
import com.intellij.openapi.compiler.CompileContext;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
/**
* @author nik
*/
public abstract class SingleTargetCompilerInstance<Item extends CompileItem<K,S,O>, K,S, O> extends
GenericCompilerInstance<BuildTarget, Item, K, S, O> {
protected SingleTargetCompilerInstance(CompileContext context) {
super(context);
}
@NotNull
@Override
public List<BuildTarget> getAllTargets() {
return Collections.singletonList(BuildTarget.DEFAULT);
}
@NotNull
@Override
public List<BuildTarget> getSelectedTargets() {
return getAllTargets();
}
@Override
public void processObsoleteTarget(@NotNull String targetId, @NotNull List<GenericCompilerCacheState<K, S, O>> obsoleteItems) {
}
}
@@ -16,8 +16,6 @@
package com.intellij.openapi.compiler.generic;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
/**
@@ -99,6 +99,7 @@ public class BuildArtifactsBeforeRunTaskProvider extends BeforeRunTaskProvider<B
}
public BuildArtifactsBeforeRunTask createTask(RunConfiguration runConfiguration) {
if (myProject.isDefault()) return null;
return new BuildArtifactsBeforeRunTask(myProject);
}
@@ -61,9 +61,16 @@ public class RequestHint {
private boolean myMethodExecuted;
public SmartStepFilter(PsiMethod psiMethod) {
myDeclaringClassName = JVMNameUtil.getJVMQualifiedName(psiMethod.getContainingClass());
myTargetMethodName = psiMethod.isConstructor()? "<init>" : psiMethod.getName();
myTargetMethodSignature = JVMNameUtil.getJVMSignature(psiMethod);
this(JVMNameUtil.getJVMQualifiedName(psiMethod.getContainingClass()),
psiMethod.isConstructor()? "<init>" : psiMethod.getName(),
JVMNameUtil.getJVMSignature(psiMethod));
}
public SmartStepFilter(@NotNull JVMName declaringClassName, @NonNls String targetMethodName,
@NotNull JVMName targetMethodSignature) {
myDeclaringClassName = declaringClassName;
myTargetMethodName = targetMethodName;
myTargetMethodSignature = targetMethodSignature;
}
public String getTargetMethodName() {
@@ -30,6 +30,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
@@ -106,14 +107,7 @@ public class JavaExecutionUtil {
@Nullable
public static String getRuntimeQualifiedName(final PsiClass aClass) {
final PsiClass containingClass = aClass.getContainingClass();
if (containingClass != null) {
final String parentName = getRuntimeQualifiedName(containingClass);
return parentName + "$" + aClass.getName();
}
else {
return aClass.getQualifiedName();
}
return ClassUtil.getJVMClassName(aClass);
}
@Nullable
@@ -16,7 +16,6 @@
package com.intellij.psi.impl.file;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.ide.projectView.impl.ProjectViewPane;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.undo.GlobalUndoableAction;
import com.intellij.openapi.command.undo.UndoManager;
@@ -139,7 +138,7 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
final ProjectView projectView = ProjectView.getInstance(project);
PsiDirectory[] directories = suggestMostAppropriateDirectories(psiPackage);
if (directories.length == 0) return;
projectView.getProjectViewPaneById(ProjectViewPane.ID).select(directories[0], directories[0].getVirtualFile(), requestFocus);
projectView.select(directories[0], directories[0].getVirtualFile(), requestFocus);
}
});
}
@@ -71,6 +71,7 @@
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<margin top="2" left="0" bottom="2" right="3"/>
<text resource-bundle="messages/IdeBundle" key="unscramble.use.unscrambler.checkbox"/>
</properties>
</component>
@@ -81,11 +82,12 @@
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<margin top="2" left="0" bottom="2" right="3"/>
<text value="Automatically detect and analyze thread dumps copied to the clipboard outside of IntelliJ IDEA"/>
</properties>
</component>
<grid id="28646" binding="myBottomPanel" custom-create="true" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<margin top="0" left="3" bottom="0" right="0"/>
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,15 @@
package com.intellij.codeInsight;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.util.*;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
@@ -347,18 +347,26 @@ public class ExceptionUtil {
@NotNull
public static List<PsiClassType> getUnhandledCloserExceptions(final PsiResourceVariable resource, @Nullable final PsiElement topElement) {
final PsiType resourceType = resource.getType();
if (resourceType instanceof PsiClassType) {
final PsiClass resourceClass = ((PsiClassType)resourceType).resolve();
if (resourceClass != null) {
final PsiMethod[] closers = resourceClass.findMethodsByName("close", false);
for (final PsiMethod method : closers) {
if (method.getParameterList().getParametersCount() == 0) {
return getUnhandledExceptions(method, resource, topElement, PsiSubstitutor.EMPTY);
final Project project = resource.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiClass autoCloseable = facade.findClass(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, ProjectScope.getLibrariesScope(project));
if (autoCloseable != null) {
final PsiMethod[] methods = autoCloseable.findMethodsByName("close", false);
if (methods.length == 1) {
final MethodSignature signature = methods[0].getSignature(PsiSubstitutor.EMPTY);
final PsiType resourceType = resource.getType();
if (resourceType instanceof PsiClassType) {
final PsiClass resourceClass = ((PsiClassType)resourceType).resolve();
if (resourceClass != null) {
final PsiMethod method = MethodSignatureUtil.findMethodBySignature(resourceClass, signature, true);
if (method != null) {
return getUnhandledExceptions(method, resource, topElement, PsiSubstitutor.EMPTY);
}
}
}
}
}
return Collections.emptyList();
}
@@ -27,6 +27,7 @@ import com.intellij.psi.tree.TokenSet;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey;
import static com.intellij.lang.PsiBuilderUtil.expect;
import static com.intellij.lang.PsiBuilderUtil.nextTokenType;
@@ -86,7 +87,7 @@ public class DeclarationParser {
}
parseClassBodyDeclarations(builderWrapper, isAnnotation);
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
expectOrError(builder, JavaTokenType.RBRACE, "expected.rbrace");
}
@Nullable
@@ -139,7 +140,7 @@ public class DeclarationParser {
}
if (declarationsAfterEnd) {
expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
expectOrError(builder, JavaTokenType.RBRACE, "expected.rbrace");
}
}
@@ -426,7 +427,7 @@ public class DeclarationParser {
final boolean anno, final boolean constructor) {
parseParameterList(builder);
eatBrackets(builder, constructor, JavaErrorMessages.message("expected.semicolon"));
eatBrackets(builder, constructor, "expected.semicolon");
if (areTypeAnnotationsSupported(builder)) {
final PsiBuilder.Marker receiver = builder.mark();
@@ -489,8 +490,8 @@ public class DeclarationParser {
builder.advanceLexer();
final IElementType delimiter = resources ? JavaTokenType.SEMICOLON : JavaTokenType.COMMA;
final String noDelimiterMsg = JavaErrorMessages.message(resources ? "expected.semicolon" : "expected.comma");
final String noElementMsg = JavaErrorMessages.message(resources ? "expected.resource" : "expected.parameter");
final String noDelimiterMsg = resources ? "expected.semicolon" : "expected.comma";
final String noElementMsg = resources ? "expected.resource" : "expected.parameter";
PsiBuilder.Marker invalidElements = null;
String errorMessage = null;
@@ -548,7 +549,7 @@ public class DeclarationParser {
if (invalidElements == null) {
if (builder.getTokenType() == delimiter) {
error(builder, noElementMsg);
error(builder, JavaErrorMessages.message(noElementMsg));
builder.advanceLexer();
if (noElements && resources) {
noElements = false;
@@ -557,7 +558,7 @@ public class DeclarationParser {
}
else {
invalidElements = builder.mark();
errorMessage = delimiterExpected ? noDelimiterMsg : noElementMsg;
errorMessage = JavaErrorMessages.message(delimiterExpected ? noDelimiterMsg : noElementMsg);
}
}
@@ -613,7 +614,7 @@ public class DeclarationParser {
if (expect(builder, JavaTokenType.IDENTIFIER)) {
if (!resource) {
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, "expected.rparen");
done(param, JavaElementType.PARAMETER);
return param;
}
@@ -624,7 +625,7 @@ public class DeclarationParser {
return modListInfo.first;
}
if (expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"))) {
if (expectOrError(builder, JavaTokenType.EQ, "expected.eq")) {
if (myExpressionParser.parse(builder) == null) {
error(builder, JavaErrorMessages.message("expected.expression"));
}
@@ -720,7 +721,8 @@ public class DeclarationParser {
return declaration;
}
private static boolean eatBrackets(final PsiBuilder builder, final boolean isError, @Nullable final String error) {
private static boolean eatBrackets(final PsiBuilder builder, final boolean isError,
@Nullable @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String errorKey) {
if (builder.getTokenType() != JavaTokenType.LBRACKET) return true;
final PsiBuilder.Marker marker = isError ? builder.mark() : null;
@@ -735,7 +737,7 @@ public class DeclarationParser {
}
if (marker != null) {
marker.error(error);
marker.error(errorKey != null ? JavaErrorMessages.message(errorKey):null);
}
return result;
@@ -840,9 +842,9 @@ public class DeclarationParser {
pair = builder.mark();
}
final boolean hasName = expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier"));
final boolean hasName = expectOrError(builder, JavaTokenType.IDENTIFIER, "expected.identifier");
expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"));
expectOrError(builder, JavaTokenType.EQ, "expected.eq");
parseAnnotationValue(builder);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -404,7 +404,7 @@ public class ExpressionParser {
final PsiBuilder.Marker refExpr = expr.precede();
myReferenceParser.parseReferenceParameterList(builder, false, false);
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.IDENTIFIER, JavaErrorMessages.message("expected.identifier"))) {
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.IDENTIFIER, "expected.identifier")) {
refExpr.done(JavaElementType.REFERENCE_EXPRESSION);
startMarker.drop();
return refExpr;
@@ -726,7 +726,7 @@ public class ExpressionParser {
}
bracketCount++;
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.RBRACKET, JavaErrorMessages.message("expected.rbracket"))) {
if (!JavaParserUtil.expectOrError(builder, JavaTokenType.RBRACKET, "expected.rbracket")) {
newExpr.done(JavaElementType.NEW_EXPRESSION);
return newExpr;
}
@@ -812,7 +812,7 @@ public class ExpressionParser {
}
}
final boolean closed = JavaParserUtil.expectOrError(builder, JavaTokenType.RPARENTH, JavaErrorMessages.message("expected.rparen"));
final boolean closed = JavaParserUtil.expectOrError(builder, JavaTokenType.RPARENTH, "expected.rparen");
list.done(JavaElementType.EXPRESSION_LIST);
if (!closed) {
@@ -827,35 +827,29 @@ public class ExpressionParser {
@Nullable
private static IElementType getGtTokenType(final PsiBuilder builder) {
final PsiBuilder.Marker sp = builder.mark();
IElementType tokenType = builder.getTokenType();
if (tokenType == JavaTokenType.GT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.GT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.GT) {
builder.advanceLexer();
if (builder.getTokenType() == JavaTokenType.EQ) {
tokenType = JavaTokenType.GTGTGTEQ;
}
else {
tokenType = JavaTokenType.GTGTGT;
}
}
else if (builder.getTokenType() == JavaTokenType.EQ) {
tokenType = JavaTokenType.GTGTEQ;
if (tokenType != JavaTokenType.GT) return tokenType;
if (builder.rawLookup(1) == JavaTokenType.GT) {
if (builder.rawLookup(2) == JavaTokenType.GT) {
if (builder.rawLookup(3) == JavaTokenType.EQ) {
tokenType = JavaTokenType.GTGTGTEQ;
}
else {
tokenType = JavaTokenType.GTGT;
tokenType = JavaTokenType.GTGTGT;
}
}
else if (builder.getTokenType() == JavaTokenType.EQ) {
tokenType = JavaTokenType.GE;
else if (builder.rawLookup(2) == JavaTokenType.EQ) {
tokenType = JavaTokenType.GTGTEQ;
}
else {
tokenType = JavaTokenType.GTGT;
}
}
else if (builder.rawLookup(1) == JavaTokenType.EQ) {
tokenType = JavaTokenType.GE;
}
sp.rollbackTo();
return tokenType;
}
@@ -39,6 +39,7 @@ import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey;
import java.util.List;
@@ -258,9 +259,10 @@ public class JavaParserUtil {
}
}
public static boolean expectOrError(final PsiBuilder builder, final IElementType expectedType, final String errorMessage) {
public static boolean expectOrError(final PsiBuilder builder, final IElementType expectedType,
@PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String errorMessageKey) {
if (!PsiBuilderUtil.expect(builder, expectedType)) {
error(builder, errorMessage);
error(builder, JavaErrorMessages.message(errorMessageKey));
return false;
}
return true;
@@ -275,7 +277,7 @@ public class JavaParserUtil {
}
public static void semicolon(final PsiBuilder builder) {
expectOrError(builder, JavaTokenType.SEMICOLON, JavaErrorMessages.message("expected.semicolon"));
expectOrError(builder, JavaTokenType.SEMICOLON, "expected.semicolon");
}
public static PsiBuilder braceMatchingBuilder(final PsiBuilder builder) {
@@ -293,7 +293,7 @@ public class ReferenceParser {
if (expect(builder, JavaTokenType.GT)) {
break;
}
else if (!expectOrError(builder, JavaTokenType.COMMA, JavaErrorMessages.message("expected.gt.or.comma"))) {
else if (!expectOrError(builder, JavaTokenType.COMMA, "expected.gt.or.comma")) {
isOk = false;
break;
}
@@ -131,7 +131,7 @@ public class StatementParser {
parseStatements(builder, parseUntilEof ? BraceMode.TILL_LAST : BraceMode.TILL_FIRST);
final boolean greedyBlock = !expectOrError(builder, JavaTokenType.RBRACE, JavaErrorMessages.message("expected.rbrace"));
final boolean greedyBlock = !expectOrError(builder, JavaTokenType.RBRACE, "expected.rbrace");
builder.getTokenType(); // eat spaces
done(codeBlock, JavaElementType.CODE_BLOCK);
@@ -543,7 +543,7 @@ public class StatementParser {
}
}
expectOrError(builder, JavaTokenType.COLON, JavaErrorMessages.message("expected.colon"));
expectOrError(builder, JavaTokenType.COLON, "expected.colon");
done(statement, JavaElementType.SWITCH_LABEL_STATEMENT);
return statement;
@@ -328,6 +328,7 @@ expected.lparen.or.lbracket='(' or '[' expected
expected.array.initializer=Array initializer expected
unexpected.tokens=Unexpected tokens
expected.gt.or.comma='>' or ',' expected.
string.expected=String literal expected
else.without.if='else' without 'if'
catch.without.try='catch' without 'try'
finally.without.try='finally' without 'try'
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class C {
static class E extends Exception { }
static class E1 extends E { }
@@ -10,6 +25,8 @@ class C {
@Override public void close() throws E3 { }
}
static interface I extends AutoCloseable { }
void m1() {
try (MyResource r = new MyResource()) { r.doSomething(); }
catch (E1 | E2 | E3 ignore) { }
@@ -24,6 +41,8 @@ class C {
catch (E3 e) { }
try (MyResource r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
try (<error descr="Unhandled exception from auto-closeable resource: java.lang.Exception">I r = null</error>) { System.out.println(r); }
}
void m2() throws Exception {
@@ -0,0 +1,18 @@
PsiJavaFile:Binary2.java
PsiAssignmentExpression:a > = b
PsiBinaryExpression:a >
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiErrorElement:Expression expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiReferenceExpression:b
PsiReferenceParameterList
<empty list>
PsiIdentifier:b('b')
@@ -0,0 +1,18 @@
PsiJavaFile:Binary3.java
PsiAssignmentExpression:a >/**/= b
PsiBinaryExpression:a >
PsiReferenceExpression:a
PsiReferenceParameterList
<empty list>
PsiIdentifier:a('a')
PsiWhiteSpace(' ')
PsiJavaToken:GT('>')
PsiErrorElement:Expression expected
<empty list>
PsiComment(C_STYLE_COMMENT)('/**/')
PsiJavaToken:EQ('=')
PsiWhiteSpace(' ')
PsiReferenceExpression:b
PsiReferenceParameterList
<empty list>
PsiIdentifier:b('b')
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public class JavaLexerTest extends LexerTestCase {
"DOUBLE_LITERAL ('1e137')");
}
public void testTigerNumericLiterals() throws Exception {
public void testTigerNumericLiterals() {
doTest("0xap0f 0xab.p0F 0x.abcP0f 0xabc.defP0F",
"FLOAT_LITERAL ('0xap0f')\nWHITE_SPACE (' ')\n" +
"FLOAT_LITERAL ('0xab.p0F')\nWHITE_SPACE (' ')\n" +
@@ -115,7 +115,7 @@ public class JavaLexerTest extends LexerTestCase {
"DOUBLE_LITERAL ('0xa_bc.de_fP1_234D')");
}
public void testMalformedCoinLiterals() throws Exception {
public void testMalformedCoinLiterals() {
doTest("0_ _1 0_8 0x_f 0b_1 0B2 0x1.0_p-1 1.0e_1022",
"INTEGER_LITERAL ('0')\nIDENTIFIER ('_')\nWHITE_SPACE (' ')\n" +
"IDENTIFIER ('_1')\nWHITE_SPACE (' ')\n" +
@@ -127,6 +127,13 @@ public class JavaLexerTest extends LexerTestCase {
"DOUBLE_LITERAL ('1.0e')\nIDENTIFIER ('_1022')");
}
public void testMalformedOperators() {
doTest("(i > = 0)",
"LPARENTH ('(')\nIDENTIFIER ('i')\nWHITE_SPACE (' ')\n" +
"GT ('>')\nWHITE_SPACE (' ')\nEQ ('=')\n" +
"WHITE_SPACE (' ')\nINTEGER_LITERAL ('0')\nRPARENTH (')')\n");
}
@Override
protected Lexer createLexer() {
return new JavaLexer(LanguageLevel.HIGHEST);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ public class ExpressionParserTest extends JavaParsingTestCase {
public void testBinary0() { doParserTest("a + b"); }
public void testBinary1() { doParserTest("a < b"); }
public void testBinary2() { doParserTest("a > = b"); }
public void testBinary3() { doParserTest("a >/**/= b"); }
public void testCond0() { doParserTest("cond ? true : false"); }
public void testCond1() { doParserTest("cond ?"); }
@@ -245,26 +245,19 @@ public class ClassUtil {
@Nullable
public static String getJVMClassName(PsiClass aClass) {
final String qName = aClass.getQualifiedName();
if (qName == null) return null;
return replaceDotsWithDollars(qName, aClass);
}
private static String replaceDotsWithDollars(final String qName, PsiClass aClass) {
StringBuilder qNameBuffer = new StringBuilder(qName);
int fromIndex = qNameBuffer.length();
PsiElement parent = aClass.getParent();
while (parent instanceof PsiClass) {
final int dotIndex = qNameBuffer.lastIndexOf(".", fromIndex);
if (dotIndex < 0) break;
qNameBuffer.replace(dotIndex, dotIndex + 1, "$");
fromIndex = dotIndex - 1;
parent = parent.getParent();
final PsiClass containingClass = aClass.getContainingClass();
if (containingClass != null) {
String parentName = getJVMClassName(containingClass);
if (parentName == null) {
return null;
}
return parentName + "$" + aClass.getName();
}
return qNameBuffer.toString();
return aClass.getQualifiedName();
}
@Nullable
public static PsiClass findPsiClassByJVMName(final PsiManager manager, final String jvmClassName) {
return findPsiClass(manager, jvmClassName.replace('/', '.'), null, true);
@@ -42,6 +42,9 @@ public class DefaultLightProjectDescriptor implements LightProjectDescriptor {
@Override
public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.HIGHEST);
LanguageLevelModuleExtension extension = model.getModuleExtension(LanguageLevelModuleExtension.class);
if (extension != null) {
extension.setLanguageLevel(LanguageLevel.HIGHEST);
}
}
}
@@ -1,160 +1,10 @@
package org.jetbrains.jps.incremental;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.ether.dependencyView.Mappings;
import org.jetbrains.jps.Module;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 9/17/11
* @author nik
*/
public abstract class Builder {
private static final Key<Set<File>> ALL_AFFECTED_FILES_KEY = Key.create("_all_affected_files_");
private static final Key<Set<File>> ALL_COMPILED_FILES_KEY = Key.create("_all_compiled_files_");
public static enum ExitCode {
OK, ABORT, ADDITIONAL_PASS_REQUIRED
}
public abstract String getName();
public abstract ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException;
public abstract String getDescription();
public void cleanupResources(CompileContext context, ModuleChunk chunk) {
ALL_AFFECTED_FILES_KEY.set(context, null);
ALL_COMPILED_FILES_KEY.set(context, null);
}
/**
* @param context
* @param delta
* @param chunk
* @param filesToCompile files compiled in this round
* @param successfullyCompiled
* @return true if additional compilation pass is required, false otherwise
* @throws Exception
*/
public final boolean updateMappings(CompileContext context, final Mappings delta, ModuleChunk chunk, Collection<File> filesToCompile, Collection<File> successfullyCompiled) throws Exception {
try {
boolean additionalPassRequired = false;
final Set<String> removedPaths = getRemovedPaths(context);
final Mappings globalMappings = context.getDataManager().getMappings();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (globalMappings) {
if (!context.isProjectRebuild() && context.shouldDifferentiate(chunk, context.isCompilingTests())) {
final Set<File> allCompiledFiles = getAllCompiledFilesContainer(context);
final Set<File> allAffectedFiles = getAllAffectedFilesContainer(context);
// mark as affected all files that were dirty before compilation
allAffectedFiles.addAll(filesToCompile);
// accumulate all successfully compiled in this round
allCompiledFiles.addAll(successfullyCompiled);
// unmark as affected all successfully compiled
allAffectedFiles.removeAll(successfullyCompiled);
final HashSet<File> affectedBeforeDif = new HashSet<File>(allAffectedFiles);
final boolean incremental = globalMappings.differentiate(
delta, removedPaths, successfullyCompiled, allCompiledFiles, allAffectedFiles
);
if (incremental) {
final Set<File> newlyAffectedFiles = new HashSet<File>(allAffectedFiles);
newlyAffectedFiles.removeAll(affectedBeforeDif);
newlyAffectedFiles.removeAll(allCompiledFiles); // the diff operation may have affected the class already compiled in thic compilation round
if (!newlyAffectedFiles.isEmpty()) {
for (File file : newlyAffectedFiles) {
context.markDirty(file);
}
additionalPassRequired = context.isMake() && chunkContainsAffectedFiles(context, chunk, newlyAffectedFiles);
}
}
else {
additionalPassRequired = context.isMake();
context.markDirtyRecursively(chunk);
}
}
globalMappings.integrate(delta, successfullyCompiled, removedPaths);
}
return additionalPassRequired;
}
catch(RuntimeException e) {
final Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw ((IOException)cause);
}
throw e;
}
}
// delete all class files that according to mappings correspond to given sources
public static void deleteCorrespondingOutputFiles(CompileContext context, Map<File, Module> sources) throws Exception {
if (!context.isProjectRebuild() && !sources.isEmpty()) {
for (Map.Entry<File, Module> pair : sources.entrySet()) {
final File file = pair.getKey();
final String srcPath = FileUtil.toSystemIndependentName(file.getPath());
final String moduleName = pair.getValue().getName().toLowerCase(Locale.US);
final SourceToOutputMapping srcToOut = context.getDataManager().getSourceToOutputMap(moduleName, context.isCompilingTests());
final Collection<String> outputs = srcToOut.getState(srcPath);
if (outputs != null) {
for (String output : outputs) {
FileUtil.delete(new File(output));
}
srcToOut.remove(srcPath);
}
}
}
}
private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set<File> affected) throws Exception {
final Set<Module> chunkModules = new HashSet<Module>(chunk.getModules());
if (!chunkModules.isEmpty()) {
for (File file : affected) {
final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file);
if (moduleAndRoot != null && chunkModules.contains(moduleAndRoot.module)) {
return true;
}
}
}
return false;
}
private static Set<File> getAllAffectedFilesContainer(CompileContext context) {
Set<File> allAffectedFiles = ALL_AFFECTED_FILES_KEY.get(context);
if (allAffectedFiles == null) {
allAffectedFiles = new HashSet<File>();
ALL_AFFECTED_FILES_KEY.set(context, allAffectedFiles);
}
return allAffectedFiles;
}
private static Set<File> getAllCompiledFilesContainer(CompileContext context) {
Set<File> allCompiledFiles = ALL_COMPILED_FILES_KEY.get(context);
if (allCompiledFiles == null) {
allCompiledFiles = new HashSet<File>();
ALL_COMPILED_FILES_KEY.set(context, allCompiledFiles);
}
return allCompiledFiles;
}
private static Set<String> getRemovedPaths(CompileContext context) {
final Set<String> removed = Paths.CHUNK_REMOVED_SOURCES_KEY.get(context);
return removed != null? removed : Collections.<String>emptySet();
}
}
@@ -2,7 +2,7 @@ package org.jetbrains.jps.incremental;
import org.jetbrains.jps.incremental.groovy.GroovyBuilder;
import org.jetbrains.jps.incremental.java.JavaBuilder;
import org.jetbrains.jps.incremental.resourses.ResourcesBuilder;
import org.jetbrains.jps.incremental.resources.ResourcesBuilder;
import java.util.*;
import java.util.concurrent.ExecutorService;
@@ -16,7 +16,7 @@ public class BuilderRegistry {
private static class Holder {
static final BuilderRegistry ourInstance = new BuilderRegistry();
}
private final Map<BuilderCategory, List<Builder>> myBuilders = new HashMap<BuilderCategory, List<Builder>>();
private final Map<BuilderCategory, List<ModuleLevelBuilder>> myBuilders = new HashMap<BuilderCategory, List<ModuleLevelBuilder>>();
private ExecutorService myTasksExecutor;
public static BuilderRegistry getInstance() {
@@ -25,7 +25,7 @@ public class BuilderRegistry {
private BuilderRegistry() {
for (BuilderCategory category : BuilderCategory.values()) {
myBuilders.put(category, new ArrayList<Builder>());
myBuilders.put(category, new ArrayList<ModuleLevelBuilder>());
}
final Runtime runtime = Runtime.getRuntime();
myTasksExecutor = Executors.newFixedThreadPool(runtime.availableProcessors());
@@ -60,7 +60,7 @@ public class BuilderRegistry {
return Collections.emptyList(); // todo
}
public List<Builder> getBuilders(BuilderCategory category){
public List<ModuleLevelBuilder> getBuilders(BuilderCategory category){
return Collections.unmodifiableList(myBuilders.get(category)); // todo
}
@@ -314,7 +314,7 @@ public class IncProjectBuilder {
finally {
try {
for (BuilderCategory category : BuilderCategory.values()) {
for (Builder builder : myBuilderRegistry.getBuilders(category)) {
for (ModuleLevelBuilder builder : myBuilderRegistry.getBuilders(category)) {
builder.cleanupResources(context, chunk);
}
}
@@ -334,7 +334,7 @@ public class IncProjectBuilder {
}
private void runBuilders(CompileContext context, ModuleChunk chunk, BuilderCategory category) throws ProjectBuildException {
final List<Builder> builders = myBuilderRegistry.getBuilders(category);
final List<ModuleLevelBuilder> builders = myBuilderRegistry.getBuilders(category);
if (builders.isEmpty()) {
return;
}
@@ -347,16 +347,16 @@ public class IncProjectBuilder {
do {
nextPassRequired = false;
context.beforeNextCompileRound(chunk);
for (Builder builder : builders) {
final Builder.ExitCode buildResult = builder.build(context, chunk);
for (ModuleLevelBuilder builder : builders) {
final ModuleLevelBuilder.ExitCode buildResult = builder.build(context, chunk);
if (buildResult == Builder.ExitCode.ABORT) {
if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
}
if (myCancelStatus.isCanceled()) {
throw new ProjectBuildException(CANCELED_MESSAGE);
}
if (buildResult == Builder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
if (!nextPassRequired) {
// recalculate basis
myModulesProcessed -= (stagesPassed * modulesInChunk) / stageCount;
@@ -0,0 +1,177 @@
package org.jetbrains.jps.incremental;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.ether.dependencyView.Mappings;
import org.jetbrains.jps.Module;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 9/17/11
*/
public abstract class ModuleLevelBuilder extends Builder {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.Builder");
private static final Key<Set<File>> ALL_AFFECTED_FILES_KEY = Key.create("_all_affected_files_");
private static final Key<Set<File>> ALL_COMPILED_FILES_KEY = Key.create("_all_compiled_files_");
public static enum ExitCode {
OK, ABORT, ADDITIONAL_PASS_REQUIRED
}
public abstract ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException;
public void cleanupResources(CompileContext context, ModuleChunk chunk) {
ALL_AFFECTED_FILES_KEY.set(context, null);
ALL_COMPILED_FILES_KEY.set(context, null);
}
/**
* @param context
* @param delta
* @param chunk
* @param filesToCompile files compiled in this round
* @param successfullyCompiled
* @return true if additional compilation pass is required, false otherwise
* @throws Exception
*/
public final boolean updateMappings(CompileContext context, final Mappings delta, ModuleChunk chunk, Collection<File> filesToCompile, Collection<File> successfullyCompiled) throws Exception {
try {
boolean additionalPassRequired = false;
final Set<String> removedPaths = getRemovedPaths(context);
final Mappings globalMappings = context.getDataManager().getMappings();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (globalMappings) {
if (!context.isProjectRebuild() && context.shouldDifferentiate(chunk, context.isCompilingTests())) {
final Set<File> allCompiledFiles = getAllCompiledFilesContainer(context);
final Set<File> allAffectedFiles = getAllAffectedFilesContainer(context);
// mark as affected all files that were dirty before compilation
allAffectedFiles.addAll(filesToCompile);
// accumulate all successfully compiled in this round
allCompiledFiles.addAll(successfullyCompiled);
// unmark as affected all successfully compiled
allAffectedFiles.removeAll(successfullyCompiled);
final HashSet<File> affectedBeforeDif = new HashSet<File>(allAffectedFiles);
final boolean incremental = globalMappings.differentiate(
delta, removedPaths, successfullyCompiled, allCompiledFiles, allAffectedFiles
);
if (LOG.isDebugEnabled()) {
LOG.debug("Differentiate Results:");
LOG.debug(" Compiled Files:");
for (final File c : allCompiledFiles) {
LOG.debug(" " + c.getAbsolutePath());
}
LOG.debug(" Affected Files:");
for (final File c : allAffectedFiles) {
LOG.debug(" " + c.getAbsolutePath());
}
LOG.debug("End Of Differentiate Results.");
}
if (incremental) {
final Set<File> newlyAffectedFiles = new HashSet<File>(allAffectedFiles);
newlyAffectedFiles.removeAll(affectedBeforeDif);
newlyAffectedFiles.removeAll(allCompiledFiles); // the diff operation may have affected the class already compiled in thic compilation round
if (!newlyAffectedFiles.isEmpty()) {
for (File file : newlyAffectedFiles) {
context.markDirty(file);
}
additionalPassRequired = context.isMake() && chunkContainsAffectedFiles(context, chunk, newlyAffectedFiles);
}
}
else {
additionalPassRequired = context.isMake();
context.markDirtyRecursively(chunk);
}
}
globalMappings.integrate(delta, successfullyCompiled, removedPaths);
}
return additionalPassRequired;
}
catch(RuntimeException e) {
final Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw ((IOException)cause);
}
throw e;
}
}
// delete all class files that according to mappings correspond to given sources
public static void deleteCorrespondingOutputFiles(CompileContext context, Map<File, Module> sources) throws Exception {
if (!context.isProjectRebuild() && !sources.isEmpty()) {
for (Map.Entry<File, Module> pair : sources.entrySet()) {
final File file = pair.getKey();
final String srcPath = FileUtil.toSystemIndependentName(file.getPath());
final String moduleName = pair.getValue().getName().toLowerCase(Locale.US);
final SourceToOutputMapping srcToOut = context.getDataManager().getSourceToOutputMap(moduleName, context.isCompilingTests());
final Collection<String> outputs = srcToOut.getState(srcPath);
if (outputs != null) {
for (String output : outputs) {
FileUtil.delete(new File(output));
}
srcToOut.remove(srcPath);
}
}
}
}
private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set<File> affected) throws Exception {
final Set<Module> chunkModules = new HashSet<Module>(chunk.getModules());
if (!chunkModules.isEmpty()) {
for (File file : affected) {
final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file);
if (moduleAndRoot != null && chunkModules.contains(moduleAndRoot.module)) {
return true;
}
}
}
return false;
}
private static Set<File> getAllAffectedFilesContainer(CompileContext context) {
Set<File> allAffectedFiles = ALL_AFFECTED_FILES_KEY.get(context);
if (allAffectedFiles == null) {
allAffectedFiles = new HashSet<File>();
ALL_AFFECTED_FILES_KEY.set(context, allAffectedFiles);
}
return allAffectedFiles;
}
private static Set<File> getAllCompiledFilesContainer(CompileContext context) {
Set<File> allCompiledFiles = ALL_COMPILED_FILES_KEY.get(context);
if (allCompiledFiles == null) {
allCompiledFiles = new HashSet<File>();
ALL_COMPILED_FILES_KEY.set(context, allCompiledFiles);
}
return allCompiledFiles;
}
private static Set<String> getRemovedPaths(CompileContext context) {
final Set<String> removed = Paths.CHUNK_REMOVED_SOURCES_KEY.get(context);
return removed != null? removed : Collections.<String>emptySet();
}
}
@@ -0,0 +1,20 @@
package org.jetbrains.jps.incremental;
/**
* @author nik
*/
public abstract class ProjectLevelBuilder extends Builder {
private final ProjectLevelBuilderCategory myCategory;
protected ProjectLevelBuilder(ProjectLevelBuilderCategory category) {
myCategory = category;
}
public abstract void build(CompileContext context);
public ProjectLevelBuilderCategory getCategory() {
return myCategory;
}
public static enum ProjectLevelBuilderCategory { TRANSLATOR, PACKAGER }
}
@@ -29,7 +29,7 @@ import java.util.*;
* @author Eugene Zhuravlev
* Date: 10/25/11
*/
public class GroovyBuilder extends Builder {
public class GroovyBuilder extends ModuleLevelBuilder {
public static final String BUILDER_NAME = "groovy";
private final boolean myForStubs;
private final String myBuilderName;
@@ -43,7 +43,7 @@ public class GroovyBuilder extends Builder {
return myBuilderName;
}
public Builder.ExitCode build(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
public ModuleLevelBuilder.ExitCode build(final CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
ExitCode exitCode = ExitCode.OK;
final Map<File, Module> toCompile = new HashMap<File, Module>();
try {
@@ -104,12 +104,13 @@ public class GroovyBuilder extends Builder {
// todo CompilerUtil.addLocaleOptions()
//todo different outputs in a chunk
//todo xmx
//todo module jdk path
final List<String> cmd = ExternalProcessUtil.buildJavaCommandLine(
SystemProperties.getJavaHome() + "/bin/java",
"org.jetbrains.groovy.compiler.rt.GroovycRunner",
Collections.<String>emptyList(), new ArrayList<String>(cp),
Arrays.asList("-Xmx384m"/*, "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5858"*/),
Arrays.asList("-Xmx384m"/*, "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239"*/),
Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath())
);
@@ -49,7 +49,7 @@ import java.util.concurrent.ExecutorService;
* @author Eugene Zhuravlev
* Date: 9/21/11
*/
public class JavaBuilder extends Builder{
public class JavaBuilder extends ModuleLevelBuilder {
public static final String BUILDER_NAME = "java";
private static final String JAVA_EXTENSION = ".java";
private static final String FORM_EXTENSION = ".form";
@@ -1,4 +1,4 @@
package org.jetbrains.jps.incremental.resourses;
package org.jetbrains.jps.incremental.resources;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
@@ -19,7 +19,7 @@ import java.util.Locale;
* @author Eugene Zhuravlev
* Date: 10/6/11
*/
public class ResourcesBuilder extends Builder{
public class ResourcesBuilder extends ModuleLevelBuilder {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.resourses.ResourcesBuilder");
public static final String BUILDER_NAME = "resources";
@@ -172,9 +172,23 @@ class DependencyContext {
public Logger<S> getLogger(final com.intellij.openapi.diagnostic.Logger log) {
return new Logger<S>() {
@Override
public void debug(S s) {
public void debug(String comment, S s) {
if (log.isDebugEnabled()) {
log.debug(getValue(s));
log.debug(comment + getValue(s));
}
}
@Override
public void debug(String comment, String t) {
if (log.isDebugEnabled()){
log.debug(comment + t);
}
}
@Override
public void debug(String comment, boolean t) {
if (log.isDebugEnabled()) {
log.debug(comment + Boolean.toString(t));
}
}
};
@@ -23,5 +23,7 @@ package org.jetbrains.ether.dependencyView;
* To change this template use File | Settings | File Templates.
*/
public interface Logger<T> {
void debug(T t);
void debug(String comment, T t);
void debug(String comment, String t);
void debug(String comment, boolean t);
}
@@ -1,13 +1,12 @@
package org.jetbrains.ether.dependencyView;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.*;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
@@ -22,7 +21,7 @@ import java.util.*;
* To change this template use File | Settings | File Templates.
*/
public class Mappings {
private final static Logger LOG = Logger.getInstance ("#org.jetbrains.ether.dependencyView.Mappings");
private final static Logger LOG = Logger.getInstance("#org.jetbrains.ether.dependencyView.Mappings");
private final static String CLASS_TO_SUBCLASSES = "classToSubclasses.tab";
private final static String CLASS_TO_CLASS = "classToClass.tab";
@@ -38,12 +37,20 @@ public class Mappings {
private DependencyContext myContext;
private org.jetbrains.ether.dependencyView.Logger<DependencyContext.S> myDebugS;
private void debug(final String s) {
private static void debug(final String s) {
LOG.debug(s);
}
private void debug(final DependencyContext.S s) {
myDebugS.debug(s);
private void debug(final String comment, final DependencyContext.S s) {
myDebugS.debug(comment, s);
}
private void debug(final String comment, final String s) {
myDebugS.debug(comment, s);
}
private void debug(final String comment, final boolean s) {
myDebugS.debug(comment, s);
}
private MultiMaplet<DependencyContext.S, DependencyContext.S> myClassToSubclasses;
@@ -534,16 +541,25 @@ public class Mappings {
final Collection<UsageRepr.Usage> affectedUsages,
final Collection<DependencyContext.S> dependants,
final boolean usages) {
debug("Affecting subclasses of class: ", className);
final DependencyContext.S fileName = myClassToSourceFile.get(className);
if (fileName == null) {
debug("No source file detected for class ", className);
debug("End of affectSubclasses");
return;
}
debug("Source file name: ", fileName);
if (usages) {
debug("Class usages affection requested");
final ClassRepr classRepr = reprByName(className);
if (classRepr != null) {
debug("Added class usage for ", classRepr.name);
affectedUsages.add(classRepr.createUsage());
}
}
@@ -579,6 +595,7 @@ public class Mappings {
dependents.addAll(deps);
}
debug("Affect field usage referenced of class ", p);
affectedUsages
.add(rootUsage instanceof UsageRepr.FieldAssignUsage ? field.createAssignUsage(myContext, p) : field.createUsage(myContext, p));
}
@@ -598,6 +615,8 @@ public class Mappings {
dependents.addAll(deps);
}
debug("Affect method usage referenced of class ", p);
affectedUsages
.add(rootUsage instanceof UsageRepr.MetaMethodUsage ? method.createMetaUsage(myContext, p) : method.createUsage(myContext, p));
}
@@ -730,32 +749,38 @@ public class Mappings {
// Public branch --- hopeless
if ((member.access & Opcodes.ACC_PUBLIC) > 0) {
debug("Switched to non-incremental mode");
debug("Public access, switching to a non-incremental mode");
return false;
}
// Protected branch
if ((member.access & Opcodes.ACC_PROTECTED) > 0) {
debug("Softening non-incremental decision: adding all relevant subclasses for a recompilation");
debug("Protected access, softening non-incremental decision: adding all relevant subclasses for a recompilation");
debug("Root class: ", owner);
final Collection<DependencyContext.S> propagated = self.propagateFieldAccess(isField ? member.name : myContext.get(""), owner);
for (DependencyContext.S className : propagated) {
affectedFiles.add(new File(myContext.getValue(myClassToSourceFile.get(className))));
final String fileName = myContext.getValue(myClassToSourceFile.get(className));
debug("Adding ", fileName);
affectedFiles.add(new File(fileName));
}
}
debug("Softening non-incremental decision: adding all package classes for a recompilation");
final String packageName = ClassRepr.getPackageName(myContext.getValue(isField ? owner : member.name));
debug("Softening non-incremental decision: adding all package classes for a recompilation");
debug("Package name: ", packageName);
// Package-local branch
for (Map.Entry<DependencyContext.S, DependencyContext.S> e : myClassToSourceFile.entrySet()) {
final DependencyContext.S className = e.getKey();
final DependencyContext.S fileName = e.getValue();
if (ClassRepr.getPackageName(myContext.getValue(className)).equals(packageName)) {
affectedFiles.add(new File(myContext.getValue(fileName)));
final String f = myContext.getValue(fileName);
debug("Adding: ", f);
affectedFiles.add(new File(f));
}
}
@@ -767,6 +792,8 @@ public class Mappings {
final Collection<File> filesToCompile,
final Collection<File> compiledFiles,
final Collection<File> affectedFiles) {
debug("Begin of Differentiate:");
delta.compensateRemovedContent(filesToCompile);
final Util u = new Util(delta);
@@ -798,14 +825,12 @@ public class Mappings {
final Difference.Specifier<ClassRepr> classDiff = Difference.make(pastClasses, classes);
debug("Processing changed classes");
debug("Processing changed classes:");
for (Pair<ClassRepr, Difference> changed : classDiff.changed()) {
final ClassRepr it = changed.first;
final ClassRepr.Diff diff = (ClassRepr.Diff)changed.second;
debug("Changed: ");
debug(it.name);
debug("Changed: ", it.name);
final int addedModifiers = diff.addedModifiers();
final int removedModifiers = diff.removedModifiers();
@@ -815,24 +840,34 @@ public class Mappings {
final boolean signatureChanged = (diff.base() & Difference.SIGNATURE) > 0;
if (superClassChanged || interfacesChanged || signatureChanged) {
debug("Superclass changed: ", superClassChanged);
debug("Interfaces changed: ", interfacesChanged);
debug("Signature changed ", signatureChanged);
final boolean extendsChanged = superClassChanged && !diff.extendsAdded();
final boolean interfacesRemoved = interfacesChanged && !diff.interfaces().removed().isEmpty();
debug("Extends changed: ", extendsChanged);
debug("Interfaces removed: ", interfacesRemoved);
u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, extendsChanged || interfacesRemoved || signatureChanged);
}
if ((diff.addedModifiers() & Opcodes.ACC_INTERFACE) > 0 || (diff.removedModifiers() & Opcodes.ACC_INTERFACE) > 0) {
debug("Class-to-interface or interface-to-class conversion detected, added class usage to affected usages");
affectedUsages.add(it.createUsage());
}
if (it.isAnnotation() && it.policy == RetentionPolicy.SOURCE) {
debug("Annotation, retention policy = SOURCE => a switch to non-incremental mode requested");
if (!incrementalDecision(it.outerClassName, it, affectedFiles)) {
debug("End of Differentiate, returning false");
return false;
}
}
if ((addedModifiers & Opcodes.ACC_PROTECTED) > 0) {
debug("Introduction of 'protected' modifier detected, adding class usage + inheritance constraint to affected usages");
final UsageRepr.Usage usage = it.createUsage();
affectedUsages.add(usage);
@@ -840,6 +875,7 @@ public class Mappings {
}
if (diff.packageLocalOn()) {
debug("Introduction of 'package local' access detected, adding class usage + package constraint to affected usages");
final UsageRepr.Usage usage = it.createUsage();
affectedUsages.add(usage);
@@ -847,54 +883,64 @@ public class Mappings {
}
if ((addedModifiers & Opcodes.ACC_FINAL) > 0 || (addedModifiers & Opcodes.ACC_PRIVATE) > 0) {
debug("Introduction of 'private' or 'final' modifier(s) detected, adding class usage to affected usages");
affectedUsages.add(it.createUsage());
}
if ((addedModifiers & Opcodes.ACC_ABSTRACT) > 0) {
affectedUsages.add(UsageRepr.createClassNewUsage(myContext, it.name));
}
if ((addedModifiers & Opcodes.ACC_STATIC) > 0 ||
(removedModifiers & Opcodes.ACC_STATIC) > 0 ||
(addedModifiers & Opcodes.ACC_ABSTRACT) > 0) {
if ((addedModifiers & Opcodes.ACC_ABSTRACT) > 0 || (addedModifiers & Opcodes.ACC_STATIC) > 0) {
debug("Introduction of 'abstract' or 'static' modifier(s) detected, adding class new usage to affected usages");
affectedUsages.add(UsageRepr.createClassNewUsage(myContext, it.name));
}
if (it.isAnnotation()) {
debug("Class is annotation, performing annotation-specific analysis");
if (diff.retentionChanged()) {
debug("Retention policy change detected, adding class usage to affected usages");
affectedUsages.add(it.createUsage());
}
else {
final Collection<ElementType> removedtargets = diff.targets().removed();
if (removedtargets.contains(ElementType.LOCAL_VARIABLE)) {
debug("Annotation, removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested");
debug("Removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested");
if (!incrementalDecision(it.outerClassName, it, affectedFiles)) {
debug("End of Differentiate, returning false");
return false;
}
}
if (!removedtargets.isEmpty()) {
debug("Removed some annotation targets, adding annotation query");
annotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr
.createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), null, removedtargets));
}
for (MethodRepr m : diff.methods().added()) {
if (!m.hasValue()) {
debug("Added method with no default value: ", m.name);
debug("Adding class usage to affected usages");
affectedUsages.add(it.createUsage());
}
}
}
debug("End of annotation-specific analysis");
}
debug("Processing added methods: ");
for (MethodRepr m : diff.methods().added()) {
debug("Method: ", m.name);
if (it.isAnnotation()) {
debug("Class is annotation, skipping method analysis");
continue;
}
if ((it.access & Opcodes.ACC_INTERFACE) > 0 ||
(it.access & Opcodes.ACC_ABSTRACT) > 0 ||
(m.access & Opcodes.ACC_ABSTRACT) > 0) {
debug("Class is abstract, or is interface, or added method in abstract => affecting all subclasses");
u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
@@ -908,6 +954,7 @@ public class Mappings {
}
else {
propagated = u.propagateMethodAccess(m.name, it.name);
debug("Conservative case on overriding methods, affecting method usages");
u.affectMethodUsages(m, propagated, m.createMetaUsage(myContext, it.name), affectedUsages, dependants);
}
}
@@ -924,10 +971,12 @@ public class Mappings {
for (MethodRepr mm : lessSpecific) {
if (!mm.equals(m)) {
debug("Found less specific method, affecting method usages");
u.affectMethodUsages(mm, propagated, mm.createUsage(myContext, it.name), affectedUsages, dependants);
}
}
debug("Processing affected by specificity methods");
for (Pair<MethodRepr, ClassRepr> p : affectedMethods) {
final MethodRepr mm = p.first;
final ClassRepr cc = p.second;
@@ -936,7 +985,12 @@ public class Mappings {
}
else {
debug("Method: ", mm.name);
debug("Class : ", cc.name);
if (overrides.satisfy(mm)) {
debug("Current method overrides that found");
final Option<Boolean> subtypeOf = u.isSubtypeOf(mm.type, m.type);
if (weakerAccess(mm.access, m.access) ||
@@ -949,11 +1003,15 @@ public class Mappings {
final DependencyContext.S file = myClassToSourceFile.get(cc.name);
if (file != null) {
affectedFiles.add(new File(myContext.getValue(file)));
final String f = myContext.getValue(file);
debug("Complex condition is satisfied, affecting file ", f);
affectedFiles.add(new File(f));
}
}
}
else {
debug("Current method does not override that found");
final Collection<DependencyContext.S> yetPropagated = self.propagateMethodAccess(mm.name, cc.name);
final Collection<DependencyContext.S> deps = myClassToClassDependency.get(cc.name);
@@ -961,6 +1019,7 @@ public class Mappings {
dependants.addAll(deps);
}
debug("Affecting method usages for that found");
u.affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, cc.name), affectedUsages, dependants);
}
}
@@ -977,19 +1036,26 @@ public class Mappings {
final DependencyContext.S outerClass = r.outerClassName;
if (u.methodVisible(outerClass, m)) {
affectedFiles.add(new File(myContext.getValue(sourceFileName)));
final String f = myContext.getValue(sourceFileName);
debug("Affecting file due to local overriding: ", f);
affectedFiles.add(new File(f));
}
}
}
}
}
}
debug("End of added methods processing");
debug("Processing removed methods:");
for (MethodRepr m : diff.methods().removed()) {
debug("Method ", m.name);
final Collection<Pair<MethodRepr, ClassRepr>> overridenMethods = u.findOverridenMethods(m, it);
final Collection<DependencyContext.S> propagated = u.propagateMethodAccess(m.name, it.name);
if (overridenMethods.size() == 0) {
debug("No overridden methods found, affecting method usages");
u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), affectedUsages, dependants);
}
else {
@@ -1006,6 +1072,7 @@ public class Mappings {
}
if (!clear) {
debug("No clearly overridden methods found, affecting method usages");
u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), affectedUsages, dependants);
}
}
@@ -1046,21 +1113,31 @@ public class Mappings {
final DependencyContext.S source = myClassToSourceFile.get(p);
if (source != null) {
affectedFiles.add(new File(myContext.getValue(source)));
final String f = myContext.getValue(source);
debug(
"Removed method is not abstract & is overrides some abstract method which is not then over-overriden in subclass ",
p);
debug("Affecting subclass source file ", f);
affectedFiles.add(new File(f));
}
}
}
}
}
}
debug("End of removed methods processing");
debug("Processing changed methods:");
for (Pair<MethodRepr, Difference> mr : diff.methods().changed()) {
final MethodRepr m = mr.first;
final MethodRepr.Diff d = (MethodRepr.Diff)mr.second;
final boolean throwsChanged = (d.exceptions().added().size() > 0) || (d.exceptions().changed().size() > 0);
debug("Method: ", m.name);
if (it.isAnnotation()) {
if (d.defaultRemoved()) {
debug("Class is annotation, default value is removed => adding annotation query");
final List<DependencyContext.S> l = new LinkedList<DependencyContext.S>();
l.add(m.name);
annotationQuery.add((UsageRepr.AnnotationUsage)UsageRepr
@@ -1076,6 +1153,7 @@ public class Mappings {
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>();
if (d.packageLocalOn()) {
debug("Method became package-local, affecting method usages outside the package");
u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants);
for (UsageRepr.Usage usage : usages) {
@@ -1089,6 +1167,7 @@ public class Mappings {
if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0 || throwsChanged) {
if (!affected) {
debug("Return type, throws list or signature changed --- affecting method usages");
u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants);
affectedUsages.addAll(usages);
}
@@ -1098,11 +1177,13 @@ public class Mappings {
(d.removedModifiers() & Opcodes.ACC_STATIC) > 0 ||
(d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0) {
if (!affected) {
debug("Added static or private specifier or removed static specifier --- affecting method usages");
u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants);
affectedUsages.addAll(usages);
}
if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0) {
debug("Added static specifier --- affecting subclasses");
u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
}
@@ -1110,11 +1191,13 @@ public class Mappings {
if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0 ||
(d.addedModifiers() & Opcodes.ACC_PUBLIC) > 0 ||
(d.addedModifiers() & Opcodes.ACC_ABSTRACT) > 0) {
debug("Added final, public or abstract specifier --- affecting subclasses");
u.affectSubclasses(it.name, affectedFiles, affectedUsages, dependants, false);
}
if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0 && !((d.removedModifiers() & Opcodes.ACC_PRIVATE) > 0)) {
if (!constrained) {
debug("Added public or package-local method became protected --- affect method usages with protected constraint");
if (!affected) {
u.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, dependants);
affectedUsages.addAll(usages);
@@ -1129,10 +1212,14 @@ public class Mappings {
}
}
}
debug("End of changed methods processing");
final int mask = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
debug("Processing added fields");
for (FieldRepr f : diff.fields().added()) {
debug("Field: ", f.name);
final boolean fPrivate = (f.access & Opcodes.ACC_PRIVATE) > 0;
final boolean fProtected = (f.access & Opcodes.ACC_PROTECTED) > 0;
final boolean fPublic = (f.access & Opcodes.ACC_PUBLIC) > 0;
@@ -1141,32 +1228,34 @@ public class Mappings {
if (!fPrivate) {
final Collection<DependencyContext.S> subClasses = getAllSubclasses(it.name);
if (subClasses != null) {
for (final DependencyContext.S subClass : subClasses) {
final ClassRepr r = u.reprByName(subClass);
final DependencyContext.S sourceFileName = myClassToSourceFile.get(subClass);
for (final DependencyContext.S subClass : subClasses) {
final ClassRepr r = u.reprByName(subClass);
final DependencyContext.S sourceFileName = myClassToSourceFile.get(subClass);
if (r != null && sourceFileName != null) {
if (r.isLocal) {
if (r != null && sourceFileName != null) {
if (r.isLocal) {
debug("Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ",
sourceFileName);
affectedFiles.add(new File(myContext.getValue(sourceFileName)));
}
else {
final DependencyContext.S outerClass = r.outerClassName;
if (!empty(outerClass) && u.fieldVisible(outerClass, f)) {
debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", sourceFileName);
affectedFiles.add(new File(myContext.getValue(sourceFileName)));
}
else {
final DependencyContext.S outerClass = r.outerClassName;
if (!empty(outerClass) && u.fieldVisible(outerClass, f)) {
affectedFiles.add(new File(myContext.getValue(sourceFileName)));
}
}
}
}
final Collection<DependencyContext.S> propagated = u.propagateFieldAccess(f.name, subClass);
u.affectFieldUsages(f, propagated, f.createUsage(myContext, subClass), affectedUsages, dependants);
debug("Affecting field usages referenced from subclass ", subClass);
final Collection<DependencyContext.S> propagated = u.propagateFieldAccess(f.name, subClass);
u.affectFieldUsages(f, propagated, f.createUsage(myContext, subClass), affectedUsages, dependants);
final Collection<DependencyContext.S> deps = myClassToClassDependency.get(subClass);
final Collection<DependencyContext.S> deps = myClassToClassDependency.get(subClass);
if (deps != null) {
dependants.addAll(deps);
}
if (deps != null) {
dependants.addAll(deps);
}
}
}
@@ -1186,6 +1275,7 @@ public class Mappings {
final Collection<DependencyContext.S> propagated = o.propagateFieldAccess(ff.name, cc.name);
final Set<UsageRepr.Usage> localUsages = new HashSet<UsageRepr.Usage>();
debug("Affecting usages of overridden field in class ", cc.name);
u.affectFieldUsages(ff, propagated, ff.createUsage(myContext, cc.name), localUsages, dependants);
if (fPrivate || (fPublic && (ffPublic || ffPLocal)) || (fProtected && ffProtected) || (fPLocal && ffPLocal)) {
@@ -1214,16 +1304,16 @@ public class Mappings {
}
}
}
debug("End of added fields processing");
debug("Processing removed fields");
debug("Processing removed fields:");
for (FieldRepr f : diff.fields().removed()) {
debug("Field ");
debug(f.name);
debug("Field: ", it.name);
if ((f.access & Opcodes.ACC_PRIVATE) == 0 && (f.access & mask) == mask && f.hasValue()) {
debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested");
if (!incrementalDecision(it.name, f, affectedFiles)) {
debug("End of Differentiate, returning false");
return false;
}
}
@@ -1231,20 +1321,20 @@ public class Mappings {
final Collection<DependencyContext.S> propagated = u.propagateFieldAccess(f.name, it.name);
u.affectFieldUsages(f, propagated, f.createUsage(myContext, it.name), affectedUsages, dependants);
}
debug("End of removed fields processing");
debug("Processing changed fields");
debug("Processing changed fields:");
for (Pair<FieldRepr, Difference> f : diff.fields().changed()) {
final Difference d = f.second;
final FieldRepr field = f.first;
debug("Field ");
debug(field.name);
debug("Field: ", it.name);
if ((field.access & Opcodes.ACC_PRIVATE) == 0 && (field.access & mask) == mask) {
if ((d.base() & Difference.ACCESS) > 0 || (d.base() & Difference.VALUE) > 0) {
debug("Inline field changed it's access or value => a switch to non-incremental mode requested");
if (!incrementalDecision(it.name, field, affectedFiles)){
if (!incrementalDecision(it.name, field, affectedFiles)) {
debug("End of Differentiate, returning false");
return false;
}
}
@@ -1254,6 +1344,7 @@ public class Mappings {
final Collection<DependencyContext.S> propagated = u.propagateFieldAccess(field.name, it.name);
if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0) {
debug("Type or signature changed --- affecting field usages");
u.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), affectedUsages, dependants);
}
else if ((d.base() & Difference.ACCESS) > 0) {
@@ -1261,7 +1352,7 @@ public class Mappings {
(d.removedModifiers() & Opcodes.ACC_STATIC) > 0 ||
(d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0 ||
(d.addedModifiers() & Opcodes.ACC_VOLATILE) > 0) {
debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages");
u.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), affectedUsages, dependants);
}
else {
@@ -1269,12 +1360,14 @@ public class Mappings {
final Set<UsageRepr.Usage> usages = new HashSet<UsageRepr.Usage>();
if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0) {
debug("Added final modifier --- affecting field assign usages");
u.affectFieldUsages(field, propagated, field.createAssignUsage(myContext, it.name), usages, dependants);
affectedUsages.addAll(usages);
affected = true;
}
if ((d.removedModifiers() & Opcodes.ACC_PUBLIC) > 0) {
debug("Removed public modifier, affecting field usages with appropriate constraint");
if (!affected) {
u.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), usages, dependants);
affectedUsages.addAll(usages);
@@ -1293,12 +1386,18 @@ public class Mappings {
}
}
}
debug("End of changed fields processing");
}
debug("End of changed classes processing");
debug("Processing removed classes:");
for (ClassRepr c : classDiff.removed()) {
debug("Adding usages of class ", c.name);
affectedUsages.add(c.createUsage());
}
debug("End of removed classes processing.");
debug("Processing added classes:");
for (ClassRepr c : classDiff.added()) {
final Collection<DependencyContext.S> depClasses = myClassToClassDependency.get(c.name);
@@ -1307,12 +1406,16 @@ public class Mappings {
final DependencyContext.S fName = myClassToSourceFile.get(depClass);
if (fName != null) {
affectedFiles.add(new File(myContext.getValue(fName)));
final String f = myContext.getValue(fName);
debug("Adding dependent file ", f);
affectedFiles.add(new File(f));
}
}
}
}
debug("End of added classes processing.");
debug("Checking dependent files:");
if (dependants != null) {
final Set<DependencyContext.S> dependentFiles = new HashSet<DependencyContext.S>();
@@ -1332,6 +1435,8 @@ public class Mappings {
continue filewise;
}
debug("Dependent file: ", depFile);
final Collection<UsageRepr.Cluster> depClusters = mySourceFileToUsages.get(depFile);
for (UsageRepr.Cluster depCluster : depClusters) {
@@ -1347,6 +1452,7 @@ public class Mappings {
final Util.UsageConstraint constraint = usageConstraints.get(usage);
if (constraint == null) {
debug("Added file with no constraints");
affectedFiles.add(theFile);
continue filewise;
}
@@ -1354,6 +1460,7 @@ public class Mappings {
final Set<DependencyContext.S> residenceClasses = depCluster.getResidence(usage);
for (DependencyContext.S residentName : residenceClasses) {
if (constraint.checkResidence(residentName)) {
debug("Added file with satisfied constraint");
affectedFiles.add(theFile);
continue filewise;
}
@@ -1369,6 +1476,7 @@ public class Mappings {
for (UsageRepr.Usage usage : annotationUsages) {
for (UsageRepr.AnnotationUsage query : annotationQuery) {
if (query.satisfies(usage)) {
debug("Added file due to annotation query");
affectedFiles.add(theFile);
continue filewise;
}
@@ -1381,6 +1489,13 @@ public class Mappings {
}
}
if (removed != null) {
for (String r : removed) {
affectedFiles.remove(new File(r));
}
}
debug("End of Differentiate, returning true");
return true;
}
@@ -1425,7 +1540,6 @@ public class Mappings {
}
}
myClassToSubclasses.putAll(delta.myClassToSubclasses);
mySourceFileToClasses.putAll(delta.mySourceFileToClasses);
mySourceFileToUsages.putAll(delta.mySourceFileToUsages);
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -44,5 +44,5 @@ xmlrpc-2.0.jar
xpp3-1.1.4-min.jar
xstream.jar
swingx-core-1.6.2.jar
netty-3.2.5.Final.jar
netty-3.3.0.Final.jar
protobuf-2.3.0.jar
Binary file not shown.
Binary file not shown.
@@ -17,7 +17,6 @@
package com.intellij.execution.ui.actions;
import com.intellij.execution.ui.layout.Grid;
import com.intellij.execution.ui.layout.GridCell;
import com.intellij.execution.ui.layout.Tab;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -74,11 +73,6 @@ public abstract class BaseViewAction extends DumbAwareAction {
return e.getData(ViewContext.CONTENT_KEY);
}
protected static boolean isDetached(ViewContext context, Content content) {
final GridCell cell = context.findCellFor(content);
return cell != null && cell.isDetached();
}
@Nullable
protected static Tab getTabFor(final ViewContext context, final Content[] content) {
Grid grid = context.findGridFor(content[0]);
@@ -72,12 +72,6 @@ public interface CellTransform {
interface Facade {
void minimize(Content content, Restore restore);
void moveToTab(final Content content);
void moveToGrid(final Content content);
Restore detach(final Content[] content);
}
}
@@ -16,17 +16,10 @@
package com.intellij.execution.ui.layout;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.ui.content.Content;
public interface GridCell {
boolean isDetached();
int getContentCount();
void attach();
void minimize(final Content content);
ActionCallback detach();
}
@@ -22,6 +22,7 @@ public interface Tab {
void setDetached(final PlaceInGrid placeInGrid, final boolean detached);
int getIndex();
int getDefaultIndex();
boolean isDetached(final PlaceInGrid placeInGrid);
}
@@ -32,4 +32,8 @@ public interface View {
void assignTab(Tab tab);
void setTabIndex(int tabIndex);
int getWindow();
void setWindow(int windowNumber);
}
@@ -51,29 +51,29 @@ public class DefaultWordsScanner implements WordsScanner {
public void processWords(CharSequence fileText, Processor<WordOccurrence> processor) {
myLexer.start(fileText);
WordOccurrence occurence = null; // shared occurence
WordOccurrence occurrence = null; // shared occurrence
while (myLexer.getTokenType() != null) {
final IElementType type = myLexer.getTokenType();
if (myIdentifierTokenSet.contains(type)) {
if (occurence == null) {
occurence = new WordOccurrence(fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE);
if (occurrence == null) {
occurrence = new WordOccurrence(fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE);
}
else {
occurence.init(fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE);
occurrence.init(fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE);
}
if (!processor.process(occurence)) return;
if (!processor.process(occurrence)) return;
}
else if (myCommentTokenSet.contains(type)) {
if (!stripWords(processor, fileText,myLexer.getTokenStart(),myLexer.getTokenEnd(), WordOccurrence.Kind.COMMENTS,occurence, false)) return;
if (!stripWords(processor, fileText,myLexer.getTokenStart(),myLexer.getTokenEnd(), WordOccurrence.Kind.COMMENTS,occurrence, false)) return;
}
else if (myLiteralTokenSet.contains(type)) {
if (!stripWords(processor, fileText, myLexer.getTokenStart(),myLexer.getTokenEnd(),WordOccurrence.Kind.LITERALS,occurence, myMayHaveFileRefsInLiterals)) return;
if (!stripWords(processor, fileText, myLexer.getTokenStart(),myLexer.getTokenEnd(),WordOccurrence.Kind.LITERALS,occurrence, myMayHaveFileRefsInLiterals)) return;
}
else {
// process all word-like characters as words
// Plugin writers may have (Maximka in JavaScript especially) some keyword token types omitted from the identifierTokenSet
if (!stripWords(processor, fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE, occurence, false)) return;
if (!stripWords(processor, fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE, occurrence, false)) return;
}
myLexer.advance();
}
@@ -268,10 +268,14 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
myScrollPane.setViewportBorder(JBScrollPane.createIndentBorder());
final DefaultActionGroup actions = new DefaultActionGroup();
actions.add(new BackAction());
actions.add(new ForwardAction());
final BackAction back = new BackAction();
final ForwardAction forward = new ForwardAction();
actions.add(back);
actions.add(forward);
actions.add(myExternalDocAction = new ExternalDocAction());
back.registerCustomShortcutSet(CustomShortcutSet.fromString("LEFT"), this);
forward.registerCustomShortcutSet(CustomShortcutSet.fromString("RIGHT"), this);
myExternalDocAction.registerCustomShortcutSet(CustomShortcutSet.fromString("UP"), this);
if (additionalActions != null) {
for (final AnAction action : additionalActions) {
actions.add(action);
@@ -35,6 +35,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.docking.DockManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -76,7 +77,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom
public RunContentManager getContentManager() {
if (myContentManager == null) {
myContentManager = new RunContentManagerImpl(myProject);
myContentManager = new RunContentManagerImpl(myProject, DockManager.getInstance(myProject));
Disposer.register(myProject, myContentManager);
}
return myContentManager;
@@ -23,6 +23,7 @@ import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.GenericProgramRunner;
import com.intellij.execution.ui.layout.impl.DockableGridContainerFactory;
import com.intellij.ide.DataManager;
import com.intellij.ide.impl.ContentManagerWatcher;
import com.intellij.openapi.Disposable;
@@ -47,6 +48,7 @@ import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter;
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
import com.intellij.ui.content.*;
import com.intellij.ui.docking.DockManager;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
@@ -65,13 +67,17 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
private static final Key<RunContentDescriptor> DESCRIPTOR_KEY = new Key<RunContentDescriptor>("Descriptor");
private final Project myProject;
private DockableGridContainerFactory myContentFactory;
private final Map<String, ContentManager> myToolwindowIdToContentManagerMap = new HashMap<String, ContentManager>();
private final Map<RunContentListener, Disposable> myListeners = new HashMap<RunContentListener, Disposable>();
private final LinkedList<String> myToolwindowIdZbuffer = new LinkedList<String>();
public RunContentManagerImpl(Project project) {
public RunContentManagerImpl(Project project, DockManager dockManager) {
myProject = project;
myContentFactory = new DockableGridContainerFactory();
dockManager.register(DockableGridContainerFactory.TYPE, myContentFactory);
Disposer.register(myProject, myContentFactory);
}
public void init() {
@@ -1,51 +0,0 @@
/*
* Copyright 2000-2009 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.execution.ui.layout.actions;
import com.intellij.execution.ui.actions.BaseViewAction;
import com.intellij.execution.ui.layout.Grid;
import com.intellij.execution.ui.layout.GridCell;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.ui.content.Content;
public class AttachCellAction extends BaseViewAction {
protected void update(final AnActionEvent e, final ViewContext context, final Content[] content) {
if (content.length == 0 || !isDetached(context, content[0])) {
setEnabled(e, false);
return;
}
Grid grid = context.findGridFor(content[0]);
GridCell cell = grid.getCellFor(content[0]);
if (ViewContext.CELL_TOOLBAR_PLACE.equals(e.getPlace()) && content.length == 1) {
setEnabled(e, cell.getContentCount() == 1);
} else {
setEnabled(e, true);
if (cell.getContentCount() > 1) {
e.getPresentation().setText(ActionsBundle.message("action.Runner.AttachCells.text", cell.getContentCount()));
}
}
}
protected void actionPerformed(final AnActionEvent e, final ViewContext context, final Content[] content) {
context.findCellFor(content[0]).attach();
}
}
@@ -19,11 +19,19 @@ package com.intellij.execution.ui.layout.actions;
import com.intellij.execution.ui.actions.BaseViewAction;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.content.Content;
import javax.swing.*;
public class CloseViewAction extends BaseViewAction {
private static final Icon ICON = IconLoader.getIcon("/actions/closeNew.png");
private static final Icon HOVERED_ICON = IconLoader.getIcon("/actions/closeNewHovered.png");
protected void update(final AnActionEvent e, final ViewContext context, final Content[] content) {
setEnabled(e, isEnabled(context, content, e.getPlace()));
e.getPresentation().setIcon(ICON);
e.getPresentation().setHoveredIcon(HOVERED_ICON);
}
protected void actionPerformed(final AnActionEvent e, final ViewContext context, final Content[] content) {
@@ -1,59 +0,0 @@
/*
* Copyright 2000-2009 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.execution.ui.layout.actions;
import com.intellij.execution.ui.actions.BaseViewAction;
import com.intellij.execution.ui.layout.Grid;
import com.intellij.execution.ui.layout.GridCell;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.ui.content.Content;
public class DetachCellAction extends BaseViewAction {
protected void update(final AnActionEvent e, final ViewContext context, final Content[] content) {
if (content.length == 0 || isDetached(context, content[0])) {
setEnabled(e, false);
return;
}
Grid grid = context.findGridFor(content[0]);
if (grid == null) {
setEnabled(e, false);
return;
}
if (ViewContext.TAB_TOOLBAR_PLACE.equals(e.getPlace()) || (ViewContext.TAB_POPUP_PLACE.equals(e.getPlace()))) {
setEnabled(e, grid.getContents().size() == 1);
}
else {
GridCell cell = grid.getCellFor(content[0]);
if (ViewContext.CELL_TOOLBAR_PLACE.equals(e.getPlace()) && content.length == 1) {
setEnabled(e, cell.getContentCount() == 1);
} else {
setEnabled(e, true);
if (cell.getContentCount() > 1) {
e.getPresentation().setText(ActionsBundle.message("action.Runner.DetachCells.text", cell.getContentCount()));
}
}
}
}
protected void actionPerformed(final AnActionEvent e, final ViewContext context, final Content[] content) {
context.findCellFor(content[0]).detach();
}
}
@@ -39,19 +39,15 @@ public class MinimizeViewAction extends BaseViewAction {
return false;
}
if (isDetached(context, content[0])) {
return false;
}
if (ViewContext.TAB_TOOLBAR_PLACE.equals(place) || ViewContext.TAB_POPUP_PLACE.equals(place)) {
return false;
}
else {
Tab tab = getTabFor(context, content);
if (tab == null) {
return false;
}
return tab.isDefault();
return !tab.isDefault();
}
else {
return getTabFor(context, content) != null;
}
}
}
@@ -1,50 +0,0 @@
/*
* Copyright 2000-2009 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.execution.ui.layout.actions;
import com.intellij.execution.ui.actions.BaseViewAction;
import com.intellij.execution.ui.layout.Grid;
import com.intellij.execution.ui.layout.Tab;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.ui.content.Content;
public class MoveToGridAction extends BaseViewAction {
protected void update(final AnActionEvent e, final ViewContext context, final Content[] content) {
if (!context.isMoveToGridActionEnabled() || content.length != 1) {
setEnabled(e, false);
return;
}
if (isDetached(context, content[0])) {
setEnabled(e, false);
return;
}
Grid grid = context.findGridFor(content[0]);
if (grid == null) {
setEnabled(e, false);
return;
}
Tab tab = context.getTabFor(grid);
setEnabled(e, tab != null && !tab.isDefault() && grid.getContents().size() == 1);
}
protected void actionPerformed(final AnActionEvent e, final ViewContext context, final Content[] content) {
context.getCellTransform().moveToGrid(content[0]);
}
}
@@ -1,56 +0,0 @@
/*
* Copyright 2000-2009 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.execution.ui.layout.actions;
import com.intellij.execution.ui.actions.BaseViewAction;
import com.intellij.execution.ui.layout.Grid;
import com.intellij.execution.ui.layout.Tab;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.ui.content.Content;
public class MoveToTabAction extends BaseViewAction {
protected void update(final AnActionEvent e, final ViewContext context, final Content[] content) {
if (!context.isMoveToGridActionEnabled() || content.length != 1) {
setEnabled(e, false);
return;
}
if (isDetached(context, content[0])) {
setEnabled(e, false);
return;
}
Grid grid = context.findGridFor(content[0]);
if (grid == null) {
setEnabled(e, false);
return;
}
Tab tab = context.getTabFor(grid);
if (ViewContext.TAB_TOOLBAR_PLACE.equals(e.getPlace())) {
setEnabled(e, false);
} else {
setEnabled(e, tab != null && tab.isDefault());
}
}
protected void actionPerformed(final AnActionEvent e, final ViewContext context, final Content[] content) {
context.getCellTransform().moveToTab(content[0]);
}
}
@@ -21,6 +21,7 @@ import javax.swing.*;
abstract class AbstractTab {
int myIndex;
int myDefaultIndex = -1;
String myDisplayName;
Icon myIcon;
@@ -38,6 +39,7 @@ abstract class AbstractTab {
void copyFrom(final AbstractTab from) {
myIndex = from.myIndex;
myDefaultIndex = from.myDefaultIndex;
myDisplayName = from.myDisplayName;
myIcon = from.myIcon;
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.ui.layout.impl;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockContainerFactory;
import com.intellij.ui.docking.DockableContent;
/**
* @author Dennis.Ushakov
*/
public class DockableGridContainerFactory implements DockContainerFactory {
public static final String TYPE = "runner-grid";
@Override
public DockContainer createContainer(DockableContent content) {
final RunnerContentUi.DockableGrid dockableGrid = (RunnerContentUi.DockableGrid)content;
return new RunnerContentUi(dockableGrid.getRunnerUi(), dockableGrid.getOriginalRunnerUi(), dockableGrid.getWindow());
}
@Override
public void dispose() {}
}
@@ -18,18 +18,16 @@ package com.intellij.execution.ui.layout.impl;
import com.intellij.execution.ui.layout.*;
import com.intellij.execution.ui.layout.actions.MinimizeViewAction;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.*;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.DimensionService;
import com.intellij.openapi.util.MutualMap;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.content.Content;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.switcher.SwitchTarget;
import com.intellij.ui.tabs.JBTabs;
import com.intellij.ui.tabs.TabInfo;
@@ -43,15 +41,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class GridCellImpl implements GridCell, Disposable {
public class GridCellImpl implements GridCell {
private final GridImpl myContainer;
private final MutualMap<Content, TabInfo> myContents = new MutualMap<Content, TabInfo>(true);
@@ -62,16 +59,12 @@ public class GridCellImpl implements GridCell, Disposable {
private final PlaceInGrid myPlaceInGrid;
private final ViewContextEx myContext;
private CellTransform.Restore.List myRestoreFromDetach;
private JBPopup myPopup;
private boolean myDisposed;
public GridCellImpl(ViewContextEx context, @NotNull GridImpl container, GridImpl.Placeholder placeholder, PlaceInGrid placeInGrid) {
myContext = context;
myContainer = container;
Disposer.register(container, this);
myPlaceInGrid = placeInGrid;
myPlaceholder = placeholder;
myTabs = new JBTabsImpl(myContext.getProject(), myContext.getActionManager(), myContext.getFocusManager(), container).setDataProvider(new DataProvider() {
@@ -97,23 +90,17 @@ public class GridCellImpl implements GridCell, Disposable {
}
}).setSideComponentVertical(!context.getLayoutSettings().isToolbarHorizontal())
.setStealthTabMode(true)
.setFocusCycle(false).setPaintFocus(true).setProvideSwitchTargets(false);
.setFocusCycle(false).setPaintFocus(true).setProvideSwitchTargets(false).setTabDraggingEnabled(true);
myTabs.addTabMouseListener(new MouseAdapter() {
public void mousePressed(final MouseEvent e) {
if (UIUtil.isCloseClick(e)) {
if (isDetached()) {
myPopup.cancel();
myPopup = null;
}
else {
minimize(e);
}
}
}
});
rebuildPopupGroup();
myTabs.addListener(new TabsListener() {
myTabs.addListener(new TabsListener.Adapter() {
public void beforeSelectionChanged(TabInfo oldSelection, TabInfo newSelection) {
if (oldSelection != null && myContext.isStateBeingRestored()) {
@@ -181,7 +168,7 @@ public class GridCellImpl implements GridCell, Disposable {
}
}
else {
if (myPlaceholder.isNull() && !isDetached()) {
if (myPlaceholder.isNull()) {
myPlaceholder.setContent(myTabs.getComponent());
}
@@ -211,7 +198,7 @@ public class GridCellImpl implements GridCell, Disposable {
ActionGroup group = (ActionGroup)myContext.getActionManager().getAction(RunnerContentUi.VIEW_TOOLBAR);
tabInfo.setTabLabelActions(group, ViewContext.CELL_TOOLBAR_PLACE);
tabInfo.setDragOutDelegate(((RunnerContentUi)myContext).myDragOutDelegate);
return tabInfo;
}
@@ -248,7 +235,7 @@ public class GridCellImpl implements GridCell, Disposable {
return myMinimizedContents.contains(content);
}
public java.util.List<SwitchTarget> getTargets(boolean onlyVisible) {
public List<SwitchTarget> getTargets(boolean onlyVisible) {
if (myTabs.getPresentation().isHideTabs()) return new ArrayList<SwitchTarget>();
return myTabs.getTargets(onlyVisible, false);
@@ -287,7 +274,7 @@ public class GridCellImpl implements GridCell, Disposable {
}
@Nullable
private TabInfo getTabFor(Content content) {
TabInfo getTabFor(Content content) {
return myContents.getValue(content);
}
@@ -306,14 +293,21 @@ public class GridCellImpl implements GridCell, Disposable {
restoreProportions();
Content[] contents = getContents();
int window = 0;
for (Content each : contents) {
if (myContainer.getStateFor(each).isMinimizedInGrid()) {
final View view = myContainer.getStateFor(each);
if (view.isMinimizedInGrid()) {
minimize(each);
}
window = view.getWindow();
}
if (!isRestoringFromDetach() && myContainer.getTab().isDetached(myPlaceInGrid) && contents.length > 0) {
_detach(!myContext.isStateBeingRestored()).notifyWhenDone(result);
final Tab tab = myContainer.getTab();
final boolean detached = (tab != null && tab.isDetached(myPlaceInGrid)) || window != myContext.getWindow();
if (detached && contents.length > 0) {
if (tab != null) {
tab.setDetached(myPlaceInGrid, false);
}
myContext.detachTo(window, this).notifyWhenDone(result);
} else {
result.setDone();
}
@@ -321,7 +315,7 @@ public class GridCellImpl implements GridCell, Disposable {
return result;
}
private Content[] getContents() {
Content[] getContents() {
return myContents.getKeys().toArray(new Content[myContents.size()]);
}
@@ -339,6 +333,14 @@ public class GridCellImpl implements GridCell, Disposable {
for (Content each : myMinimizedContents) {
saveState(each, true);
}
final DimensionService service = DimensionService.getInstance();
final Dimension size = myContext.getContentManager().getComponent().getSize();
service.setSize(getDimensionKey(), size, myContext.getProject());
if (myContext.getWindow() != 0) {
final JFrame frame = (JFrame)DockManager.getInstance(myContext.getProject()).getIdeFrame((DockContainer)myContext);
service.setLocation(getDimensionKey(), frame.getLocationOnScreen());
}
}
public void saveProportions() {
@@ -350,8 +352,7 @@ public class GridCellImpl implements GridCell, Disposable {
state.setMinimizedInGrid(minimized);
state.setPlaceInGrid(myPlaceInGrid);
state.assignTab(myContainer.getTabIndex());
state.getTab().setDetached(myPlaceInGrid, isDetached());
state.setWindow(myContext.getWindow());
}
public void restoreProportions() {
@@ -362,7 +363,7 @@ public class GridCellImpl implements GridCell, Disposable {
for (Content each : myContents.getKeys()) {
final TabInfo eachTab = getTabFor(each);
boolean isSelected = eachTab != null && myTabs.getSelectedInfo() == eachTab;
if (isSelected && (isShowing || isDetached())) {
if (isSelected && isShowing) {
myContext.getContentManager().addSelectedContent(each);
}
else {
@@ -391,147 +392,22 @@ public class GridCellImpl implements GridCell, Disposable {
}
}
public ActionCallback detach() {
return _detach(true);
@Nullable
public Point getLocation() {
return DimensionService.getInstance().getLocation(getDimensionKey(), myContext.getProject());
}
private ActionCallback _detach(final boolean requestFocus) {
myContext.saveUiState();
final DimensionService dimService = DimensionService.getInstance();
Point storedLocation = dimService.getLocation(getDimensionKey(), myContext.getProject());
Dimension storedSize = dimService.getSize(getDimensionKey(), myContext.getProject());
final IdeFrame frame = WindowManager.getInstance().getIdeFrame(myContext.getProject());
final Rectangle targetBounds = frame.suggestChildFrameBounds();
if (storedLocation != null && storedSize != null) {
targetBounds.setLocation(storedLocation);
targetBounds.setSize(storedSize);
}
final ActionCallback result = new ActionCallback();
if (storedLocation == null || storedSize == null) {
if (myContents.size() > 0) {
myContext.validate(myContents.getKeys().iterator().next(), new ActiveRunnable() {
public ActionCallback run() {
if (!myTabs.getComponent().isShowing()) {
detachTo(targetBounds.getLocation(), targetBounds.getSize(), false, requestFocus).notifyWhenDone(result);
} else {
detachForShowingTabs(requestFocus).notifyWhenDone(result);
}
return new ActionCallback.Done();
}
});
return result;
}
}
detachTo(targetBounds.getLocation(), targetBounds.getSize(), false, requestFocus).notifyWhenDone(result);
return result;
@Nullable
public Dimension getSize() {
return DimensionService.getInstance().getSize(getDimensionKey(), myContext.getProject());
}
private ActionCallback detachForShowingTabs(boolean requestFocus) {
return detachTo(myTabs.getComponent().getLocationOnScreen(), myTabs.getComponent().getSize(), false, requestFocus);
}
private ActionCallback detachTo(Point screenPoint, Dimension size, boolean dragging, final boolean requestFocus) {
if (isDetached()) {
if (myPopup != null) {
return new ActionCallback.Done();
}
}
final Content[] contents = getContents();
myRestoreFromDetach = new CellTransform.Restore.List();
myRestoreFromDetach.add(myPlaceholder.detach());
myRestoreFromDetach.add(myContainer.detach(contents));
myRestoreFromDetach.add(new CellTransform.Restore() {
public ActionCallback restoreInGrid() {
ensureVisible();
return new ActionCallback.Done();
}
});
myPopup = createPopup(dragging, requestFocus);
myPopup.setSize(size);
myPopup.setLocation(screenPoint);
myPopup.show(myContext.getContentManager().getComponent());
myContext.saveUiState();
myTabs.updateTabActions(true);
return new ActionCallback.Done();
}
private void ensureVisible() {
if (myTabs.getSelectedInfo() != null) {
myContext.select(getContentFor(myTabs.getSelectedInfo()), true);
}
}
private JBPopup createPopup(boolean dragging, final boolean requestFocus) {
Wrapper wrapper = new Wrapper(myTabs.getComponent());
wrapper.setBorder(new EmptyBorder(1, 0, 0, 0));
final ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(wrapper, myTabs.getComponent())
.setTitle(myContainer.getSessionName())
.setMovable(true)
.setRequestFocus(requestFocus)
.setFocusable(true)
.setResizable(true)
.setDimensionServiceKey(myContext.getProject(), getDimensionKey(), true)
.setCancelOnOtherWindowOpen(false)
.setCancelOnClickOutside(false)
.setCancelKeyEnabled(true)
.setLocateByContent(dragging)
.setLocateWithinScreenBounds(!dragging)
.setCancelKeyEnabled(false)
.setBelongsToGlobalPopupStack(false)
.setModalContext(false)
.setCancelCallback(new Computable<Boolean>() {
public Boolean compute() {
if (myDisposed || myContents.size() == 0) return Boolean.TRUE;
myRestoreFromDetach.restoreInGrid();
myRestoreFromDetach = null;
myContext.saveUiState();
myTabs.updateTabActions(true);
return Boolean.TRUE;
}
});
return builder.createPopup();
}
public void attach() {
if (isDetached()) {
myPopup.cancel();
myPopup = null;
}
}
public boolean isDetached() {
return myRestoreFromDetach != null && !myRestoreFromDetach.isRestoringNow();
}
public boolean isRestoringFromDetach() {
return myRestoreFromDetach != null && myRestoreFromDetach.isRestoringNow();
}
private String getDimensionKey() {
return "GridCell.Tab." + myContainer.getTab().getIndex() + "." + myPlaceInGrid.name();
}
public boolean isValidForCalculatePropertions() {
return !isDetached() && getContentCount() > 0;
public boolean isValidForCalculateProportions() {
return getContentCount() > 0;
}
public void minimize(Content content) {
@@ -553,13 +429,4 @@ public class GridCellImpl implements GridCell, Disposable {
updateSelection(myTabs.getComponent().getRootPane() != null);
return new ActionCallback.Done();
}
public void dispose() {
myDisposed = true;
if (myPopup != null) {
myPopup.cancel();
myPopup = null;
}
}
}
@@ -35,7 +35,7 @@ import java.awt.*;
import java.util.*;
import java.util.List;
public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform.Facade, DataProvider {
public class GridImpl extends Wrapper implements Grid, Disposable, DataProvider {
private final ThreeComponentsSplitter myTopSplit = new ThreeComponentsSplitter();
private final Splitter mySplitter = new Splitter(true);
@@ -152,8 +152,7 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
public boolean updateGridUI() {
for (final GridCellImpl cell : myPlaceInGrid2Cell.values()) {
final boolean eachToHide = myContents.size() == 1 && !cell.isDetached();
cell.setHideTabs(eachToHide);
cell.setHideTabs(myContents.size() == 1);
}
final Content onlyContent = myContents.get(0);
@@ -252,7 +251,7 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
final GridCellImpl cell = myPlaceInGrid2Cell.get(placeInGrid);
if (!cell.isValidForCalculatePropertions()) return;
if (!cell.isValidForCalculateProportions()) return;
final TabImpl tab = (TabImpl)getTab();
@@ -335,19 +334,12 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
ArrayList<Content> result = new ArrayList<Content>();
for (Content each : getContents()) {
if (!isDetached(each)) {
result.add(each);
}
result.add(each);
}
return result;
}
public boolean isDetached(Content content) {
return getCellFor(content).isDetached();
}
public List<Content> getContents() {
return myContents;
}
@@ -360,28 +352,6 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
});
}
public void moveToTab(final Content content) {
myViewContext.getCellTransform().moveToTab(content);
}
public void moveToGrid(final Content content) {
myViewContext.getCellTransform().moveToGrid(content);
}
public CellTransform.Restore detach(final Content[] content) {
final CellTransform.Restore.List restore = new CellTransform.Restore.List();
restore.add(myViewContext.getCellTransform().detach(content));
restore.add(new CellTransform.Restore() {
public ActionCallback restoreInGrid() {
revalidate();
repaint();
return new ActionCallback.Done();
}
});
return restore;
}
@Nullable
public Object getData(@NonNls final String dataId) {
if (ViewContext.CONTEXT_KEY.is(dataId)) {
@@ -394,10 +364,6 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
return null;
}
public String getSessionName() {
return mySessionName;
}
@Nullable
public SwitchTarget getCellFor(Component c) {
Component eachParent = c;
@@ -419,9 +385,7 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
Collection<GridCellImpl> cells = myPlaceInGrid2Cell.values();
ArrayList<SwitchTarget> result = new ArrayList<SwitchTarget>();
for (GridCellImpl each : cells) {
if (!each.isDetached()) {
result.addAll(each.getTargets(onlyVisible));
}
result.addAll(each.getTargets(onlyVisible));
}
return result;
}
@@ -0,0 +1,276 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.ui.layout.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.Gray;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.ui.tabs.impl.TabLabel;
import com.intellij.util.ui.SameColor;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.util.List;
import java.util.Map;
/**
* @author Dennis.Ushakov
*/
public class
JBRunnerTabs extends JBTabsImpl {
public JBRunnerTabs(@Nullable Project project, ActionManager actionManager, IdeFocusManager focusManager, @NotNull Disposable parent) {
super(project, actionManager, focusManager, parent);
}
@Override
protected void paintFirstGhost(Graphics2D g2d) {}
@Override
protected void paintLastGhost(Graphics2D g2d) {}
public boolean isGhostsAlwaysVisible() {
return false;
}
protected void doPaintInactive(Graphics2D g2d,
boolean leftGhostExists,
TabLabel label,
Rectangle effectiveBounds,
boolean rightGhostExists) {
Insets insets = getTabsBorder().getEffectiveBorder();
int _x = effectiveBounds.x + insets.left;
int _y = effectiveBounds.y + insets.top + 5;
int _width = effectiveBounds.width - insets.left - insets.right;
int _height = effectiveBounds.height - insets.top - insets.bottom - 5;
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
g2d
.setPaint(new GradientPaint(_x, _y, new Color(255, 255, 255, 180), _x, _y + effectiveBounds.height, new Color(255, 255, 255, 100)));
g2d.fillRect(_x, _y, _width, _height);
g2d.setColor(new Color(255, 255, 255, 100));
g2d.drawRect(_x, _y, _width - 1, _height - 1);
}
@Override
protected void doPaintBackground(Graphics2D g2d, Rectangle clip) {
g2d.setColor(UIUtil.getPanelBackground());
g2d.fill(clip);
g2d.setColor(new Color(0, 0, 0, 50));
g2d.fill(clip);
List<TabInfo> visibleInfos = getVisibleInfos();
Insets insets = getTabsBorder().getEffectiveBorder();
int maxOffset = 0;
int maxLength = 0;
for (int i = visibleInfos.size() - 1; i >= 0; i--) {
TabInfo visibleInfo = visibleInfos.get(i);
TabLabel tabLabel = myInfo2Label.get(visibleInfo);
Rectangle r = tabLabel.getBounds();
if (r.width == 0 || r.height == 0) continue;
maxOffset = r.x + r.width;
maxLength = r.height;
break;
}
maxOffset++;
Rectangle r2 = getBounds();
Rectangle rectangle;
int y = r2.y + insets.top;
int height = maxLength - insets.top - insets.bottom;
height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
g2d.setPaint(UIUtil.getPanelBackground());
g2d.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
g2d.fillRect(0, 0, rectangle.x + rectangle.width, 5);
g2d.fillRect(2, maxLength, getSize().width, getSize().height);
g2d.drawLine(0, 0, 0, getSize().height);
}
protected void paintSelectionAndBorder(Graphics2D g2d) {
if (getSelectedInfo() == null) return;
TabLabel label = getSelectedLabel();
Rectangle r = label.getBounds();
r = new Rectangle(r.x, r.y + 5, r.width, r.height - 5);
ShapeInfo selectedShape = _computeSelectedLabelShape(r);
Insets insets = getTabsBorder().getEffectiveBorder();
Insets i = selectedShape.path.transformInsets(insets);
int _x = r.x;
int _y = r.y;
int _height = r.height;
if (!isHideTabs()) {
g2d.setPaint(new GradientPaint(_x, _y, new SameColor(255), _x, _y + _height, UIUtil.getPanelBackground()));
g2d.fill(selectedShape.fillPath.getShape());
g2d.setColor(new Color(255, 255, 255, 180));
g2d.draw(selectedShape.fillPath.getShape());
}
g2d.setColor(UIUtil.getPanelBackground());
g2d.fillRect(2, selectedShape.labelPath.getMaxY() - 3, selectedShape.path.getMaxX() - 3, 4);
g2d.drawLine(1, selectedShape.labelPath.getMaxY(), 1, getHeight() - 1);
g2d.drawLine(selectedShape.path.getMaxX() - 1, selectedShape.labelPath.getMaxY() - 4,
selectedShape.path.getMaxX() - 1, getHeight() - 1);
if (isHideTabs()) return;
g2d.setColor(new Color(0, 0, 0, 50));
g2d.drawLine(1, selectedShape.labelPath.getMaxY(), 1, getHeight() - 1);
g2d.drawLine(selectedShape.path.getMaxX() - 1, selectedShape.labelPath.getMaxY() - 4,
selectedShape.path.getMaxX() - 1, getHeight() - 1);
}
@Override
public Color getBackground() {
return Gray._142;
}
protected ShapeInfo _computeSelectedLabelShape(Rectangle r) {
final ShapeInfo shape = new ShapeInfo();
shape.path = getEffectiveLayout().createShapeTransform(getSize());
shape.insets = shape.path.transformInsets(getLayoutInsets());
shape.labelPath = shape.path.createTransform(r);
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1);
shape.labelTopY = shape.labelPath.getY() + shape.labelPath.deltaY(1);
shape.labelLeftX = shape.labelPath.getX();
shape.labelRightX = shape.labelPath.getMaxX() - shape.labelPath.deltaX(1);
int leftX = shape.insets.left;
shape.path.moveTo(leftX, shape.labelBottomY);
shape.path.lineTo(shape.labelLeftX, shape.labelBottomY);
shape.path.lineTo(shape.labelLeftX, shape.labelTopY);
shape.path.lineTo(shape.labelRightX, shape.labelTopY);
shape.path.lineTo(shape.labelRightX, shape.labelBottomY);
int lastX = shape.path.getWidth() - shape.path.deltaX(shape.insets.right);
shape.path.lineTo(lastX, shape.labelBottomY);
shape.path.lineTo(lastX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.closePath();
shape.fillPath = shape.path.copy();
return shape;
}
@Override
public int getToolbarInset() {
return 8;
}
public boolean shouldAddToGlobal(Point point) {
final TabLabel label = getSelectedLabel();
if (label == null || point == null) {
return true;
}
final Rectangle bounds = label.getBounds();
return point.y <= bounds.y + bounds.height;
}
@Override
public Rectangle layout(JComponent c, Rectangle bounds) {
if (c instanceof Toolbar) {
bounds.height -= 5;
return super.layout(c, bounds);
}
if (c instanceof GridImpl) {
bounds.x -= 1;
bounds.width += 1;
}
return super.layout(c, bounds);
}
@Override
public void processDropOver(TabInfo over, RelativePoint relativePoint) {
super.processDropOver(over, relativePoint);
final Point point = relativePoint.getPoint(getComponent());
for (Map.Entry<TabInfo, TabLabel> entry : myInfo2Label.entrySet()) {
final TabLabel label = entry.getValue();
if (label.getBounds().contains(point) && myDropInfo != entry.getKey()) {
select(entry.getKey(), false);
break;
}
}
}
@Override
protected TabLabel createTabLabel(TabInfo info) {
return new MyTabLabel(this, info);
}
private static class MyTabLabel extends TabLabel {
public MyTabLabel(JBTabsImpl tabs, final TabInfo info) {
super(tabs, info);
}
@Override
public void apply(UiDecorator.UiDecoration decoration) {
setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL));
myLabel.setFont(UIUtil.getLabelFont(UIUtil.FontSize.SMALL));
setBorder(new EmptyBorder(7, 5, 7, 5));
}
@Override
public void setTabActionsAutoHide(boolean autoHide) {
super.setTabActionsAutoHide(autoHide);
apply(null);
}
@Override
public void setTabActions(ActionGroup group) {
super.setTabActions(group);
if (myActionPanel != null) {
final JComponent wrapper = (JComponent)myActionPanel.getComponent(0);
wrapper.remove(0);
wrapper.add(Box.createHorizontalStrut(6), BorderLayout.WEST);
}
}
@Override
protected int getSelectedOffset() {
return getNonSelectedOffset();
}
}
}
@@ -28,21 +28,28 @@ import com.intellij.openapi.util.ActiveRunnable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.ui.UIBundle;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.content.*;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.docking.DockableContent;
import com.intellij.ui.docking.DragSession;
import com.intellij.ui.docking.impl.DockManagerImpl;
import com.intellij.ui.switcher.QuickActionProvider;
import com.intellij.ui.switcher.SwitchProvider;
import com.intellij.ui.switcher.SwitchTarget;
import com.intellij.ui.tabs.JBTabs;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsListener;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.AbstractLayoutManager;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -50,13 +57,15 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.*;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Facade, ViewContextEx, PropertyChangeListener, SwitchProvider,
QuickActionProvider {
QuickActionProvider, DockContainer {
@NonNls public static final String LAYOUT = "Runner.Layout";
@NonNls public static final String VIEW_POPUP = "Runner.View.Popup";
@@ -70,8 +79,9 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
MyComponent myComponent = new MyComponent();
private final Wrapper myToolbar = new Wrapper();
final MyDragOutDelegate myDragOutDelegate = new MyDragOutDelegate();
JBTabs myTabs;
JBRunnerTabs myTabs;
private final Comparator<TabInfo> myTabsComparator = new Comparator<TabInfo>() {
public int compare(final TabInfo o1, final TabInfo o2) {
//noinspection ConstantConditions
@@ -110,6 +120,20 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
private int myAttractionCount;
private ActionGroup myLeftToolbarActions;
private JBTabs myCurrentOver;
private Image myCurrentOverImg;
private TabInfo myCurrentOverInfo;
private RunnerContentUi myOriginal;
private CopyOnWriteArraySet<Listener> myDockingListeners = new CopyOnWriteArraySet<Listener>();
private Set<RunnerContentUi> myChildren = new TreeSet<RunnerContentUi>(new Comparator<RunnerContentUi>() {
@Override
public int compare(RunnerContentUi o1, RunnerContentUi o2) {
return o1.myWindow - o2.myWindow;
}
});
private int myWindow;
private boolean myDisposing;
public RunnerContentUi(Project project,
RunnerLayoutUi ui,
ActionManager actionManager,
@@ -124,6 +148,12 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
myFocusManager = focusManager;
}
public RunnerContentUi(RunnerContentUi ui, RunnerContentUi original, int window) {
this(ui.myProject, ui.myRunnerUi, ui.myActionManager, ui.myFocusManager, ui.myLayoutSettings, ui.mySessionName);
myOriginal = original;
original.myChildren.add(this);
myWindow = window == 0 ? original.findFreeWindow() : window;
}
public void setTopActions(@NotNull final ActionGroup topActions, @NotNull String place) {
myTopActions = topActions;
@@ -150,32 +180,27 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
public void initUi() {
if (myTabs != null) return;
myTabs = new JBTabsImpl(myProject, myActionManager, myFocusManager, this)
.setDataProvider(new DataProvider() {
public Object getData(@NonNls final String dataId) {
if (ViewContext.CONTENT_KEY.is(dataId)) {
TabInfo info = myTabs.getTargetInfo();
if (info != null) {
return getGridFor(info).getData(dataId);
}
myTabs = (JBRunnerTabs)new JBRunnerTabs(myProject, myActionManager, myFocusManager, this).setDataProvider(new DataProvider() {
public Object getData(@NonNls final String dataId) {
if (ViewContext.CONTENT_KEY.is(dataId)) {
TabInfo info = myTabs.getTargetInfo();
if (info != null) {
return getGridFor(info).getData(dataId);
}
else if (ViewContext.CONTEXT_KEY.is(dataId)) {
return RunnerContentUi.this;
}
return null;
}
}).setProvideSwitchTargets(false).setInnerInsets(new Insets(1, 0, 0, 0)).setToDrawBorderIfTabsHidden(false)
.setUiDecorator(new UiDecorator() {
@NotNull
public UiDecoration getDecoration() {
return new UiDecoration(null, new Insets(1, 8, 1, 8));
else if (ViewContext.CONTEXT_KEY.is(dataId)) {
return RunnerContentUi.this;
}
}).getJBTabs();
return null;
}
}).setTabLabelActionsAutoHide(false).setProvideSwitchTargets(false).setInnerInsets(new Insets(0, 0, 0, 0))
.setToDrawBorderIfTabsHidden(false).setTabDraggingEnabled(isMoveToGridActionEnabled()).setUiDecorator(null).getJBTabs();
rebuildTabPopup();
myTabs.getPresentation().setPaintBorder(0, 0, 0, 0).setTabSidePaintBorder(2).setPaintFocus(false)
myTabs.getPresentation().setPaintBorder(0, 0, 0, 0).setPaintFocus(false)
.setRequestFocusOnLastFocusedComponent(true);
myTabs.getComponent().setBackground(myToolbar.getBackground());
myTabs.getComponent().setBorder(new EmptyBorder(0, 2, 0, 0));
final NonOpaquePanel wrappper = new NonOpaquePanel(new BorderLayout(0, 0));
wrappper.add(myToolbar, BorderLayout.WEST);
@@ -194,6 +219,11 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
}
@Override
public void tabsMoved() {
saveUiState();
}
public void selectionChanged(final TabInfo oldSelection, final TabInfo newSelection) {
if (!myTabs.getComponent().isShowing()) return;
@@ -207,6 +237,14 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
}
});
if (myOriginal != null) {
final ContentManager manager = ContentFactory.SERVICE.getInstance().createContentManager(this, false, myProject);
Disposer.register((Disposable)myRunnerUi, manager);
manager.getComponent();
} else {
DockManager.getInstance(myProject).register(this);
}
}
private void rebuildTabPopup() {
@@ -249,10 +287,15 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
return group;
}
public void doWhenInitialized(final Runnable runnable) {
myInitialized.doWhenDone(runnable);
@Override
public boolean isOriginal() {
return myOriginal == null;
}
@Override
public int getWindow() {
return myWindow;
}
public void propertyChange(final PropertyChangeEvent evt) {
Content content = (Content)evt.getSource();
@@ -302,11 +345,193 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
}
@Override
public ActionCallback detachTo(int window, GridCell cell) {
if (myOriginal != null) {
return myOriginal.detachTo(window, cell);
}
RunnerContentUi target = null;
if (window > 0) {
for (RunnerContentUi child : myChildren) {
if (child.myWindow == window) {
target = child;
break;
}
}
}
final GridCellImpl gridCell = (GridCellImpl)cell;
final Content[] contents = gridCell.getContents();
storeDefaultIndices(contents);
for (Content content : contents) {
content.putUserData(RunnerLayout.DROP_INDEX, getStateFor(content).getTab().getIndex());
}
Dimension size = gridCell.getSize();
if (size == null) {
size = new Dimension(200, 200);
}
final DockableGrid content = new DockableGrid(null, null, size, Arrays.asList(contents), window);
if (target != null) {
target.add(content, null);
} else {
final Point location = gridCell.getLocation();
location.translate(size.width / 2, size.height / 2);
getDockManager().createNewDockContainerFor(content, new RelativePoint(location));
}
return new ActionCallback.Done();
}
private void storeDefaultIndices(Content[] contents) {
for (Content content : contents) {
content.putUserData(RunnerLayout.DEFAULT_INDEX, getStateFor(content).getTab().getDefaultIndex());
}
}
@Override
public RelativeRectangle getAcceptArea() {
return new RelativeRectangle(myTabs.getComponent());
}
@Override
public boolean canAccept(DockableContent content, RelativePoint point) {
if (!(content instanceof DockableGrid)) {
return false;
}
final RunnerContentUi ui = ((DockableGrid)content).getOriginalRunnerUi();
return ui.getProject() == myProject && ui.mySessionName.equals(mySessionName);
}
@Override
public JComponent getComponent() {
initUi();
return myComponent;
}
@Override
public JComponent getContainerComponent() {
initUi();
return myManager.getComponent();
}
@Override
public void add(DockableContent dockable, RelativePoint dropTarget) {
saveUiState();
final DockableGrid dockableGrid = (DockableGrid)dockable;
final List<Content> contents = dockableGrid.getContents();
final boolean wasRestoring = myOriginal != null && myOriginal.isStateBeingRestored();
setStateIsBeingRestored(true, this);
try {
final Point point = dropTarget != null ? dropTarget.getPoint(myComponent) : null;
boolean hadGrid = !myTabs.shouldAddToGlobal(point);
for (Content content : contents) {
dockableGrid.getRunnerUi().myManager.removeContent(content, false);
myManager.removeContent(content, false);
if (hadGrid && contents.size() == 1 && !wasRestoring) {
getStateFor(content).assignTab(getTabFor(getSelectedGrid()));
getStateFor(content).setPlaceInGrid(myLayoutSettings.getDefaultGridPlace(content));
} else if (contents.size() == 1 && !wasRestoring) {
getStateFor(content).assignTab(myLayoutSettings.createNewTab());
getStateFor(content).setPlaceInGrid(myLayoutSettings.getDefaultGridPlace(content));
}
getStateFor(content).setWindow(myWindow);
myManager.addContent(content);
}
} finally {
setStateIsBeingRestored(false, this);
}
saveUiState();
updateTabsUI(true);
}
@Override
public void closeAll() {
final Content[] contents = myManager.getContents();
for (Content content : contents) {
getStateFor(content).setWindow(0);
}
myManager.removeAllContents(false);
for (Content content : contents) {
myOriginal.myManager.addContent(content);
myOriginal.findCellFor(content).minimize(content);
}
}
@Override
public void addListener(final Listener listener, Disposable parent) {
myDockingListeners.add(listener);
Disposer.register(parent, new Disposable() {
@Override
public void dispose() {
myDockingListeners.remove(listener);
}
});
}
@Override
public boolean isEmpty() {
return myTabs.isEmptyVisible() || myDisposing;
}
@Override
public Image startDropOver(DockableContent content, RelativePoint point) {
return null;
}
@Override
public Image processDropOver(DockableContent content, RelativePoint point) {
JBTabs current = getTabsAt(content, point);
if (myCurrentOver != null && myCurrentOver != current) {
resetDropOver(content);
}
if (myCurrentOver == null && current != null) {
myCurrentOver = current;
Presentation presentation = content.getPresentation();
myCurrentOverInfo = new TabInfo(new JLabel("")).setText(presentation.getText()).setIcon(presentation.getIcon());
myCurrentOverImg = myCurrentOver.startDropOver(myCurrentOverInfo, point);
}
if (myCurrentOver != null) {
myCurrentOver.processDropOver(myCurrentOverInfo, point);
}
return myCurrentOverImg;
}
@Nullable
private JBTabs getTabsAt(DockableContent content, RelativePoint point) {
if (content instanceof DockableGrid) {
final Point p = point.getPoint(getComponent());
Component c = SwingUtilities.getDeepestComponentAt(getComponent(), p.x, p.y);
while (c != null) {
if (c instanceof JBTabs) {
return (JBTabs)c;
}
c = c.getParent();
}
}
return null;
}
@Override
public void resetDropOver(DockableContent content) {
if (myCurrentOver != null) {
myCurrentOver.resetDropOver(myCurrentOverInfo);
myCurrentOver = null;
myCurrentOverInfo = null;
myCurrentOverImg = null;
}
}
@Override
public boolean isDisposeWhenEmpty() {
return myOriginal != null;
}
public boolean isCycleRoot() {
return false;
}
@@ -337,6 +562,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
event.getContent().addPropertyChangeListener(RunnerContentUi.this);
fireContentOpened(event.getContent());
}
public void contentRemoved(final ContentManagerEvent event) {
@@ -349,6 +575,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
removeGridIfNeeded(grid);
}
updateTabsUI(false);
fireContentClosed(event.getContent());
}
public void contentRemoveQuery(final ContentManagerEvent event) {
@@ -387,6 +614,16 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
grid = new GridImpl(this, mySessionName);
grid.setBorder(new EmptyBorder(1, 0, 0, 0));
if (myCurrentOver != null || myOriginal != null) {
Integer forcedDropIndex = content.getUserData(RunnerLayout.DROP_INDEX);
final int index = myTabs.getDropInfoIndex() + (myOriginal != null ? myOriginal.getTabOffsetFor(this) : 0);
final TabImpl tab = myLayoutSettings.getOrCreateTab(-1);
final Integer defaultIndex = content.getUserData(RunnerLayout.DEFAULT_INDEX);
tab.setDefaultIndex(defaultIndex != null ? defaultIndex : -1);
tab.setIndex(forcedDropIndex != null ? forcedDropIndex : index);
getStateFor(content).assignTab(tab);
}
TabInfo tab = new TabInfo(grid).setObject(getStateFor(content).getTab()).setText("Tab");
@@ -418,6 +655,15 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
return grid;
}
private int getTabOffsetFor(RunnerContentUi ui) {
int offset = myTabs.getTabCount();
for (RunnerContentUi child : myChildren) {
if (child == ui) break;
offset += child.myTabs.getTabCount();
}
return offset;
}
@Nullable
public GridCell findCellFor(final Content content) {
GridImpl cell = getGridFor(content, false);
@@ -498,9 +744,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
for (TabInfo each : tabs) {
hasToolbarContent |= updateTabUI(each);
}
myTabs.getPresentation().setHideTabs(!hasToolbarContent && tabs.size() <= 1);
myTabs.getPresentation().setHideTabs(!hasToolbarContent && tabs.size() <= 1 && myOriginal == null);
myTabs.updateTabActions(validateNow);
if (validateNow) {
@@ -508,7 +752,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
}
private static boolean updateTabUI(TabInfo tab) {
private boolean updateTabUI(TabInfo tab) {
TabImpl t = getTabFor(tab);
if (t == null) {
return false;
@@ -534,9 +778,11 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
if (icon == null && contents.size() == 1) {
tab.setHidden(grid.isMinimized(contents.get(0)));
icon = contents.get(0).getIcon();
}
tab.setDragOutDelegate(myTabs.getTabs().size() > 1 || !isOriginal() ? myDragOutDelegate : null);
Tab gridTab = grid.getTab();
tab.setText(title).setIcon(gridTab != null && gridTab.isDefault() ? null : icon);
@@ -569,10 +815,38 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
public void saveUiState() {
if (isStateBeingRestored()) return;
if (myOriginal != null) {
myOriginal.saveUiState();
return;
}
int offset = updateTabsIndices(myTabs, 0);
for (RunnerContentUi child : myChildren) {
offset = updateTabsIndices(child.myTabs, offset);
}
doSaveUiState();
}
private static int updateTabsIndices(final JBRunnerTabs tabs, int offset) {
for (TabInfo each : tabs.getTabs()) {
final int index = tabs.getIndexOf(each);
final TabImpl tab = getTabFor(each);
if (tab != null) tab.setIndex(index + offset);
}
return offset + tabs.getTabCount();
}
private void doSaveUiState() {
if (isStateBeingRestored()) return;
for (TabInfo each : myTabs.getTabs()) {
GridImpl eachGrid = getGridFor(each);
eachGrid.saveUiState();
}
for (RunnerContentUi child : myChildren) {
child.doSaveUiState();
}
}
@Nullable
@@ -581,6 +855,17 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
return getTabFor(info);
}
@Override
public void showNotify() {
final Window window = SwingUtilities.getWindowAncestor(myComponent);
if (window instanceof IdeFrame.Child) {
((IdeFrame.Child)window).setFrameTitle(mySessionName);
}
}
@Override
public void hideNotify() {}
@Nullable
private static TabImpl getTabFor(@Nullable final TabInfo tab) {
if (tab == null) {
@@ -640,6 +925,10 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
if (myComponent.getRootPane() != null) {
saveUiState();
}
if (myOriginal != null) {
myDisposing = true;
fireContentClosed(null);
}
}
public boolean canChangeSelectionTo(Content content, boolean implicit) {
@@ -674,14 +963,25 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
public void dispose() {
if (myOriginal != null) {
myOriginal.myChildren.remove(this);
}
}
public void restoreLayout() {
Content[] all = myManager.getContents();
final RunnerContentUi[] children = myChildren.toArray(new RunnerContentUi[myChildren.size()]);
final List<Content> contents = new ArrayList<Content>();
Collections.addAll(contents, myManager.getContents());
for (RunnerContentUi child : children) {
Collections.addAll(contents, child.myManager.getContents());
}
Content[] all = contents.toArray(new Content[contents.size()]);
setStateIsBeingRestored(true, this);
try {
for (RunnerContentUi child : children) {
child.myManager.removeAllContents(false);
}
myManager.removeAllContents(false);
myMinimizedViewActions.removeAll();
}
@@ -730,7 +1030,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
public boolean isMinimizeActionEnabled() {
return myMinimizeActionEnabled;
return myMinimizeActionEnabled && myOriginal == null;
}
public boolean isMoveToGridActionEnabled() {
@@ -820,12 +1120,12 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
public void addNotify() {
super.addNotify();
if (!myUiLastStateWasRestored) {
if (!myUiLastStateWasRestored && myOriginal == null) {
myUiLastStateWasRestored = true;
//noinspection SSBasedInspection
// [kirillk] this is done later since restoreUiState doesn't work properly in the addNotify call chain
//todo to investigate and to fix (may cause extra flickering)
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
public void run() {
restoreLastUiState().doWhenDone(new Runnable() {
@@ -946,90 +1246,6 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
updateTabsUI(false);
}
private static boolean willBeEmptyOnRemove(GridImpl grid, List<Content> toRemove) {
List<Content> attachedToGrid = grid.getAttachedContents();
for (Content each : attachedToGrid) {
if (!toRemove.contains(each)) return false;
}
return true;
}
public CellTransform.Restore detach(final Content[] content) {
List<Content> contents = Arrays.asList(content);
for (Content each : content) {
GridImpl eachGrid = getGridFor(each, false);
if (willBeEmptyOnRemove(eachGrid, contents)) {
TabInfo info = myTabs.findInfo(eachGrid);
if (info != null) {
info.setHidden(true);
}
}
}
updateTabsUI(true);
return new CellTransform.Restore() {
public ActionCallback restoreInGrid() {
showHiddenTabs();
updateTabsUI(true);
return new ActionCallback.Done();
}
};
}
private void showHiddenTabs() {
List<TabInfo> tabs = myTabs.getTabs();
for (TabInfo eachInfos : tabs) {
GridImpl eachGrid = (GridImpl)eachInfos.getComponent();
if (!eachGrid.getAttachedContents().isEmpty()) {
eachInfos.setHidden(false);
}
}
}
public void moveToTab(final Content content) {
saveUiState();
setStateIsBeingRestored(true, this);
try {
myManager.removeContent(content, false);
getStateFor(content).assignTab(myLayoutSettings.createNewTab());
getStateFor(content).setPlaceInGrid(PlaceInGrid.center);
myManager.addContent(content);
}
finally {
setStateIsBeingRestored(false, this);
}
saveUiState();
}
public void moveToGrid(final Content content) {
saveUiState();
setStateIsBeingRestored(true, this);
try {
myManager.removeContent(content, false);
getStateFor(content).assignTab(myLayoutSettings.getDefaultTab());
getStateFor(content).setPlaceInGrid(myLayoutSettings.getDefaultGridPlace(content));
myManager.addContent(content);
}
finally {
setStateIsBeingRestored(false, this);
}
select(content, true).doWhenDone(new Runnable() {
public void run() {
saveUiState();
}
});
}
public Project getProject() {
return myProject;
}
@@ -1055,7 +1271,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
}
public boolean isHorizontalToolbar() {
return myLayoutSettings.isToolbarHorizontal();
return false;
}
public ActionCallback select(final Content content, final boolean requestFocus) {
@@ -1068,18 +1284,12 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
final ActionCallback result = new ActionCallback();
if (grid.isDetached(content)) {
if (requestFocus) {
myTabs.select(info, false).doWhenDone(new Runnable() {
public void run() {
grid.select(content, requestFocus).notifyWhenDone(result);
}
}
else {
myTabs.select(info, false).doWhenDone(new Runnable() {
public void run() {
grid.select(content, requestFocus).notifyWhenDone(result);
}
});
}
});
return result;
}
@@ -1233,4 +1443,142 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
return result;
}
private int findFreeWindow() {
int i;
for (i = 1; i < Integer.MAX_VALUE; i++) {
if (!isUsed(i)) {
return i;
}
}
return i;
}
private boolean isUsed(int i) {
for (RunnerContentUi child : myChildren) {
if (child.getWindow() == i) {
return true;
}
}
return false;
}
private DockManagerImpl getDockManager() {
return (DockManagerImpl)DockManager.getInstance(myProject);
}
class MyDragOutDelegate implements TabInfo.DragOutDelegate {
private DragSession mySession;
@Override
public void dragOutStarted(MouseEvent mouseEvent, TabInfo info) {
final JComponent component = info.getComponent();
final Content[] data = CONTENT_KEY.getData((DataProvider)component);
final List<Content> contents = Arrays.asList(data);
storeDefaultIndices(data);
final Dimension size = info.getComponent().getSize();
final Image image = myTabs.getComponentImage(info);
if (component instanceof Grid) {
info.setHidden(true);
}
Presentation presentation = new Presentation(info.getText());
presentation.setIcon(info.getIcon());
mySession = getDockManager().createDragSession(mouseEvent, new DockableGrid(image, presentation,
size,
contents, 0));
}
@Override
public void processDragOut(MouseEvent event, TabInfo source) {
mySession.process(event);
}
@Override
public void dragOutFinished(MouseEvent event, TabInfo source) {
final Component component = event.getComponent();
final IdeFrame window = UIUtil.getParentOfType(IdeFrame.class, component);
if (window != null) {
}
mySession.process(event);
mySession = null;
}
}
class DockableGrid implements DockableContent<List<Content>> {
final Image myImg;
private Presentation myPresentation;
private final Dimension myPreferredSize;
private final List<Content> myContents;
private final int myWindow;
public DockableGrid(Image img, Presentation presentation, final Dimension size, List<Content> contents, int window) {
myImg = img;
myPresentation = presentation;
myPreferredSize = size;
myContents = contents;
myWindow = window;
}
@Override
public List<Content> getKey() {
return myContents;
}
@Override
public Image getPreviewImage() {
return myImg;
}
@Override
public Dimension getPreferredSize() {
return myPreferredSize;
}
@Override
public String getDockContainerType() {
return DockableGridContainerFactory.TYPE;
}
@Override
public Presentation getPresentation() {
return myPresentation;
}
public RunnerContentUi getRunnerUi() {
return RunnerContentUi.this;
}
public RunnerContentUi getOriginalRunnerUi() {
return myOriginal != null ? myOriginal : RunnerContentUi.this;
}
public List<Content> getContents() {
return myContents;
}
@Override
public void close() {
}
public int getWindow() {
return myWindow;
}
}
void fireContentOpened(Content content) {
for (Listener each : myDockingListeners) {
each.contentAdded(content);
}
}
void fireContentClosed(Content content) {
for (Listener each : myDockingListeners) {
each.contentRemoved(content);
}
}
}
@@ -20,6 +20,7 @@ import com.intellij.execution.ui.layout.LayoutAttractionPolicy;
import com.intellij.execution.ui.layout.PlaceInGrid;
import com.intellij.execution.ui.layout.Tab;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.content.Content;
@@ -33,7 +34,8 @@ import javax.swing.*;
import java.util.*;
public class RunnerLayout {
public static final Key<Integer> DEFAULT_INDEX = Key.create("RunnerLayoutDefaultIndex");
public static final Key<Integer> DROP_INDEX = Key.create("RunnerLayoutDropIndex");
private final String myID;
protected Map<String, ViewImpl> myViews = new HashMap<String, ViewImpl>();
@@ -64,10 +66,6 @@ public class RunnerLayout {
return tab;
}
public TabImpl getDefaultTab() {
return getOrCreateTab(0);
}
private TabImpl createNewTab(final int index) {
final TabImpl tab;
@@ -153,7 +151,9 @@ public class RunnerLayout {
}
for (TabImpl eachTab : myTabs) {
eachTab.write(parentNode);
if (isUsed(eachTab)) {
eachTab.write(parentNode);
}
}
parentNode.addContent(XmlSerializer.serialize(myGeneral));
@@ -166,13 +166,13 @@ public class RunnerLayout {
myViews.clear();
for (TabImpl each : myTabs) {
final TabImpl.Default defaultTab = getOrCreateDefaultTab(each.getIndex());
final TabImpl.Default defaultTab = getOrCreateDefaultTab(each.getDefaultIndex());
each.copyFrom(defaultTab);
}
}
public boolean isToolbarHorizontal() {
return myGeneral.horizontalToolbar;
return false;
}
public void setToolbarHorizontal(boolean horizontal) {
@@ -40,6 +40,10 @@ public class TabImpl extends AbstractTab implements Tab {
return myIndex;
}
public int getDefaultIndex() {
return myDefaultIndex >= 0 ? myDefaultIndex : myIndex;
}
public String getDisplayName() {
return myDisplayName;
}
@@ -52,6 +56,10 @@ public class TabImpl extends AbstractTab implements Tab {
myIndex = index;
}
public void setDefaultIndex(final int index) {
myDefaultIndex = index;
}
public void setDisplayName(final String displayName) {
myDisplayName = displayName;
}
@@ -161,6 +169,7 @@ public class TabImpl extends AbstractTab implements Tab {
public Default(final int index, final String displayName, final Icon icon) {
myIndex = index;
myDefaultIndex = index;
myDisplayName = displayName;
myIcon = icon;
}
@@ -16,14 +16,19 @@
package com.intellij.execution.ui.layout.impl;
import com.intellij.execution.ui.layout.GridCell;
import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.util.ActionCallback;
public interface ViewContextEx extends ViewContext {
RunnerLayout getLayoutSettings();
ActionGroup getCellPopupGroup(String place);
void doWhenInitialized(Runnable runnable);
boolean isOriginal();
int getWindow();
ActionCallback detachTo(int window, GridCell cell);
}
@@ -31,16 +31,19 @@ public class ViewImpl implements View {
private Tab myTab;
private int myTabIndex;
private int myWindow;
private PlaceInGrid myPlaceInGrid;
private boolean myMinimizedInGrid;
public ViewImpl(String id, TabImpl tab, final PlaceInGrid placeInGrid, boolean minimizedInGrid) {
public ViewImpl(String id, TabImpl tab, final PlaceInGrid placeInGrid, boolean minimizedInGrid, int window) {
myID = id;
myTab = tab;
myPlaceInGrid = placeInGrid;
myMinimizedInGrid = minimizedInGrid;
myWindow = window;
}
public ViewImpl(RunnerLayout settings, Element element) {
@@ -94,6 +97,16 @@ public class ViewImpl implements View {
myTabIndex = tabIndex;
}
@Override
public int getWindow() {
return myWindow;
}
@Override
public void setWindow(int windowNumber) {
myWindow = windowNumber;
}
public static class Default {
private final String myID;
@@ -110,7 +123,7 @@ public class ViewImpl implements View {
public ViewImpl createView(RunnerLayout settings) {
final TabImpl tab = myTabID == Integer.MAX_VALUE ? settings.createNewTab() : settings.getOrCreateTab(myTabID);
return new ViewImpl(myID, tab, myPlaceInGrid, myMinimizedInGrid);
return new ViewImpl(myID, tab, myPlaceInGrid, myMinimizedInGrid, 0);
}
public PlaceInGrid getPlaceInGrid() {
@@ -32,6 +32,8 @@ import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.util.Processor;
import com.intellij.util.containers.hash.*;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,6 +41,7 @@ import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.HashMap;
import java.util.List;
/**
@@ -207,7 +210,7 @@ public class GotoRelatedFileAction extends AnAction {
}
}
List<GotoRelatedItem> items = new ArrayList<GotoRelatedItem>();
Set<GotoRelatedItem> items = new HashSet<GotoRelatedItem> ();
for (GotoRelatedProvider provider : Extensions.getExtensions(GotoRelatedProvider.EP_NAME)) {
items.addAll(provider.getItems(contextElement));
@@ -215,7 +218,7 @@ public class GotoRelatedFileAction extends AnAction {
items.addAll(provider.getItems(dataContext));
}
}
return items;
return new ArrayList<GotoRelatedItem>(items);
}
@Override
@@ -48,6 +48,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
@@ -319,10 +320,17 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements Expo
@NonNls Properties props = new Properties();
Calendar calendar = Calendar.getInstance();
Date date = new Date(calendar.getTimeInMillis());
SimpleDateFormat sdfMonthNameShort = new SimpleDateFormat("MMM");
SimpleDateFormat sdfMonthNameFull = new SimpleDateFormat("MMMM");
SimpleDateFormat sdfYearFull = new SimpleDateFormat("yyyy");
props.setProperty("DATE", DateFormatUtil.formatDate(calendar.getTime()));
props.setProperty("TIME", DateFormatUtil.formatTime(calendar.getTime()));
props.setProperty("YEAR", Integer.toString(calendar.get(Calendar.YEAR)));
props.setProperty("YEAR", sdfYearFull.format(date));
props.setProperty("MONTH", getCalendarValue(calendar, Calendar.MONTH));
props.setProperty("MONTH_NAME_SHORT", sdfMonthNameShort.format(date));
props.setProperty("MONTH_NAME_FULL", sdfMonthNameFull.format(date));
props.setProperty("DAY", getCalendarValue(calendar, Calendar.DAY_OF_MONTH));
props.setProperty("HOUR", getCalendarValue(calendar, Calendar.HOUR_OF_DAY));
props.setProperty("MINUTE", getCalendarValue(calendar, Calendar.MINUTE));
@@ -539,6 +539,7 @@ public abstract class TodoTreeBuilder extends AbstractTreeBuilder {
return null;
}
Object[] children = getTreeStructure().getChildElements(parent);
Arrays.sort(children, getUi().getNodeDescriptorComparator());
int idx = -1;
for (int i = 0; i < children.length; i++) {
if (obj.equals(children[i])) {
@@ -584,6 +585,7 @@ public abstract class TodoTreeBuilder extends AbstractTreeBuilder {
return null;
}
Object[] children = getTreeStructure().getChildElements(parent);
Arrays.sort(children, getUi().getNodeDescriptorComparator());
int idx = -1;
for (int i = 0; i < children.length; i++) {
if (obj.equals(children[i])) {
@@ -228,18 +228,20 @@ public class FileStructurePopup implements Disposable {
for (ObjectWithWeight p : paths) {
final Object last = ((TreePath)p.node).getLastPathComponent();
final List<PsiElement> elements = new ArrayList<PsiElement>();
FilteringTreeStructure.FilteringNode node =
(FilteringTreeStructure.FilteringNode)((DefaultMutableTreeNode)last).getUserObject();
while (node != null) {
elements.add(getPsi(node));
node = node.getParentNode();
}
final int size = ContainerUtil.intersection(parents, elements).size();
if (size > max) {
max = size;
cur = p.node;
} else if (size == max && size == parents.size()) {
cur = p.node;
final Object object = ((DefaultMutableTreeNode)last).getUserObject();
if (object instanceof FilteringTreeStructure.FilteringNode) {
FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)object;
while (node != null) {
elements.add(getPsi(node));
node = node.getParentNode();
}
final int size = ContainerUtil.intersection(parents, elements).size();
if (size > max) {
max = size;
cur = p.node;
} else if (size == max && size == parents.size()) {
cur = p.node;
}
}
}
@@ -19,7 +19,8 @@
*/
package com.intellij.psi.stubs;
import java.io.ByteArrayInputStream;
import com.intellij.util.io.UnsyncByteArrayInputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
@@ -45,7 +46,7 @@ public class SerializedStubTree {
}
public StubElement getStub() {
return SerializationManager.getInstance().deserialize(new ByteArrayInputStream(myBytes));
return SerializationManager.getInstance().deserialize(new UnsyncByteArrayInputStream(myBytes));
}
public boolean equals(final Object that) {
@@ -3570,6 +3570,10 @@ public class AbstractTreeUi {
}
}
public Comparator getNodeDescriptorComparator() {
return myNodeDescriptorComparator;
}
private void disposeNode(DefaultMutableTreeNode node) {
TreeNode parent = node.getParent();
if (parent instanceof DefaultMutableTreeNode) {
@@ -18,6 +18,8 @@ package com.intellij.notification;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -97,6 +99,11 @@ public class Notification {
public void expire() {
NotificationsManager.getNotificationsManager().expire(this);
hideBalloon();
myExpired = true;
}
public void hideBalloon() {
if (myBalloonRef != null) {
final Balloon balloon = myBalloonRef.get();
if (balloon != null) {
@@ -104,15 +111,20 @@ public class Notification {
}
myBalloonRef = null;
}
myExpired = true;
}
public void setBalloon(@Nullable final Balloon balloon) {
if (balloon != null) {
myBalloonRef = new WeakReference<Balloon>(balloon);
} else {
myBalloonRef = null;
}
public void setBalloon(@NotNull final Balloon balloon) {
hideBalloon();
myBalloonRef = new WeakReference<Balloon>(balloon);
balloon.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
WeakReference<Balloon> ref = myBalloonRef;
if (ref != null && ref.get() == balloon) {
myBalloonRef = null;
}
}
});
}
@Nullable
@@ -272,6 +272,17 @@ public class TableScrollingUtil {
moveEnd(list);
}
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)), list);
new AnAction() {
public void actionPerformed(AnActionEvent e) {
moveHome(list);
}
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0)), list);
new AnAction() {
public void actionPerformed(AnActionEvent e) {
moveEnd(list);
}
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0)), list);
}
}
@@ -30,7 +30,7 @@ public interface DockContainer extends Disposable, Activatable {
RelativeRectangle getAcceptArea();
boolean canAccept(DockableContent content, RelativePoint point);
JComponent getComponent();
JComponent getContainerComponent();
void add(DockableContent content, RelativePoint dropTarget);
@@ -20,7 +20,7 @@ import org.jdom.Element;
public interface DockContainerFactory extends Disposable {
DockContainer createContainer();
DockContainer createContainer(DockableContent content);
interface Persistent extends DockContainerFactory {
@@ -22,12 +22,18 @@ public interface TabsListener {
void beforeSelectionChanged(TabInfo oldSelection, TabInfo newSelection);
void tabsMoved();
class Adapter implements TabsListener {
public void selectionChanged(TabInfo oldSelection, TabInfo newSelection) {
}
public void beforeSelectionChanged(TabInfo oldSelection, TabInfo newSelection) {
}
@Override
public void tabsMoved() {
}
}
}
@@ -30,7 +30,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class ActionPanel extends NonOpaquePanel {
public class ActionPanel extends NonOpaquePanel {
private final ActionGroup myGroup;
private final List<ActionButton> myButtons = new ArrayList<ActionButton>();
@@ -253,6 +253,9 @@ class DragHelper extends MouseDragHelper {
myDragRec = null;
myTabs.resetTabsCache();
if (!willDragOutStart) {
myTabs.fireTabsMoved();
}
myTabs.relayout(true, false);
myTabs.revalidate();
@@ -163,7 +163,7 @@ public class JBTabsImpl extends JComponent
private boolean myOwnSwitchProvider = true;
private SwitchProvider mySwitchDelegate;
private TabInfo myDropInfo;
protected TabInfo myDropInfo;
private int myDropInfoIndex;
private TabInfo myOldSelection;
@@ -629,7 +629,7 @@ public class JBTabsImpl extends JComponent
}
info.getChangeSupport().addPropertyChangeListener(this);
final TabLabel label = new TabLabel(this, info);
final TabLabel label = createTabLabel(info);
myInfo2Label.put(info, label);
if (!isDropTarget) {
@@ -674,6 +674,9 @@ public class JBTabsImpl extends JComponent
return info;
}
protected TabLabel createTabLabel(TabInfo info) {
return new TabLabel(this, info);
}
@NotNull
public TabInfo addTab(TabInfo info) {
@@ -832,6 +835,14 @@ public class JBTabsImpl extends JComponent
}
}
void fireTabsMoved() {
for (TabsListener eachListener : myTabListeners) {
if (eachListener != null) {
eachListener.tabsMoved();
}
}
}
private ActionCallback requestFocus(final JComponent toFocus) {
if (toFocus == null) return new ActionCallback.Done();
@@ -1745,17 +1756,18 @@ public class JBTabsImpl extends JComponent
return myInfo2Label.get(getSelectedInfo());
}
static class ShapeInfo {
ShapeTransform path;
ShapeTransform fillPath;
ShapeTransform labelPath;
int labelBottomY;
int labelTopY;
int labelLeftX;
int labelRightX;
Insets insets;
Color from;
Color to;
protected static class ShapeInfo {
public ShapeInfo() {}
public ShapeTransform path;
public ShapeTransform fillPath;
public ShapeTransform labelPath;
public int labelBottomY;
public int labelTopY;
public int labelLeftX;
public int labelRightX;
public Insets insets;
public Color from;
public Color to;
}
@@ -2977,7 +2989,7 @@ public class JBTabsImpl extends JComponent
}
}
public static Rectangle layout(JComponent c, Rectangle bounds) {
public Rectangle layout(JComponent c, Rectangle bounds) {
final Rectangle now = c.getBounds();
if (!bounds.equals(now)) {
c.setBounds(bounds);
@@ -2987,7 +2999,7 @@ public class JBTabsImpl extends JComponent
return bounds;
}
public static Rectangle layout(JComponent c, int x, int y, int width, int height) {
public Rectangle layout(JComponent c, int x, int y, int width, int height) {
return layout(c, new Rectangle(x, y, width, height));
}
@@ -43,7 +43,7 @@ import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
public class TabLabel extends JPanel {
private final SimpleColoredComponent myLabel = new SimpleColoredComponent() {
protected final SimpleColoredComponent myLabel = new SimpleColoredComponent() {
@Override
protected boolean shouldDrawMacShadow() {
return SystemInfo.isMac;
@@ -54,7 +54,7 @@ public class TabLabel extends JPanel {
private Icon myOverlayedIcon;
private final TabInfo myInfo;
private ActionPanel myActionPanel;
protected ActionPanel myActionPanel;
private boolean myCentered;
private final Wrapper myLabelPlaceholder = new Wrapper();
@@ -224,7 +224,7 @@ public class TabLabel extends JPanel {
});
}
private int getNonSelectedOffset() {
protected int getNonSelectedOffset() {
if (myTabs.isEditorTabs()) {
int offset = (TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT / 2);
if (myTabs.isSingleRow()) {
@@ -237,7 +237,7 @@ public class TabLabel extends JPanel {
return 2;
}
private int getSelectedOffset() {
protected int getSelectedOffset() {
return myTabs.isEditorTabs() ? -(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT / 2) + 1 : 1;
}
@@ -53,7 +53,11 @@ public abstract class UndoRedoAction extends DumbAwareAction {
}
UndoManager undoManager = getUndoManager(editor, dataContext);
presentation.setEnabled(undoManager != null && isAvailable(editor, undoManager));
if (undoManager == null) {
presentation.setEnabled(false);
return;
}
presentation.setEnabled(isAvailable(editor, undoManager));
Pair<String, String> pair = getActionNameAndDescription(editor, undoManager);
@@ -162,13 +162,13 @@ public class SocketLock {
try {
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeUTF(ACTIVATE_COMMAND + StringUtil.join(args, "\0"));
out.flush();
String response = in.readUTF();
if (response.equals("ok")) {
return ActivateStatus.ACTIVATED;
}
}
catch(IOException e) {
}
return ActivateStatus.CANNOT_ACTIVATE;
}
@@ -111,7 +111,17 @@ public class StartupUtil {
}
if (activateStatus != SocketLock.ActivateStatus.NO_INSTANCE) {
showError("Error", "Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() + " can be run at a time.");
if (isHeadless()) { //team server inspections
System.out.println("Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() + " can be run at a time.");
return false;
}
if (activateStatus == SocketLock.ActivateStatus.CANNOT_ACTIVATE) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
"Only one instance of " + ApplicationNamesInfo.getInstance().getFullProductName() +
" can be run at a time.",
"Error",
JOptionPane.INFORMATION_MESSAGE);
}
return false;
}
@@ -133,6 +133,7 @@ public class EventLog implements Notifications {
mainText += content;
}
mainText = StringUtil.replace(mainText, "&nbsp;", " ");
int nlIndex = eolIndex(mainText);
if (nlIndex >= 0) {
mainText = mainText.substring(0, nlIndex);
@@ -329,6 +330,7 @@ public class EventLog implements Notifications {
group.add(new DumbAwareAction("Mark all as read", "Mark all unread notifications as read", IconLoader.getIcon("/general/reset.png")) {
@Override
public void update(AnActionEvent e) {
if (project.isDisposed()) return;
e.getPresentation().setEnabled(!getProjectComponent(project).myProjectModel.getNotifications().isEmpty());
}
@@ -314,13 +314,6 @@ public class NotificationsManagerImpl extends NotificationsManager implements No
.setHideOnKeyOutside(hideOnClickOutside).setHideOnFrameResize(false);
final Balloon balloon = builder.createBalloon();
balloon.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
notification.setBalloon(null);
}
});
notification.setBalloon(balloon);
return balloon;
}
@@ -57,6 +57,11 @@ public class CommandProcessorImpl extends CommandProcessorEx {
myUndoConfirmationPolicy = undoConfirmationPolicy;
myDocument = document;
}
@Override
public String toString() {
return "'" + myName + "', group: '" + myGroupId + "'";
}
}
private CommandDescriptor myCurrentCommand = null;
@@ -219,7 +224,8 @@ public class CommandProcessorImpl extends CommandProcessorEx {
}
public void leaveModal() {
CommandLog.LOG.assertTrue(myCurrentCommand == null);
CommandLog.LOG.assertTrue(myCurrentCommand == null, "Command must not run: " + String.valueOf(myCurrentCommand));
myCurrentCommand = myInterruptedCommands.pop();
if (myCurrentCommand != null) {
fireCommandStarted();
@@ -22,6 +22,7 @@ import com.intellij.openapi.wm.IdeFrame;
import com.intellij.ui.docking.DockContainer;
import com.intellij.ui.docking.DockContainerFactory;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.docking.DockableContent;
import org.jdom.Element;
public class DockableEditorContainerFactory implements DockContainerFactory.Persistent {
@@ -39,7 +40,7 @@ public class DockableEditorContainerFactory implements DockContainerFactory.Pers
}
@Override
public DockContainer createContainer() {
public DockContainer createContainer(DockableContent content) {
return createContainer(false);
}
@@ -187,7 +187,7 @@ public class DockableEditorTabbedContainer implements DockContainer.Persistent {
}
@Override
public JComponent getComponent() {
public JComponent getContainerComponent() {
return mySplitters;
}
@@ -196,7 +196,7 @@ public class DockableEditorTabbedContainer implements DockContainer.Persistent {
}
public void close(VirtualFile file) {
mySplitters.getCurrentWindow().closeFile(file);
mySplitters.closeFile(file, false);
}
@Override
@@ -586,6 +586,31 @@ public class EditorsSplitters extends JPanel {
return null;
}
void closeFile(VirtualFile file, boolean moveFocus) {
final List<EditorWindow> windows = findWindows(file);
if (!windows.isEmpty()) {
final VirtualFile nextFile = findNextFile(file);
for (final EditorWindow window : windows) {
LOG.assertTrue(window.getSelectedEditor() != null);
window.closeFile(file, false, moveFocus);
if (window.getTabCount() == 0 && nextFile != null) {
EditorWithProviderComposite newComposite = myManager.newEditorComposite(nextFile);
window.setEditor(newComposite, moveFocus); // newComposite can be null
}
}
// cleanup windows with no tabs
for (final EditorWindow window : windows) {
if (window.isDisposed()) {
// call to window.unsplit() which might make its sibling disposed
continue;
}
if (window.getTabCount() == 0) {
window.unsplit(false);
}
}
}
}
private final class MyFocusTraversalPolicy extends IdeFocusTraversalPolicy {
public final Component getDefaultComponentImpl(final Container focusCycleRoot) {
if (myCurrentWindow != null) {
@@ -556,33 +556,12 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
assertDispatchThread();
runChange(new FileEditorManagerChange() {
public void run(EditorsSplitters splitters) {
final List<EditorWindow> windows = splitters.findWindows(file);
if (!windows.isEmpty()) {
final VirtualFile nextFile = splitters.findNextFile(file);
for (final EditorWindow window : windows) {
LOG.assertTrue(window.getSelectedEditor() != null);
window.closeFile(file, false, moveFocus);
if (window.getTabCount() == 0 && nextFile != null) {
EditorWithProviderComposite newComposite = newEditorComposite(nextFile);
window.setEditor(newComposite, moveFocus); // newComposite can be null
}
}
// cleanup windows with no tabs
for (final EditorWindow window : windows) {
if (window.isDisposed()) {
// call to window.unsplit() which might make its sibling disposed
continue;
}
if (window.getTabCount() == 0) {
window.unsplit(false);
}
}
}
splitters.closeFile(file, moveFocus);
}
}, closeAllCopies ? null : getActiveSplitters(true).getResult());
}
//-------------------------------------- Open File ----------------------------------------
//-------------------------------------- Open File ----------------------------------------
@NotNull
public Pair<FileEditor[], FileEditorProvider[]> openFileWithProviders(@NotNull final VirtualFile file,
@@ -865,7 +844,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
@Nullable
private EditorWithProviderComposite newEditorComposite(final VirtualFile file) {
EditorWithProviderComposite newEditorComposite(final VirtualFile file) {
if (file == null) {
return null;
}
@@ -220,11 +220,11 @@ public class GlassPaneDialogWrapperPeer extends DialogWrapperPeer implements Foc
}
public boolean isVisible() {
return myDialog.isVisible();
return myDialog != null && myDialog.isVisible();
}
public boolean isShowing() {
return myDialog.isShowing();
return myDialog != null && myDialog.isShowing();
}
public void setSize(final int width, final int height) {
@@ -188,6 +188,7 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
return ioFile;
}
// todo[r.sh] use NIO2 API after migration to JDK 7
// returns -1 if could not get attributes
@MagicConstant(flags = {BA_EXISTS, BA_REGULAR, BA_DIRECTORY, BA_HIDDEN})
private static int getBooleanAttributes(@NotNull File f) {
@@ -196,8 +197,7 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
Object flags = JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD.invoke(JAVA_IO_FILESYSTEM, f);
return ((Integer)flags).intValue();
}
catch (Exception ignored) {
}
catch (Exception ignored) { }
}
return -1;
}
@@ -535,7 +535,9 @@ public abstract class LocalFileSystemBase extends LocalFileSystem {
public byte[] contentsToByteArray(@NotNull final VirtualFile file) throws IOException {
final FileInputStream stream = new FileInputStream(convertToIOFileAndCheck(file));
try {
return FileUtil.loadBytes(stream, (int)file.getLength());
final int length = (int)file.getLength();
assert length >= 0 : file;
return FileUtil.loadBytes(stream, length);
}
finally {
stream.close();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -508,7 +508,9 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent {
}
else {
try {
return FileUtil.loadBytes(contentStream, (int)file.getLength());
final int length = (int)file.getLength();
assert length >= 0 : file;
return FileUtil.loadBytes(contentStream, length);
}
catch (IOException e) {
throw FSRecords.handleError(e);
@@ -122,7 +122,7 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
@Override
public IdeFrame getIdeFrame(DockContainer container) {
Component parent = UIUtil.findUltimateParent(container.getComponent());
Component parent = UIUtil.findUltimateParent(container.getContainerComponent());
if (parent instanceof IdeFrame) {
return (IdeFrame)parent;
}
@@ -143,7 +143,7 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
if (c == null) return null;
for (DockContainer eachContainer : myContainers) {
if (SwingUtilities.isDescendingFrom(c, eachContainer.getComponent())) {
if (SwingUtilities.isDescendingFrom(c, eachContainer.getContainerComponent())) {
return eachContainer;
}
}
@@ -152,7 +152,7 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
if (parent == null) return null;
for (DockContainer eachContainer : myContainers) {
if (parent == UIUtil.findUltimateParent(eachContainer.getComponent())) {
if (parent == UIUtil.findUltimateParent(eachContainer.getContainerComponent())) {
return eachContainer;
}
}
@@ -354,8 +354,8 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
return myFactories.get(type);
}
private void createNewDockContainerFor(DockableContent content, RelativePoint point) {
DockContainer container = getFactory(content.getDockContainerType()).createContainer();
public void createNewDockContainerFor(DockableContent content, RelativePoint point) {
DockContainer container = getFactory(content.getDockContainerType()).createContainer(content);
register(container);
final DockWindow window = createWindowFor(null, container);
@@ -424,7 +424,7 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
center.add(myNorthPanel, BorderLayout.NORTH);
myDockContentUiContainer = new NonOpaquePanel(new BorderLayout());
myDockContentUiContainer.add(myContainer.getComponent(), BorderLayout.CENTER);
myDockContentUiContainer.add(myContainer.getContainerComponent(), BorderLayout.CENTER);
center.add(myDockContentUiContainer, BorderLayout.CENTER);
myUiContainer.add(center, BorderLayout.CENTER);
@@ -227,7 +227,7 @@ group.reopen.mac.text=Open _Recent
group.$LRU.description=List of recently opened projects
action.CloseProject.text=Close Pro_ject
action.CloseProject.description=Close current project
action.ShowSettings.text=Se_ttings
action.ShowSettings.text=Se_ttings...
action.ShowSettings.description=Configure application settings
action.ShowProjectStructureSettings.text=Pro_ject Structure...
action.ShowProjectStructureSettings.description=Configure project structure
@@ -1147,7 +1147,7 @@ group.EditSelectGroup.text=Editor Select Actions
group.EditCreateDeleteGroup.text=Editor Create/Delete Actions
group.CutCopyPasteGroup.text=Cut/Copy/Paste Actions
group.EditSelectWordGroup.text=Select Word Actions
group.EditBookmarksGroup.text=Bookmarks
group.EditBookmarksGroup.text=Boo_kmarks
group.OpenProjectGroup.text=Open Project Actions
group.EditSmartGroup.text=Edit Code Actions
group.ProjectViewGroup.text=Project View Actions
@@ -133,6 +133,8 @@ tests.passed.with.warnings.message=Tests passed (with warnings)
junit.run.hide.passed.action.name=Hide Passed
junit.run.hide.passed.action.description=Hide passed tests
junit.runing.info.track.test.action.name=Track Running Test
junit.runing.info.sort.alphabetically.action.name=Sort Alphabetically
junit.runing.info.sort.alphabetically.action.description=Sort tests or suites alphabetically
junit.runing.info.track.test.action.description=Select currently running test in tree
junit.runing.info.collapse.test.action.name=Collapse all test suites
junit.runing.info.expand.test.action.name=Expand all test suites
@@ -728,18 +728,14 @@
</group>
<group id="RunnerLayoutActions">
<group id="Runner.Layout" icon="/debugger/restoreLayout.png" popup="true">
<action id="Runner.RestoreLayout" class="com.intellij.execution.ui.layout.actions.RestoreLayoutAction"/>
<action id="Runner.ToggleToolbarLayout" class="com.intellij.execution.ui.layout.actions.ToggleToolbarLayoutAction"/>
<group id="Runner.Layout" icon="/debugger/restoreLayout.png">
<action id="Runner.RestoreLayout" class="com.intellij.execution.ui.layout.actions.RestoreLayoutAction"
icon="/debugger/restoreLayout.png"/>
<!--action id="Runner.ToggleToolbarLayout" class="com.intellij.execution.ui.layout.actions.ToggleToolbarLayoutAction"/-->
</group>
<group id="Runner.View.Popup">
<action id="Runner.MoveViewToGrid" class="com.intellij.execution.ui.layout.actions.MoveToGridAction" icon="/debugger/toGrid.png"/>
<action id="Runner.MoveViewToTab" class="com.intellij.execution.ui.layout.actions.MoveToTabAction" icon="/debugger/toTab.png"/>
<action id="Runner.DetachCell" class="com.intellij.execution.ui.layout.actions.DetachCellAction" icon="/debugger/detach.png"/>
<action id="Runner.AttachCell" class="com.intellij.execution.ui.layout.actions.AttachCellAction" icon="/debugger/attach.png"/>
<separator/>
<action id="Runner.MinimizeView" class="com.intellij.execution.ui.layout.actions.MinimizeViewAction" icon="/actions/minimize.png"/>
<separator/>
<action id="Runner.CloseView" class="com.intellij.execution.ui.layout.actions.CloseViewAction" icon="/actions/cross.png"/>
@@ -753,10 +749,6 @@
<group id="Runner.View.Toolbar">
<reference ref="Runner.MoveViewToGrid"/>
<reference ref="Runner.MoveViewToTab"/>
<reference ref="Runner.DetachCell"/>
<reference ref="Runner.AttachCell"/>
<reference ref="Runner.MinimizeView"/>
<reference ref="Runner.CloseView"/>
</group>
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.notification;
import com.intellij.testFramework.UsefulTestCase;
/**
* @author peter
*/
class EventLogTest extends UsefulTestCase {
public void testNbsp() {
def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello&nbsp;world", NotificationType.ERROR))
assert entry.message == 'Title: Hello world'
}
}
@@ -0,0 +1,580 @@
package com.intellij.openapi.fileEditor;
import com.intellij.codeStyle.CodeStyleFacade;
import com.intellij.codeStyle.DefaultCodeStyleFacade;
import com.intellij.mock.MockCommandProcessor;
import com.intellij.mock.MockEditorFactory;
import com.intellij.mock.MockVirtualFile;
import com.intellij.mock.MockVirtualFileManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.fileTypes.*;
import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl;
import com.intellij.openapi.fileTypes.impl.InternalFileTypeFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectLocator;
import com.intellij.openapi.project.impl.DefaultProjectLocator;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.testFramework.MockSchemesManagerFactory;
import com.intellij.testFramework.PlatformLiteFixture;
import com.intellij.util.LocalTimeCounter;
import org.jetbrains.annotations.NotNull;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Arrays;
public class FileDocumentManagerImplTest extends PlatformLiteFixture {
private MyFileDocumentManagerImpl myDocumentManager;
@Override
protected void setUp() throws Exception {
super.setUp();
initApplication();
registerExtension(FileTypeFactory.FILE_TYPE_FACTORY_EP, new InternalFileTypeFactory());
registerExtensionPoint(FileDocumentSynchronizationVetoer.EP_NAME, FileDocumentSynchronizationVetoer.class);
getApplication().registerService(CommandProcessor.class, new MyMockCommandProcessor());
getApplication().registerService(CodeStyleFacade.class, new DefaultCodeStyleFacade());
getApplication().registerService(ProjectLocator.class, new DefaultProjectLocator());
MockEditorFactory editorFactory = new MockEditorFactory();
getApplication().registerService(EditorFactory.class, editorFactory);
final LanguageFileType[] fileType = {null};
getApplication().addComponent(FileTypeManager.class, new FileTypeManagerImpl(null, new MockSchemesManagerFactory()){
@NotNull
@Override
public FileType getFileTypeByFileName(@NotNull String fileName) {
return fileType[0];
}
@NotNull
@Override
public FileType getFileTypeByFile(@NotNull VirtualFile file) {
return fileType[0];
}
@NotNull
@Override
public FileType getFileTypeByExtension(@NotNull String extension) {
return fileType[0];
}
});
fileType[0] = StdFileTypes.JAVA;
getApplication().getComponent(FileTypeManager.class);
myDocumentManager = new MyFileDocumentManagerImpl();
getApplication().registerService(FileDocumentManager.class, myDocumentManager);
}
public void testGetCachedDocument_Cached() throws Exception {
final Document cachedDocument = myDocumentManager.getCachedDocument(new MockVirtualFile("test.txt"));
assertNull(cachedDocument);
}
public void testGetCachedDocument_NotCached() throws Exception {
final VirtualFile file = newTextFile();
final Document document = myDocumentManager.getDocument(file);
assertSame(myDocumentManager.getCachedDocument(file), document);
}
public void testGetDocument_CreateNew() throws Exception {
final VirtualFile file = newTextFile();
final Document document = myDocumentManager.getDocument(file);
assertNotNull(document);
assertEquals("test", document.getText());
assertEquals(file.getModificationStamp(), document.getModificationStamp());
assertEquals(file.isWritable(), document.isWritable());
}
public void testGetDocument_CreateNew_ReadOnly() throws Exception {
final MockVirtualFile file = newTextFile();
file.setWritable(false);
final Document document = myDocumentManager.getDocument(file);
assertNotNull(document);
assertEquals("test", document.getText());
assertEquals(file.getModificationStamp(), document.getModificationStamp());
assertEquals(file.isWritable(), document.isWritable());
}
public void testGetDocument_ReturnCachedValueTwice() throws Exception {
final VirtualFile file = newTextFile();
final Document document = myDocumentManager.getDocument(file);
assertNotNull(document);
assertEquals("test", document.getText());
final Document document2 = myDocumentManager.getDocument(file);
assertSame(document2, document);
}
public void testGetDocument_CreatesNewAfterGced() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
int idCode = System.identityHashCode(document);
//noinspection UnusedAssignment
document = null;
System.gc();
System.gc();
document = myDocumentManager.getDocument(file);
assertTrue(idCode != System.identityHashCode(document));
}
public void testGetUnsavedDocuments_NoDocuments() throws Exception {
final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments();
assertEquals(0, unsavedDocuments.length);
}
public void testGetUnsavedDocuments_CreatedDocument() throws Exception {
final VirtualFile file = newTextFile();
myDocumentManager.getDocument(file);
final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments();
assertEquals(0, unsavedDocuments.length);
}
public void testGetUnsavedDocuments_ModifiedDocument() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments();
assertEquals(1, unsavedDocuments.length);
assertSame(document, unsavedDocuments[0]);
assertTrue(Arrays.equals("test".getBytes(), file.contentsToByteArray()));
}
public void testGetUnsavedDocuments_afterSaveAllDocuments() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
myDocumentManager.saveAllDocuments();
final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments();
assertEquals(0, unsavedDocuments.length);
}
public void testGetUnsavedDocuments_afterSaveDocuments() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
myDocumentManager.saveDocument(document);
final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments();
assertEquals(0, unsavedDocuments.length);
}
private static MockVirtualFile newTextFile() {
return new MockVirtualFile("test.txt", "test");
}
public void testGetUnsavedDocuments_afterSaveDocumentWithProblems() throws Exception {
final VirtualFile file = new MockVirtualFile("test.txt", "test") {
@Override
@NotNull
public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException {
throw new IOException("");
}
};
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
myDocumentManager.saveDocument(document);
assertNotNull(myDocumentManager.myExceptionOnSave);
final Document[] unsavedDocuments = myDocumentManager.getUnsavedDocuments();
assertEquals(1, unsavedDocuments.length);
assertSame(document, unsavedDocuments[0]);
assertTrue(Arrays.equals("test".getBytes(), file.contentsToByteArray()));
}
public void testUnsavedDocument_DontGc() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
int idCode = System.identityHashCode(document);
//noinspection UnusedAssignment
document = null;
System.gc();
System.gc();
document = myDocumentManager.getDocument(file);
assertEquals(idCode, System.identityHashCode(document));
}
public void testUnsavedDocument_GcAfterSave() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
int idCode = System.identityHashCode(document);
//noinspection UnusedAssignment
document = null;
myDocumentManager.saveAllDocuments();
System.gc();
System.gc();
document = myDocumentManager.getDocument(file);
assertTrue(idCode != System.identityHashCode(document));
}
public void testSaveDocument_DocumentWasntChanged() throws Exception {
final VirtualFile file = newTextFile();
final long stamp = file.getModificationStamp();
Document document = myDocumentManager.getDocument(file);
myDocumentManager.saveDocument(document);
assertEquals(stamp, file.getModificationStamp());
}
public void testSaveDocument_DocumentWasChanged() throws Exception {
final VirtualFile file = newTextFile();
final long stamp = file.getModificationStamp();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
myDocumentManager.saveDocument(document);
assertTrue(stamp != file.getModificationStamp());
assertEquals(document.getModificationStamp(), file.getModificationStamp());
assertTrue(Arrays.equals("xxxtest".getBytes(), file.contentsToByteArray()));
}
public void testSaveAllDocuments_DocumentWasChanged() throws Exception {
final VirtualFile file = newTextFile();
final long stamp = file.getModificationStamp();
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
myDocumentManager.saveAllDocuments();
assertTrue(stamp != file.getModificationStamp());
assertTrue(Arrays.equals("xxxtest".getBytes(), file.contentsToByteArray()));
}
public void testGetFile() throws Exception {
final VirtualFile file = newTextFile();
Document document = myDocumentManager.getDocument(file);
assertSame(file, myDocumentManager.getFile(document));
}
public void testConvertSeparators() throws Exception {
final VirtualFile file = new MockVirtualFile("test.txt", "test\rtest");
Document document = myDocumentManager.getDocument(file);
assertEquals("test\ntest", document.getText());
}
public void testRememberSeparators() throws Exception {
final VirtualFile file = new MockVirtualFile("test.txt", "test\rtest");
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
myDocumentManager.saveAllDocuments();
assertTrue(Arrays.equals("xxxtest\rtest".getBytes(), file.contentsToByteArray()));
}
public void testContentChanged_noDocument() throws Exception {
final MockVirtualFile file = new MockVirtualFile("test.txt", "test\rtest");
file.setListener(myDocumentManager);
file.setContent(null, "xxx", true);
assertNull(myDocumentManager.getCachedDocument(file));
}
public void testContentChanged_documentPresent() throws Exception {
final MockVirtualFile file = new MockVirtualFile("test.txt", "test\rtest");
file.setListener(myDocumentManager);
Document document = myDocumentManager.getDocument(file);
file.setContent(null, "xxx", true);
assertEquals("xxx", document.getText());
assertEquals(file.getModificationStamp(), document.getModificationStamp());
}
public void testContentChanged_ignoreEventsFromSelf() throws Exception {
final MockVirtualFile file = new MockVirtualFile("test.txt", "test\rtest");
file.setListener(myDocumentManager);
Document document = myDocumentManager.getDocument(file);
file.setContent(myDocumentManager, "xxx", true);
assertEquals("test\ntest", document.getText());
}
public void testContentChanged_ignoreEventsFromSelfOnSave() throws Exception {
final VirtualFile file = new MockVirtualFile("test.txt", "test\rtest") {
public Writer getWriter(final Object requestor, final long newModificationStamp) {
final VirtualFile self = this;
return new CharArrayWriter() {
@Override
public void close() {
super.close();
long oldStamp = getModificationStamp();
setModificationStamp(newModificationStamp);
setText(toString());
myDocumentManager.contentsChanged(new VirtualFileEvent(requestor, self, null, oldStamp, getModificationStamp()));
}
};
}
};
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "xxx");
final long stamp = document.getModificationStamp();
myDocumentManager.saveAllDocuments();
assertEquals(stamp, document.getModificationStamp());
}
public void testContentChanged_reloadChangedDocument() throws Exception {
final MockVirtualFile file = new MockVirtualFile("test.txt", "test\rtest");
file.setListener(myDocumentManager);
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "zzz");
myDocumentManager.myReloadFromDisk = Boolean.TRUE;
try {
file.setContent(null, "xxx", true);
assertEquals("xxx", document.getText());
assertEquals(file.getModificationStamp(), document.getModificationStamp());
assertEquals(0, myDocumentManager.getUnsavedDocuments().length);
}
finally {
myDocumentManager.myReloadFromDisk = null;
}
}
public void testContentChanged_dontreloadChangedDocument() throws Exception {
final MockVirtualFile file = newTextFile();
file.setListener(myDocumentManager);
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "zzz");
myDocumentManager.myReloadFromDisk = Boolean.FALSE;
try {
long oldDocumentStamp = document.getModificationStamp();
file.setContent(null, "xxx", true);
assertEquals("zzztest", document.getText());
assertEquals(oldDocumentStamp, document.getModificationStamp());
}
finally {
myDocumentManager.myReloadFromDisk = null;
}
}
public void testSaveDocument_dontSaveIfModStampEqualsToFile() throws Exception {
final VirtualFile file = new MockVirtualFile("test.txt", "test") {
@NotNull
@Override
public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException {
fail();
throw new IOException();
}
};
DocumentEx document = (DocumentEx)myDocumentManager.getDocument(file);
document.insertString(0, "zzz");
document.setModificationStamp(file.getModificationStamp());
myDocumentManager.saveDocument(document);
}
// this test requires changes in idea code to support MockFile as local file system file (FileDocumentManager.needsRefresh).
// TODO: think how to test this functionality without hacking production code
public void atestContentChanged_reloadChangedDocumentOnSave() throws Exception {
final MockVirtualFile file = new MockVirtualFile("test.txt", "test\rtest") {
@Override
public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) {
long oldStamp = getModificationStamp();
setModificationStamp(LocalTimeCounter.currentTime());
myDocumentManager.contentsChanged(new VirtualFileEvent(null, this, null, oldStamp, getModificationStamp()));
}
};
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "zzz");
file.setContent(null, "xxx", false);
myDocumentManager.myReloadFromDisk = Boolean.TRUE;
try {
file.setActualTimeStamp(file.getTimeStamp() + 1);
myDocumentManager.saveAllDocuments();
long fileStamp = file.getModificationStamp();
assertEquals("xxx", document.getText());
assertEquals(file.getModificationStamp(), document.getModificationStamp());
assertEquals(file.getModificationStamp(), fileStamp);
assertEquals(0, myDocumentManager.getUnsavedDocuments().length);
}
finally {
myDocumentManager.myReloadFromDisk = null;
}
}
public void testContentChanged_dontreloadChangedDocumentOnSave() throws Exception {
final MockVirtualFile file = new MockVirtualFile("test.txt", "test") {
@Override
public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) {
long oldStamp = getModificationStamp();
setModificationStamp(LocalTimeCounter.currentTime());
myDocumentManager.contentsChanged(new VirtualFileEvent(null, this, null, oldStamp, getModificationStamp()));
}
};
myDocumentManager.myReloadFromDisk = Boolean.FALSE;
try {
Document document = myDocumentManager.getDocument(file);
document.insertString(0, "zzz");
long documentStamp = document.getModificationStamp();
file.setContent(null, "xxx", false);
file.setActualTimeStamp(file.getTimeStamp() + 1);
myDocumentManager.saveAllDocuments();
assertEquals("zzztest", document.getText());
assertEquals(file.getModificationStamp(), document.getModificationStamp());
assertTrue(Arrays.equals("zzztest".getBytes(), file.contentsToByteArray()));
assertEquals(documentStamp, document.getModificationStamp());
}
finally {
myDocumentManager.myReloadFromDisk = null;
}
}
public void testReplaceDocumentTestWithTheSameTest() throws Exception {
final boolean[] canCallSave = {true};
final VirtualFile file = new MockVirtualFile("test.txt", "test") {
@NotNull
@Override
public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException {
if (!canCallSave[0]) fail();
return super.getOutputStream(requestor, newModificationStamp, newTimeStamp);
}
};
DocumentEx document = (DocumentEx)myDocumentManager.getDocument(file);
String newText = "test text";
document.replaceString(0, document.getTextLength(), newText);
assertTrue(myDocumentManager.isDocumentUnsaved(document));
myDocumentManager.saveDocument(document);
canCallSave[0] = false;
final long modificationStamp = document.getModificationStamp();
document.replaceString(0, document.getTextLength(), newText);
if (myDocumentManager.isDocumentUnsaved(document)) {
assertTrue(document.getModificationStamp() > modificationStamp);
}
else {
assertEquals(modificationStamp, document.getModificationStamp());
}
}
public void testExternalReplaceWithTheSameText() throws Exception{
final long[] modificationStamp = new long[1];
modificationStamp[0] = 1;
final VirtualFile file = new MockVirtualFile("test.txt", "test") {
@NotNull
@Override
public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) throws IOException {
fail();
throw new IOException();
}
@Override
public long getModificationStamp() {
return modificationStamp[0];
}
@Override
public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) {
myDocumentManager.contentsChanged(new VirtualFileEvent(null, this, null, 1, 2));
}
};
DocumentEx document = (DocumentEx)myDocumentManager.getDocument(file);
modificationStamp[0] = 2;
file.refresh(false, false);
assertEquals(2, document.getModificationStamp());
}
public static class MyFileDocumentManagerImpl extends FileDocumentManagerImpl {
public static final FileDocumentManagerListener[] LISTENERS = new FileDocumentManagerListener[0];
public IOException myExceptionOnSave;
public Boolean myReloadFromDisk = null;
public MyFileDocumentManagerImpl() {
super(new MockVirtualFileManager());
}
@Override
protected void reportErrorOnSave(IOException e) {
myExceptionOnSave = e;
}
@Override
protected boolean askReloadFromDisk(VirtualFile file, Document document) {
if (myReloadFromDisk == null){
fail();
return false;
}
else{
return myReloadFromDisk.booleanValue();
}
}
@NotNull
@Override
protected FileDocumentManagerListener[] getListeners() {
return LISTENERS;
}
}
private static class MyMockCommandProcessor extends MockCommandProcessor {
@Override
public void executeCommand(Project project, @NotNull Runnable runnable, String name, Object groupId) {
runnable.run();
}
@Override
public void executeCommand(Project project,
@NotNull Runnable runnable,
String name,
Object groupId,
@NotNull UndoConfirmationPolicy confirmationPolicy,
Document document) {
runnable.run();
}
@Override
public void executeCommand(Project project,
@NotNull Runnable runnable,
String name,
Object groupId,
@NotNull UndoConfirmationPolicy confirmationPolicy) {
runnable.run();
}
@Override
public void executeCommand(@NotNull Runnable runnable, String name, Object groupId) {
runnable.run();
}
}
}

Some files were not shown because too many files have changed in this diff Show More