Merge remote-tracking branch 'origin/master'

This commit is contained in:
Maxim.Medvedev
2012-02-11 11:11:23 +04:00
123 changed files with 1748 additions and 420 deletions
@@ -284,13 +284,7 @@ public class CompileServerManager implements ApplicationComponent{
}
try {
for (RequestFuture future : futures) {
try {
future.get();
}
catch (InterruptedException ignored) {
}
catch (java.util.concurrent.ExecutionException ignored) {
}
future.waitFor();
}
}
finally {
@@ -447,7 +441,7 @@ public class CompileServerManager implements ApplicationComponent{
connected = client.connect(NetUtils.getLocalHostString(), port);
if (connected) {
final RequestFuture setupFuture = sendSetupRequest(client);
setupFuture.get();
setupFuture.waitFor();
myProcessHandler = processHandler;
myClient = client;
}
@@ -99,7 +99,7 @@ import org.jetbrains.jps.api.RequestFuture;
import java.io.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class CompileDriver {
@@ -591,15 +591,10 @@ public class CompileDriver {
final Set<Artifact> artifacts = ArtifactCompileScope.getArtifactsToBuild(myProject, compileContext.getCompileScope(), true);
final RequestFuture future = compileOnServer(compileContext, modules, artifacts, paths, callback);
if (future != null) {
try {
startCancelWatcher(indicator, future);
future.get();
}
catch (InterruptedException e) {
LOG.error(e); // todo
}
catch (ExecutionException e) {
LOG.error(e); // todo
while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) {
if (indicator.isCanceled()) {
future.cancel(true);
}
}
}
else {
@@ -686,27 +681,6 @@ public class CompileDriver {
});
}
private static void startCancelWatcher(final ProgressIndicator indicator, final RequestFuture future) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(200L);
if (future.isDone() || future.isCancelled()) {
break;
}
if (indicator.isCanceled()) {
future.cancel(true);
break;
}
}
catch (InterruptedException ignored) {
}
}
}
});
}
private static List<String> fetchFiles(CompileContextImpl context) {
if (context.isRebuild()) {
return Collections.emptyList();
@@ -590,7 +590,7 @@ public class ExpectedTypesProvider {
}
return;
}
PsiExpression anotherExpr = index > 0 ? operands[0] : operands[1];
PsiExpression anotherExpr = index > 0 ? operands[0] : index < operands.length ? operands[1] : null;
PsiType anotherType = anotherExpr != null ? anotherExpr.getType() : null;
IElementType i = expr.getOperationTokenType();
if (i == JavaTokenType.MINUS ||
@@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
@@ -247,6 +248,38 @@ public class AnnotationsHighlightUtil {
return highlightInfo;
}
public static HighlightInfo checkForeignInnerClassesUsed(final PsiAnnotation annotation) {
final HighlightInfo[] infos = new HighlightInfo[1];
final PsiAnnotationOwner owner = annotation.getOwner();
if (owner instanceof PsiModifierList) {
final PsiElement parent = ((PsiModifierList)owner).getParent();
if (parent instanceof PsiClass) {
annotation.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitElement(PsiElement element) {
if (infos[0] != null) return;
super.visitElement(element);
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
final PsiElement resolve = expression.resolve();
if (resolve instanceof PsiField &&
((PsiMember)resolve).hasModifierProperty(PsiModifier.PRIVATE) &&
PsiTreeUtil.isAncestor(parent, resolve, true)) {
String description = JavaErrorMessages.message("private.symbol",
HighlightUtil.formatField((PsiField)resolve),
HighlightUtil.formatClass((PsiClass)parent));
infos[0] = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, description);
}
}
});
}
}
return infos[0];
}
private static PsiField[] getFields(final PsiClass elementTypeClass, @NonNls final String... names) {
PsiField[] result = new PsiField[names.length];
for (int i = 0; i < names.length; i++) {
@@ -498,6 +498,7 @@ public class HighlightMethodUtil {
AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo);
ChangeMethodSignatureFromUsageFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange);
ConvertDoubleToFloatFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange);
WrapExpressionFix.registerWrapAction(methodCandidates, list.getExpressions(), highlightInfo);
ChangeParameterClassFix.registerQuickFixActions(methodCall, list, highlightInfo);
if (methodCandidates.length == 0) {
@@ -1273,6 +1274,7 @@ public class HighlightMethodUtil {
if (classReference != null) {
ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, getFixRange(infoElement));
ChangeMethodSignatureFromUsageFix.registerIntentions(results, list, info, null);
ConvertDoubleToFloatFix.registerIntentions(results, list, info, null);
PermuteArgumentsFix.registerFix(info, constructorCall, toMethodCandidates(results), getFixRange(list));
ChangeParameterClassFix.registerQuickFixActions(constructorCall, list, info);
QuickFixAction.registerQuickFixAction(info, getFixRange(list), new SurroundWithArrayFix(constructorCall), null);
@@ -1014,7 +1014,7 @@ public class HighlightUtil {
}
// true if floating point literal consists of zeros only
private static boolean isFPZero(final String text) {
public static boolean isFPZero(final String text) {
for (int i = 0; i < text.length(); i++) {
final char c = text.charAt(i);
if (Character.isDigit(c) && c != '0') return false;
@@ -184,6 +184,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation));
}
@Override public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) {
@@ -0,0 +1,109 @@
/*
* 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.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
/**
* User: anna
* Date: 2/10/12
*/
public class ConvertDoubleToFloatFix implements IntentionAction {
private final PsiExpression myExpression;
public ConvertDoubleToFloatFix(PsiExpression expression) {
myExpression = expression;
}
@NotNull
@Override
public String getText() {
return "Convert '" + myExpression.getText() + "' to float";
}
@NotNull
@Override
public String getFamilyName() {
return getText();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (myExpression.isValid()) {
if (!StringUtil.endsWithIgnoreCase(myExpression.getText(), "d")) {
final PsiLiteralExpression expression = (PsiLiteralExpression)createFloatingPointExpression(project);
final Object value = expression.getValue();
return value instanceof Float && !((Float)value).isInfinite() && !(((Float)value).floatValue() == 0 && !HighlightUtil.isFPZero(expression.getText()));
}
}
return false;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
myExpression.replace(createFloatingPointExpression(project));
}
private PsiExpression createFloatingPointExpression(Project project) {
return JavaPsiFacade.getElementFactory(project).createExpressionFromText(myExpression.getText() + "f", myExpression);
}
@Override
public boolean startInWriteAction() {
return true;
}
public static void registerIntentions(@NotNull JavaResolveResult[] candidates,
@NotNull PsiExpressionList list,
@NotNull HighlightInfo highlightInfo,
TextRange fixRange) {
if (candidates.length == 0) return;
PsiExpression[] expressions = list.getExpressions();
for (JavaResolveResult candidate : candidates) {
registerIntention(expressions, highlightInfo, fixRange, candidate, list);
}
}
private static void registerIntention(@NotNull PsiExpression[] expressions,
@NotNull HighlightInfo highlightInfo,
TextRange fixRange,
@NotNull JavaResolveResult candidate,
@NotNull PsiElement context) {
if (!candidate.isStaticsScopeCorrect()) return;
PsiMethod method = (PsiMethod)candidate.getElement();
if (method != null && context.getManager().isInProject(method)) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length == expressions.length) {
for (int i = 0, length = parameters.length; i < length; i++) {
PsiParameter parameter = parameters[i];
final PsiExpression expression = expressions[i];
if (expression instanceof PsiLiteralExpression && PsiType.FLOAT.equals(parameter.getType()) && PsiType.DOUBLE.equals(expression.getType())) {
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new ConvertDoubleToFloatFix(expression), null);
}
}
}
}
}
}
@@ -60,7 +60,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
}
//do not show lookup when typing varargs ellipsis
final PsiElement prevSibling = lastElement.getPrevSibling();
final PsiElement prevSibling = PsiTreeUtil.prevVisibleLeaf(lastElement);
if (prevSibling == null || ".".equals(prevSibling.getText())) return false;
PsiElement parent = prevSibling;
do {
@@ -33,6 +33,8 @@ class PackageLookupItem extends LookupItem<PsiPackage> {
@Override
public void handleInsert(InsertionContext context) {
super.handleInsert(context);
AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null);
if (getTailType() == TailType.DOT || context.getCompletionChar() == '.') {
AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor(), null);
}
}
}
@@ -334,6 +334,9 @@ public class VisibilityInspection extends GlobalJavaInspectionTool {
if (accessModifier == PsiModifier.PRIVATE) {
if (SUGGEST_PRIVATE_FOR_INNERS) {
if (isInExtendsList(to, fromTopLevel.getElement().getExtendsList())) return false;
if (isInExtendsList(to, fromTopLevel.getElement().getImplementsList())) return false;
if (isInAnnotations(to, fromTopLevel)) return false;
return fromTopLevel == toOwner || fromOwner == toTopLevel || toOwner != null && refUtil.getOwnerClass(toOwner) == from;
}
@@ -354,6 +357,24 @@ public class VisibilityInspection extends GlobalJavaInspectionTool {
return false;
}
private static boolean isInAnnotations(final RefJavaElement to, final RefClass fromTopLevel) {
final PsiModifierList modifierList = fromTopLevel.getElement().getModifierList();
if (modifierList == null) return false;
final PsiElement toElement = to.getElement();
final boolean [] resolved = new boolean[] {false};
modifierList.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
if (resolved[0]) return;
super.visitReferenceExpression(expression);
if (expression.resolve() == toElement) {
resolved[0] = true;
}
}
});
return resolved[0];
}
private static boolean isInExtendsList(final RefJavaElement to, final PsiReferenceList extendsList) {
if (extendsList != null) {
@@ -15,6 +15,7 @@
*/
package com.intellij.ide.fileTemplates;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
@@ -108,6 +109,26 @@ public class JavaCreateFromTemplateHandler implements CreateFromTemplateHandler
return false;
}
@Override
public boolean isNameRequired() {
return false;
}
@Override
public String getErrorMessage() {
return IdeBundle.message("title.cannot.create.class");
}
@Override
public Properties prepareProperties(Properties props) {
String packageName = props.getProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME);
if(packageName == null || packageName.length() == 0){
props = new Properties(props);
props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME);
}
return props;
}
public static boolean canCreate(PsiDirectory dir) {
return JavaDirectoryService.getInstance().getPackage(dir) != null;
}
@@ -0,0 +1,4 @@
@SuppressWarnings(<error descr="'ThisClass.FOO' has private access in 'ThisClass'">ThisClass.FOO</error>)
public class ThisClass {
private static final String FOO = "foo";
}
@@ -0,0 +1,7 @@
// "Convert '1e1' to float" "true"
class Test {
void bar() {
foo(1e1f);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '2.' to float" "true"
class Test {
void bar() {
foo(2.f);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '.3' to float" "true"
class Test {
void bar() {
foo(.3f);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '0.0' to float" "true"
class Test {
void bar() {
foo(0.0f);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '3.14' to float" "true"
class Test {
void bar() {
foo(3.14f);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '1e1' to float" "true"
class Test {
void bar() {
foo(1e<caret>1);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '2.' to float" "true"
class Test {
void bar() {
foo(2<caret>.);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '.3' to float" "true"
class Test {
void bar() {
foo(.<caret>3);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '0.0' to float" "true"
class Test {
void bar() {
foo(0<caret>.0);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '3.14' to float" "true"
class Test {
void bar() {
foo(3<caret>.14);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '1e-9d' to float" "false"
class Test {
void bar() {
foo(1e-9<caret>d);
}
void foo(float f){}
}
@@ -0,0 +1,7 @@
// "Convert '1e137' to float" "false"
class Test {
void bar() {
foo(1e1<caret>37);
}
void foo(float f){}
}
@@ -4,3 +4,10 @@ End of files
Compiling files:
src/packageA/Base.java
End of files
Cleaning output files:
out/production/OverrideAnnotatedAnonymousNotRecompile/packageA/Derived$1.class
out/production/OverrideAnnotatedAnonymousNotRecompile/packageA/Derived.class
End of files
Compiling files:
src/packageA/Derived.java
End of files
@@ -5,8 +5,10 @@ Compiling files:
src/Base.java
End of files
Cleaning output files:
out/production/DeleteMethodImplementation4/BaseImpl.class
out/production/DeleteMethodImplementation4/BaseImplImpl.class
End of files
Compiling files:
src/BaseImpl.java
src/BaseImplImpl.java
End of files
@@ -4,3 +4,9 @@ End of files
Compiling files:
src/Base.java
End of files
Cleaning output files:
out/production/DeleteMethodImplementation5/BaseImpl.class
End of files
Compiling files:
src/BaseImpl.java
End of files
@@ -4,3 +4,9 @@ End of files
Compiling files:
src/BaseImpl.java
End of files
Cleaning output files:
out/production/DeleteMethodImplementation6/BaseImplImpl.class
End of files
Compiling files:
src/BaseImplImpl.java
End of files
@@ -0,0 +1,13 @@
class SelectLeafFirst {
void aaa(){}
<caret>
void bbb(){}
void clear(){}
void zzz(){}
class ClearClass {
void kkk(){}
void www(){}
void clear(){}
void yyy(){}
}
}
@@ -0,0 +1,5 @@
-SelectLeafFirst.java
-SelectLeafFirst
[clear():void]
-ClearClass
clear():void
@@ -0,0 +1,13 @@
class SelectLeafFirst2 {
void aaa(){}
void bbb(){}
void clear(){}
void zzz(){}
class ClearClass {
void kkk(){}
<caret>
void www(){}
void clear(){}
void yyy(){}
}
}
@@ -0,0 +1,5 @@
-SelectLeafFirst2.java
-SelectLeafFirst2
clear():void
-ClearClass
[clear():void]
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>ThisClass.java</file>
<line>5</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Declaration access can be weaker</problem_class>
<hints>
<hint value="packageLocal" />
</hints>
<description>Can be package local</description>
</problem>
<problem>
<file>ThisClass.java</file>
<line>4</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Declaration access can be weaker</problem_class>
<hints>
<hint value="packageLocal" />
</hints>
<description>Can be package local</description>
</problem>
</problems>
@@ -0,0 +1,9 @@
import java.util.ArrayList;
@SuppressWarnings(ThisClass.PUBLICFINALNAME)
public class ThisClass extends ArrayList<ThisClass.FF> {
public static final String PUBLICFINALNAME = "stuff";
public static class FF {}
public static void main(String[] args) {
}
}
@@ -176,6 +176,10 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
doTest(false, false);
}
public void testHighlightInaccessibleFromClassModifierList() throws Exception {
doTest(false, false);
}
public void testDynamicallyAddIgnoredAnnotations() throws Exception {
ExtensionPoint<EntryPoint> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL);
EntryPoint extension = new EntryPoint() {
@@ -0,0 +1,29 @@
/*
* 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.codeInsight.daemon.quickFix;
/**
* @author cdr
*/
public class ConvertDoubleToFloatFixTest extends LightQuickFix15TestCase {
public void test() throws Exception { doAllTests(); }
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat";
}
}
@@ -102,4 +102,11 @@ public class VisibilityInspectionTest extends InspectionTestCase {
myTool.SUGGEST_PRIVATE_FOR_INNERS = false;
doTest("visibility/typeArguments", myTool, false, true);
}
public void testUsedFromAnnotationsExtendsList() throws Exception {
myTool.SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS = true;
myTool.SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES = true;
myTool.SUGGEST_PRIVATE_FOR_INNERS = true;
doTest("visibility/usedFromAnnotationsExtendsList", myTool, false, true);
}
}
@@ -29,5 +29,7 @@ public class JavaFileStructureFilteringTest extends JavaFileStructureTestCase {
public void testAnonymousType()throws Exception{checkTree("point");}
public void testCamel()throws Exception{checkTree("sohe");}
public void testCamel2()throws Exception{checkTree("soHe");}
public void testSelectLeafFirst()throws Exception{checkTree("clear");}
public void testSelectLeafFirst2()throws Exception{checkTree("clear");}
}
@@ -79,17 +79,34 @@ public class RequestFuture<T> implements Future {
return myDone.get();
}
public Object get() throws InterruptedException, ExecutionException {
while (!isDone()) {
mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS);
public void waitFor() {
try {
while (!isDone()) {
mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS);
}
}
catch (InterruptedException ignored) {
}
}
public boolean waitFor(long timeout, TimeUnit unit) {
try {
if (!isDone()) {
mySemaphore.tryAcquire(timeout, unit);
}
}
catch (InterruptedException ignored) {
}
return isDone();
}
public Object get() throws InterruptedException, ExecutionException {
waitFor();
return null;
}
public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (!isDone()) {
mySemaphore.tryAcquire(timeout, unit);
}
waitFor(timeout, unit);
return null;
}
@@ -23,6 +23,7 @@ import java.util.*;
* Date: 9/17/11
*/
public class CompileContext extends UserDataHolderBase implements MessageHandler{
private static final String CANCELED_MESSAGE = "The build has been canceled";
private final CompileScope myScope;
private final boolean myIsMake;
private final boolean myIsProjectRebuild;
@@ -155,28 +156,39 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
return myCompilingTests;
}
public CanceledStatus getCancelStatus() {
public final CanceledStatus getCancelStatus() {
return myCancelStatus;
}
public final boolean isCanceled() {
return getCancelStatus().isCanceled();
}
public final void checkCanceled() throws ProjectBuildException {
if (isCanceled()) {
throw new ProjectBuildException(CANCELED_MESSAGE);
}
}
void setCompilingTests(boolean compilingTests) {
myCompilingTests = compilingTests;
}
void beforeCompileRound(@NotNull ModuleChunk chunk) {
myFsState.beforeNextRoundStart();
}
public void afterCompileRound() {
myFsState.clearContextRoundData();
}
public void onChunkBuildStart(ModuleChunk chunk) {
myFsState.setContextChunk(chunk);
}
void beforeNextCompileRound(@NotNull ModuleChunk chunk) {
myFsState.beforeNextRoundStart();
}
public void clearContextRoundData() {
myFsState.clearContextRoundData();
}
void onChunkBuildComplete(@NotNull ModuleChunk chunk) throws IOException {
myDataManager.flush(true);
myFsState.clearContextChunk();
if (!myErrorsFound && !myCancelStatus.isCanceled()) {
final boolean compilingTests = isCompilingTests();
@@ -52,6 +52,10 @@ public class FSState {
myContextModules.addAll(chunk.getModules());
}
public void clearContextChunk() {
myContextModules.clear();
}
public void beforeNextRoundStart() {
myLastRoundDelta = myCurrentRoundDelta;
myCurrentRoundDelta = new FilesDelta();
@@ -60,7 +64,6 @@ public class FSState {
public void clearContextRoundData() {
myCurrentRoundDelta = null;
myLastRoundDelta = null;
myContextModules.clear();
}
public void clearRecompile(RootDescriptor rd) {
@@ -24,7 +24,7 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* @author Eugene Zhuravlev
@@ -34,7 +34,6 @@ public class IncProjectBuilder {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder");
public static final String COMPILE_SERVER_NAME = "COMPILE SERVER";
private static final String CANCELED_MESSAGE = "The build has been canceled";
private final ProjectDescriptor myProjectDescriptor;
private final BuilderRegistry myBuilderRegistry;
@@ -119,11 +118,7 @@ public class IncProjectBuilder {
if (descriptor != null) {
try {
final RequestFuture future = descriptor.client.sendShutdownRequest();
future.get();
}
catch (InterruptedException ignored) {
}
catch (ExecutionException ignored) {
future.waitFor(500L, TimeUnit.MILLISECONDS);
}
finally {
// ensure process is not running
@@ -229,9 +224,7 @@ public class IncProjectBuilder {
// check that output and source roots are not overlapping
final List<File> filesToDelete = new ArrayList<File>();
for (File outputRoot : rootsToDelete) {
if (myCancelStatus.isCanceled()) {
throw new ProjectBuildException(CANCELED_MESSAGE);
}
context.checkCanceled();
boolean okToDelete = true;
if (PathUtil.isUnder(allSourceRoots, outputRoot)) {
okToDelete = false;
@@ -389,7 +382,7 @@ public class IncProjectBuilder {
boolean nextPassRequired;
do {
nextPassRequired = false;
context.beforeNextCompileRound(chunk);
context.beforeCompileRound(chunk);
if (!context.isProjectRebuild()) {
syncOutputFiles(context, chunk);
@@ -401,9 +394,7 @@ public class IncProjectBuilder {
if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
}
if (myCancelStatus.isCanceled()) {
throw new ProjectBuildException(CANCELED_MESSAGE);
}
context.checkCanceled();
if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
if (!nextPassRequired) {
// recalculate basis
@@ -440,16 +431,14 @@ public class IncProjectBuilder {
}
while (nextPassRequired);
context.clearContextRoundData();
context.afterCompileRound();
}
}
private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException {
for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
builder.build(context);
if (myCancelStatus.isCanceled()) {
throw new ProjectBuildException(CANCELED_MESSAGE);
}
context.checkCanceled();
}
}
@@ -42,8 +42,8 @@ import java.net.ServerSocket;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author Eugene Zhuravlev
@@ -257,14 +257,19 @@ public class JavaBuilder extends ModuleLevelBuilder {
if (hasSourcesToCompile) {
final Set<File> sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.<File>emptySet());
final String chunkName = chunk.getName();
final String chunkName = getChunkPresentableName(chunk);
context.processMessage(new ProgressMessage("Compiling java [" + chunkName + "]"));
final boolean compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink);
final Map<File, String> chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests());
context.checkCanceled();
final ClassLoader compiledClassesLoader = createInstrumentationClassLoader(classpath, platformCp, chunkSourcePath, outputSink);
context.checkCanceled();
if (!forms.isEmpty()) {
try {
context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]"));
@@ -275,6 +280,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
}
context.checkCanceled();
if (addNotNullAssertions) {
try {
context.processMessage(new ProgressMessage("Adding NotNull assertions [" + chunkName + "]"));
@@ -285,6 +292,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
}
context.checkCanceled();
if (!compiledOk && diagnosticSink.getErrorCount() == 0) {
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Compilation failed: internal java compiler error"));
}
@@ -316,6 +325,24 @@ public class JavaBuilder extends ModuleLevelBuilder {
return exitCode;
}
private static String getChunkPresentableName(ModuleChunk chunk) {
final Set<Module> modules = chunk.getModules();
if (modules.isEmpty()) {
return "<empty>";
}
if (modules.size() == 1) {
return modules.iterator().next().getName();
}
final StringBuilder buf = new StringBuilder();
for (Module module : modules) {
if (buf.length() > 0) {
buf.append(",");
}
buf.append(module.getName());
}
return buf.toString();
}
private boolean compileJava(ModuleChunk chunk, Collection<File> files,
Collection<File> classpath,
Collection<File> platformCp,
@@ -338,14 +365,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest(
options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer
);
try {
future.get();
}
catch (InterruptedException e) {
e.printStackTrace(System.err);
}
catch (ExecutionException e) {
e.printStackTrace(System.err);
while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) {
if (context.isCanceled()) {
future.cancel(true);
}
}
rc = future.getResponseHandler().isTerminatedSuccessfully();
}
@@ -66,6 +66,18 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
return super.isSameFile(a, b);
}
@Override
public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
checkCanceled();
return super.getFileForInput(location, packageName, relativeName);
}
@Override
public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
checkCanceled();
return super.getJavaFileForInput(location, className, kind);
}
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
if (kind != JavaFileObject.Kind.SOURCE && kind != JavaFileObject.Kind.CLASS) {
throw new IllegalArgumentException("Invalid kind " + kind);
@@ -86,6 +98,8 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
}
private OutputFileObject getFileForOutput(Location location, JavaFileObject.Kind kind, String fileName, @Nullable String className, FileObject sibling) throws IOException {
checkCanceled();
JavaFileObject src = null;
if (sibling instanceof JavaFileObject) {
final JavaFileObject javaFileObject = (JavaFileObject)sibling;
@@ -190,4 +204,18 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
return name.toString().replace('.', File.separatorChar);
}
private int myChecksCounter = 0;
private void checkCanceled() {
final int counter = (myChecksCounter + 1) % 10;
myChecksCounter = counter;
if (counter == 0 && myContext.isCanceled()) {
throw new RuntimeException("Compilation canceled") {
@Override
public Throwable fillInStackTrace() {
return this;
}
};
}
}
}
@@ -2,7 +2,6 @@ package org.jetbrains.jps.javac;
import com.intellij.openapi.util.SystemInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.server.ClasspathBootstrap;
@@ -29,13 +28,14 @@ public class JavacMain {
Collection<File> sourcePath,
Map<File, Set<File>> outputDirToRoots,
final DiagnosticOutputConsumer outConsumer,
final OutputFileConsumer outputSink, @Nullable CanceledStatus canceledStatus) {
final OutputFileConsumer outputSink,
CanceledStatus canceledStatus) {
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
for (File outputDir : outputDirToRoots.keySet()) {
outputDir.mkdirs();
}
final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink));
final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus));
fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff
fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff
@@ -111,10 +111,15 @@ public class JavacMain {
private final StandardJavaFileManager myStdManager;
private final DiagnosticOutputConsumer myOutConsumer;
private final OutputFileConsumer myOutputFileSink;
private final CanceledStatus myCanceledStatus;
public ContextImpl(@NotNull JavaCompiler compiler, @NotNull DiagnosticOutputConsumer outConsumer, @NotNull OutputFileConsumer sink) {
public ContextImpl(@NotNull JavaCompiler compiler,
@NotNull DiagnosticOutputConsumer outConsumer,
@NotNull OutputFileConsumer sink,
CanceledStatus canceledStatus) {
myOutConsumer = outConsumer;
myOutputFileSink = sink;
myCanceledStatus = canceledStatus;
StandardJavaFileManager stdManager = null;
final Class<StandardJavaFileManager> optimizedManagerClass = ClasspathBootstrap.getOptimizedFileManagerClass();
if (optimizedManagerClass != null) {
@@ -136,7 +141,7 @@ public class JavacMain {
}
public boolean isCanceled() {
return false; // todo
return myCanceledStatus.isCanceled();
}
public StandardJavaFileManager getStandardFileManager() {
@@ -11,9 +11,9 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.api.CanceledStatus;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import javax.tools.*;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.*;
@@ -32,10 +32,11 @@ public class JavacServer {
private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("javac-server");
private final ChannelFactory myChannelFactory;
private final ChannelPipelineFactory myPipelineFactory;
private ExecutorService myThreadPool;
public JavacServer() {
final ExecutorService threadPool = Executors.newCachedThreadPool();
myChannelFactory = new NioServerSocketChannelFactory(threadPool, threadPool, 1);
myThreadPool = Executors.newCachedThreadPool();
myChannelFactory = new NioServerSocketChannelFactory(myThreadPool, myThreadPool, 1);
final ChannelRegistrar channelRegistrar = new ChannelRegistrar();
final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
myPipelineFactory = new ChannelPipelineFactory() {
@@ -103,7 +104,15 @@ public class JavacServer {
}
public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, final UUID sessionId, List<String> options, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, Map<File, Set<File>> outs) {
public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx,
final UUID sessionId,
List<String> options,
Collection<File> files,
Collection<File> classpath,
Collection<File> platformCp,
Collection<File> sourcePath,
Map<File, Set<File>> outs,
final CanceledStatus canceledStatus) {
final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() {
public void outputLineAvailable(String line) {
Channels.write(ctx.getChannel(), JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createStdOutputResponse(line)));
@@ -122,7 +131,7 @@ public class JavacServer {
};
try {
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, null/*todo*/);
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus);
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc));
}
catch (Throwable e) {
@@ -131,8 +140,14 @@ public class JavacServer {
}
}
public static void cancelBuild() {
// todo
private final Set<CancelHandler> myCancelHandlers = Collections.synchronizedSet(new HashSet<CancelHandler>());
public void cancelBuilds() {
synchronized (myCancelHandlers) {
for (CancelHandler handler : myCancelHandlers) {
handler.cancel();
}
}
}
private static List<File> toFiles(List<String> paths) {
@@ -145,7 +160,7 @@ public class JavacServer {
private class CompilationRequestsHandler extends SimpleChannelHandler {
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {
final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)e.getMessage();
final UUID sessionId = JavacProtoUtil.fromProtoUUID(msg.getSessionId());
final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
@@ -172,14 +187,26 @@ public class JavacServer {
outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
}
reply = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs);
final CancelHandler cancelHandler = new CancelHandler();
myCancelHandlers.add(cancelHandler);
myThreadPool.submit(new Runnable() {
public void run() {
try {
final JavacRemoteProto.Message exitMsg = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler);
Channels.write(ctx.getChannel(), exitMsg);
}
finally {
myCancelHandlers.remove(cancelHandler);
}
}
});
}
else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){
cancelBuild();
cancelBuilds();
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse());
}
else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){
cancelBuild();
cancelBuilds();
new Thread("StopThread") {
public void run() {
JavacServer.this.stop();
@@ -213,4 +240,19 @@ public class JavacServer {
super.channelOpen(ctx, e);
}
}
private static class CancelHandler implements CanceledStatus {
private volatile boolean myIsCanceled = false;
private CancelHandler() {
}
public void cancel() {
myIsCanceled = true;
}
public boolean isCanceled() {
return myIsCanceled;
}
}
}
@@ -72,7 +72,7 @@ public class GenericTest extends IncrementalTestCase {
public void testChangeToCovariantMethodInBase3() throws Exception {
doTest();
}
*/
public void testChangeVarargSignature() throws Exception {
doTest();
}
@@ -80,7 +80,6 @@ public class GenericTest extends IncrementalTestCase {
public void testChangeVarargSignature1() throws Exception {
doTest();
}
*/
public void testCovariance() throws Exception {
doTest();
@@ -114,7 +113,7 @@ public class GenericTest extends IncrementalTestCase {
doTest();
}
/* Not working yet
/* Not working yet */
public void testOverrideAnnotatedAnonymousNotRecompile() throws Exception {
doTest();
}
@@ -122,7 +121,6 @@ public class GenericTest extends IncrementalTestCase {
public void testOverrideAnnotatedInner() throws Exception {
doTest();
}
*/
public void testParamTypes() throws Exception {
doTest();
@@ -177,7 +177,7 @@ public abstract class IncrementalTestCase extends TestCase {
finally {
try {
closeAppender();
delete(new File(workDir));
//delete(new File(workDir));
}
finally {
Logger.setFactory(oldFactory);
@@ -116,11 +116,9 @@ public class MemberChangeTest extends IncrementalTestCase {
doTest();
}
/* Not working yet
public void testDeleteMethodImplementation4() throws Exception {
doTest();
}
*/
public void testDeleteMethodImplementation5() throws Exception {
doTest();
@@ -1103,47 +1103,55 @@ public class Mappings {
}
if ((m.access & Opcodes.ACC_ABSTRACT) == 0) {
final Collection<Pair<MethodRepr, ClassRepr>> overriding = u.findOverridingMethods(m, it, false);
for (final Pair<MethodRepr, ClassRepr> p : overriding) {
final DependencyContext.S fName = myClassToSourceFile.get(p.second.name);
affectedFiles.add(new File(myContext.getValue(fName)));
}
for (DependencyContext.S p : propagated) {
final ClassRepr s = u.reprByName(p);
if (!p.equals(it.name)) {
final ClassRepr s = u.reprByName(p);
if (s != null) {
final Collection<Pair<MethodRepr, ClassRepr>> overridenInS = u.findOverridenMethods(m, s);
if (s != null) {
final Collection<Pair<MethodRepr, ClassRepr>> overridenInS = u.findOverridenMethods(m, s);
overridenInS.addAll(overridenMethods);
overridenInS.addAll(overridenMethods);
boolean allAbstract = true;
boolean visited = false;
boolean allAbstract = true;
boolean visited = false;
for (Pair<MethodRepr, ClassRepr> pp : overridenInS) {
final ClassRepr cc = pp.second;
for (Pair<MethodRepr, ClassRepr> pp : overridenInS) {
final ClassRepr cc = pp.second;
if (cc == myMockClass) {
visited = true;
continue;
}
if (cc.name.equals(it.name)) {
continue;
}
if (cc == myMockClass) {
visited = true;
continue;
allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0);
if (!allAbstract) {
break;
}
}
if (cc.name.equals(it.name)) {
continue;
}
if (allAbstract && visited) {
final DependencyContext.S source = myClassToSourceFile.get(p);
visited = true;
allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0);
if (!allAbstract) {
break;
}
}
if (allAbstract && visited) {
final DependencyContext.S source = myClassToSourceFile.get(p);
if (source != null) {
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));
if (source != null) {
final String f = myContext.getValue(source);
debug("Removed method is not abstract & overrides some abstract method which is not then over-overriden in subclass ",
p);
debug("Affecting subclass source file ", f);
affectedFiles.add(new File(f));
}
}
}
}
@@ -1597,19 +1605,19 @@ public class Mappings {
for (DependencyContext.S f : delta.getChangedFiles()) {
mySourceFileToClasses.remove(f);
final Collection<ClassRepr> classes = delta.mySourceFileToClasses.get(f);
if (classes != null){
if (classes != null) {
mySourceFileToClasses.put(f, classes);
}
mySourceFileToUsages.remove(f);
final Collection<UsageRepr.Cluster> clusters = delta.mySourceFileToUsages.get(f);
if (clusters != null){
if (clusters != null) {
mySourceFileToUsages.put(f, clusters);
}
mySourceFileToAnnotationUsages.remove(f);
final Collection<UsageRepr.Usage> usages = delta.mySourceFileToAnnotationUsages.get(f);
if (usages != null){
if (usages != null) {
mySourceFileToAnnotationUsages.put(f, usages);
}
}
@@ -1637,7 +1645,7 @@ public class Mappings {
depClasses.retainAll(changedClasses);
if (! classChanged && depClasses.isEmpty()) {
if (!classChanged && depClasses.isEmpty()) {
continue;
}
}
@@ -93,17 +93,20 @@ public abstract class CachedValuesManager {
}
public static class MemoizationKey<T> extends Key<T> {
private final String myName;
public MemoizationKey(@NotNull @NonNls String name) {
super(name);
myName = name;
}
public int hashCode() {
return toString().hashCode();
return myName.hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof MemoizationKey && toString().equals(obj.toString());
return obj instanceof MemoizationKey && myName.equals(((MemoizationKey)obj).myName);
}
}
@@ -124,7 +124,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
protected synchronized Object createComponent(Class componentInterface) {
final Object component = getPicoContainer().getComponentInstance(componentInterface.getName());
assert component != null : "Can't instantiate component for: " + componentInterface;
LOG.assertTrue(component != null, "Can't instantiate component for: " + componentInterface);
return component;
}
@@ -78,7 +78,8 @@ public abstract class TemplateInsertHandler implements InsertHandler {
String lookupString = editor.getDocument().getCharsSequence().subSequence(startOffset, endOffset).toString();
lookupItem.setLookupString(lookupString);
final OffsetMap offsetMap = context.getOffsetMap();
final OffsetMap offsetMap = new OffsetMap(document);
offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, startOffset);
offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, endOffset);
offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, endOffset);
@@ -79,6 +79,10 @@ class ParameterInfoComponent extends JPanel{
myCurrentParameterIndex = -1;
}
public Object getHighlighted() {
return myHighlighted;
}
class MyParameterContext implements ParameterInfoUIContextEx {
private int i;
public void setupUIComponentPresentation(String text,
@@ -113,20 +113,33 @@ public class ParameterInfoController {
int selectedParameterIndex = myComponent.getCurrentParameterIndex();
List<Object> params = new ArrayList<Object>(objects.length);
final Object highlighted = myComponent.getHighlighted();
for(Object o:objects) {
final Object[] availableParams = myHandler.getParametersForDocumentation(o, context);
if (highlighted != null && !o.equals(highlighted)) continue;
collectParams(context, selectedParameterIndex, params, o);
}
if (availableParams != null &&
selectedParameterIndex < availableParams.length &&
selectedParameterIndex >= 0
) {
params.add(availableParams[selectedParameterIndex]);
//choose anything when highlighted is not applicable
if (highlighted != null && params.isEmpty()) {
for (Object o : objects) {
collectParams(context, selectedParameterIndex, params, o);
}
}
return ArrayUtil.toObjectArray(params);
}
private void collectParams(ParameterInfoContext context, int selectedParameterIndex, List<Object> params, Object o) {
final Object[] availableParams = myHandler.getParametersForDocumentation(o, context);
if (availableParams != null &&
selectedParameterIndex < availableParams.length &&
selectedParameterIndex >= 0
) {
params.add(availableParams[selectedParameterIndex]);
}
}
private static ArrayList<ParameterInfoController> getAllControllers(Editor editor) {
ArrayList<ParameterInfoController> array = editor.getUserData(ALL_CONTROLLERS_KEY);
if (array == null){
@@ -64,7 +64,7 @@ public abstract class InspectionTool extends InspectionProfileEntry {
}
public RefManager getRefManager() {
return myContext.getRefManager();
return getContext().getRefManager();
}
public abstract void runInspection(@NotNull AnalysisScope scope, @NotNull InspectionManager manager);
@@ -339,6 +339,11 @@ public class InspectionToolRegistrar {
getTool().runInspection(scope, manager);
}
@Override
public void initialize(@NotNull GlobalInspectionContextImpl context) {
getTool().initialize(context);
}
@NotNull
@Override
public JobDescriptor[] getJobDescriptors(GlobalInspectionContext globalInspectionContext) {
@@ -35,4 +35,8 @@ public interface CreateFromTemplateHandler {
Properties props) throws IncorrectOperationException;
boolean canCreate(final PsiDirectory[] dirs);
boolean isNameRequired();
String getErrorMessage();
Properties prepareProperties(Properties props);
}
@@ -16,6 +16,7 @@
package com.intellij.ide.fileTemplates;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDirectory;
@@ -67,4 +68,19 @@ public class DefaultCreateFromTemplateHandler implements CreateFromTemplateHandl
public boolean canCreate(final PsiDirectory[] dirs) {
return true;
}
@Override
public boolean isNameRequired() {
return true;
}
@Override
public String getErrorMessage() {
return IdeBundle.message("title.cannot.create.file");
}
@Override
public Properties prepareProperties(Properties props) {
return props;
}
}
@@ -118,7 +118,7 @@ public class FileTemplateUtil{
}
public static String[] calculateAttributes(String templateContent, Properties properties, boolean includeDummies) throws ParseException {
final Set<String> unsetAttributes = new HashSet<String>();
final Set<String> unsetAttributes = new LinkedHashSet<String>();
final Set<String> definedAttributes = new HashSet<String>();
//noinspection HardCodedStringLiteral
SimpleNode template = RuntimeSingleton.parse(new StringReader(templateContent), "MyTemplate");
@@ -258,7 +258,7 @@ public class FileTemplateUtil{
}
public static PsiElement createFromTemplate(@NotNull final FileTemplate template,
@NonNls @Nullable final String fileName,
@NonNls @Nullable String fileName,
@Nullable Properties props,
@NotNull final PsiDirectory directory,
@Nullable ClassLoader classLoader) throws Exception {
@@ -269,9 +269,16 @@ public class FileTemplateUtil{
FileTemplateManager.getInstance().addRecentName(template.getName());
fillDefaultProperties(props, directory);
final CreateFromTemplateHandler handler = findHandler(template);
if (fileName != null && props.getProperty(FileTemplate.ATTRIBUTE_NAME) == null) {
props.setProperty(FileTemplate.ATTRIBUTE_NAME, fileName);
}
else if (fileName == null && handler.isNameRequired()) {
fileName = props.getProperty(FileTemplate.ATTRIBUTE_NAME);
if (fileName == null) {
throw new Exception("File name must be specified");
}
}
//Set escaped references to dummy values to remove leading "\" (if not already explicitely set)
String[] dummyRefs = calculateAttributes(template.getText(), props, true);
@@ -279,15 +286,10 @@ public class FileTemplateUtil{
props.setProperty(dummyRef, "");
}
if (template.isTemplateOfType(StdFileTypes.JAVA)){
String packageName = props.getProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME);
if(packageName == null || packageName.length() == 0){
props = new Properties(props);
props.setProperty(FileTemplate.ATTRIBUTE_PACKAGE_NAME, FileTemplate.ATTRIBUTE_PACKAGE_NAME);
}
}
props = handler.prepareProperties(props);
final Properties props_ = props;
final String fileName_ = fileName;
String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(),
new ThrowableComputable<String, IOException>() {
@Override
@@ -304,8 +306,7 @@ public class FileTemplateUtil{
ApplicationManager.getApplication().runWriteAction(new Runnable(){
public void run(){
try{
CreateFromTemplateHandler handler = findHandler(template);
result [0] = handler.createFromTemplate(project, directory, fileName, template, templateText, finalProps);
result [0] = handler.createFromTemplate(project, directory, fileName_, template, templateText, finalProps);
}
catch (Exception ex){
commandException[0] = ex;
@@ -322,7 +323,7 @@ public class FileTemplateUtil{
return result[0];
}
private static CreateFromTemplateHandler findHandler(final FileTemplate template) {
public static CreateFromTemplateHandler findHandler(final FileTemplate template) {
for(CreateFromTemplateHandler handler: Extensions.getExtensions(CreateFromTemplateHandler.EP_NAME)) {
if (handler.handlesTemplate(template)) {
return handler;
@@ -32,6 +32,7 @@ public class AttributesDefaults {
private final String myDefaultName;
private final TextRange myDefaultRange;
private final Map<String, Pair<String, TextRange>> myNamesToValueAndRangeMap = new HashMap<String, Pair<String, TextRange>>();
private boolean myFixedName;
public AttributesDefaults(@NonNls @Nullable final String defaultName,
@Nullable final TextRange defaultRange) {
@@ -78,4 +79,13 @@ public class AttributesDefaults {
final Pair<String, TextRange> valueAndRange = myNamesToValueAndRangeMap.get(attributeKey);
return valueAndRange == null ? null : valueAndRange.first;
}
public boolean isFixedName() {
return myFixedName;
}
public AttributesDefaults withFixedName(boolean fixedName) {
myFixedName = fixedName;
return this;
}
}
@@ -55,14 +55,18 @@ public abstract class CreateFromTemplateActionBase extends AnAction {
}
else {
FileTemplateManager.getInstance().addRecentName(selectedTemplate.getName());
PsiElement createdElement = new CreateFromTemplateDialog(project, dir, selectedTemplate, getAttributesDefaults()).create();
final AttributesDefaults defaults = getAttributesDefaults(dataContext);
final CreateFromTemplateDialog dialog = new CreateFromTemplateDialog(project, dir, selectedTemplate, defaults);
PsiElement createdElement = dialog.create();
if (createdElement != null) {
elementCreated(dialog, createdElement);
view.selectElement(createdElement);
}
}
}
}
@Nullable
protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) {
return DirectoryChooserUtil.getOrChooseDirectory(view);
}
@@ -73,7 +77,10 @@ public abstract class CreateFromTemplateActionBase extends AnAction {
protected abstract FileTemplate getTemplate(final Project project, final PsiDirectory dir);
@Nullable
public AttributesDefaults getAttributesDefaults() {
public AttributesDefaults getAttributesDefaults(DataContext dataContext) {
return null;
}
protected void elementCreated(CreateFromTemplateDialog dialog, PsiElement createdElement) {
}
}
@@ -22,7 +22,6 @@ import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
import com.intellij.ide.fileTemplates.actions.AttributesDefaults;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
@@ -65,6 +64,11 @@ public class CreateFromTemplateDialog extends DialogWrapper {
myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties;
FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory);
boolean mustEnterName = FileTemplateUtil.findHandler(template).isNameRequired();
if (attributesDefaults != null && attributesDefaults.isFixedName()) {
myDefaultProperties.setProperty(FileTemplate.ATTRIBUTE_NAME, attributesDefaults.getDefaultFileName());
mustEnterName = false;
}
String[] unsetAttributes = null;
try {
@@ -75,7 +79,7 @@ public class CreateFromTemplateDialog extends DialogWrapper {
}
if (unsetAttributes != null) {
myAttrPanel = new CreateFromTemplatePanel(unsetAttributes, !myTemplate.isTemplateOfType(StdFileTypes.JAVA), attributesDefaults);
myAttrPanel = new CreateFromTemplatePanel(unsetAttributes, mustEnterName, attributesDefaults);
myAttrComponent = myAttrPanel.getComponent();
init();
}
@@ -110,7 +114,7 @@ public class CreateFromTemplateDialog extends DialogWrapper {
}
}
private void doCreate(final String fileName) {
private void doCreate(@Nullable final String fileName) {
try {
myCreatedElement = FileTemplateUtil.createFromTemplate(myTemplate, fileName, myAttrPanel.getProperties(myDefaultProperties),
myDirectory);
@@ -120,12 +124,16 @@ public class CreateFromTemplateDialog extends DialogWrapper {
}
}
public Properties getEnteredProperties() {
return myAttrPanel.getProperties(new Properties());
}
private void showErrorDialog(final Exception e) {
Messages.showMessageDialog(myProject, filterMessage(e.getMessage()), getErrorMessage(), Messages.getErrorIcon());
}
private String getErrorMessage() {
return myTemplate.isTemplateOfType(StdFileTypes.JAVA) ? IdeBundle.message("title.cannot.create.class") : IdeBundle.message("title.cannot.create.file");
return FileTemplateUtil.findHandler(myTemplate).getErrorMessage();
}
@Nullable
@@ -19,8 +19,7 @@ package com.intellij.ide.fileTemplates.ui;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.actions.AttributesDefaults;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.impl.DialogWrapperPeerImpl;
import com.intellij.openapi.ui.DialogWrapperPeer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.ui.ScrollPaneFactory;
@@ -37,8 +36,6 @@ import java.util.Properties;
*/
public class CreateFromTemplatePanel{
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.fileTemplates.ui.CreateFromTemplatePanel");
private JPanel myMainPanel;
private JPanel myAttrPanel;
private JTextField myFilenameField;
@@ -47,7 +44,7 @@ public class CreateFromTemplatePanel{
private int myLastRow = 0;
private int myHorisontalMargin = -1;
private int myHorizontalMargin = -1;
private int myVerticalMargin = -1;
private final boolean myMustEnterName;
private final AttributesDefaults myAttributesDefaults;
@@ -57,7 +54,6 @@ public class CreateFromTemplatePanel{
myMustEnterName = mustEnterName;
myUnsetAttributes = unsetAttributes;
myAttributesDefaults = attributesDefaults;
Arrays.sort(myUnsetAttributes);
}
public boolean hasSomethingToAsk() {
@@ -95,16 +91,16 @@ public class CreateFromTemplatePanel{
return myMainPanel;
}
public void ensureFitToScreen(int horisontalMargin, int verticalMargin){
myHorisontalMargin = horisontalMargin;
public void ensureFitToScreen(int horizontalMargin, int verticalMargin){
myHorizontalMargin = horizontalMargin;
myVerticalMargin = verticalMargin;
}
private Dimension getMainPanelPreferredSize(Dimension superPreferredSize){
if((myHorisontalMargin > 0) && (myVerticalMargin > 0)){
if((myHorizontalMargin > 0) && (myVerticalMargin > 0)){
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension preferredSize = superPreferredSize;
Dimension maxSize = new Dimension(screenSize.width - myHorisontalMargin, screenSize.height - myVerticalMargin);
Dimension maxSize = new Dimension(screenSize.width - myHorizontalMargin, screenSize.height - myVerticalMargin);
int width = Math.min(preferredSize.width, maxSize.width);
int height = Math.min(preferredSize.height, maxSize.height);
if(height < preferredSize.height){
@@ -119,8 +115,7 @@ public class CreateFromTemplatePanel{
}
private void updateShown() {
final Insets insets = new Insets(2, 2, 2, 2);
myAttrPanel.add(Box.createHorizontalStrut(200), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0));
final Insets insets = new Insets(2, 4, 4, 2);
if(myMustEnterName || Arrays.asList(myUnsetAttributes).contains(FileTemplate.ATTRIBUTE_NAME)){
final JLabel filenameLabel = new JLabel(IdeBundle.message("label.file.name"));
myAttrPanel.add(filenameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0));
@@ -134,7 +129,7 @@ public class CreateFromTemplatePanel{
// set predefined file name value
myFilenameField.setText(fileName);
final TextRange selectionRange;
// select range from default attrubutes or select file name without extension
// select range from default attributes or select file name without extension
if (myAttributesDefaults.getDefaultFileNameSelection() != null) {
selectionRange = myAttributesDefaults.getDefaultFileNameSelection();
} else {
@@ -151,15 +146,17 @@ public class CreateFromTemplatePanel{
}
}
}
myAttrPanel.add(myFilenameField, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0));
myAttrPanel.add(myFilenameField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, insets, 0, 0));
}
myLastRow = 2;
for (String attribute : myUnsetAttributes) {
if (attribute.equals(FileTemplate.ATTRIBUTE_NAME)) { // already asked above
continue;
}
final JLabel label = new JLabel(attribute.replace('_', ' ') + ":");
final JTextField field = new JTextField();
field.setColumns(30);
if (myAttributesDefaults != null) {
final String defaultValue = myAttributesDefaults.getDefaultValueFor(attribute);
final TextRange selectionRange = myAttributesDefaults.getRangeFor(attribute);
@@ -172,9 +169,9 @@ public class CreateFromTemplatePanel{
}
}
myAttributes.add(new Pair<String, JTextField>(attribute, field));
myAttrPanel.add(label, new GridBagConstraints(0, myLastRow * 2 + 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
myAttrPanel.add(label, new GridBagConstraints(0, myLastRow, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
insets, 0, 0));
myAttrPanel.add(field, new GridBagConstraints(0, myLastRow * 2 + 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST,
myAttrPanel.add(field, new GridBagConstraints(1, myLastRow, 1, 1, 1.0, 0.0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, insets, 0, 0));
myLastRow++;
}
@@ -194,17 +191,17 @@ public class CreateFromTemplatePanel{
}
}
public Properties getProperties(Properties predefinedProperties){
public Properties getProperties(Properties predefinedProperties) {
Properties result = (Properties) predefinedProperties.clone();
for (Pair<String, JTextField> pair : myAttributes) {
result.put(pair.first, pair.second.getText());
result.setProperty(pair.first, pair.second.getText());
}
return result;
}
private void setPredefinedSelectionFor(final JTextField field, final TextRange selectionRange) {
private static void setPredefinedSelectionFor(final JTextField field, final TextRange selectionRange) {
field.select(selectionRange.getStartOffset(), selectionRange.getEndOffset());
field.putClientProperty(DialogWrapperPeerImpl.HAVE_INITIAL_SELECTION, true);
field.putClientProperty(DialogWrapperPeer.HAVE_INITIAL_SELECTION, true);
}
}
@@ -87,7 +87,7 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl
myUpdateQueue = new MergingUpdateQueue("StructureView", Registry.intValue("structureView.coalesceTime"), false, myToolWindow.getComponent(), this, myToolWindow.getComponent(), true);
myUpdateQueue.setRestartTimerOnAdd(true);
ActionManager.getInstance().addTimerListener(500, new TimerListener() {
final TimerListener timerListener = new TimerListener() {
public ModalityState getModalityState() {
return ModalityState.stateForComponent(myToolWindow.getComponent());
}
@@ -95,6 +95,13 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl
public void run() {
checkUpdate();
}
};
ActionManager.getInstance().addTimerListener(500, timerListener);
Disposer.register(this, new Disposable() {
@Override
public void dispose() {
ActionManager.getInstance().removeTimerListener(timerListener);
}
});
myToolWindow.getComponent().addHierarchyListener(new HierarchyListener() {
@@ -818,11 +818,16 @@ public class FileStructurePopup implements Disposable {
final Object object = ((DefaultMutableTreeNode)last).getUserObject();
if (object instanceof FilteringTreeStructure.FilteringNode) {
FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)object;
FilteringTreeStructure.FilteringNode candidate = node;
while (node != null) {
elements.add(getPsi(node));
node = node.getParentNode();
}
final int size = ContainerUtil.intersection(parents, elements).size();
if (size == elements.size() - 1 && size == parents.size() && candidate.children().isEmpty()) {
return p.node;
}
if (size > max) {
max = size;
cur.clear();
@@ -28,6 +28,8 @@ import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashMap;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -100,13 +102,13 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
public ModuleFileData(final String rootElementName, Module module) {
super(rootElementName);
myModule = module;
myOptions = new TreeMap<String, String>();
myOptions = new THashMap<String, String>(2);
}
protected ModuleFileData(final ModuleFileData storageData) {
super(storageData);
myOptions = new TreeMap<String, String>(storageData.myOptions);
myOptions = new THashMap<String, String>(storageData.myOptions);
myModule = storageData.myModule;
}
@@ -130,7 +132,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
final Element root = super.save();
myOptions.put(VERSION_OPTION, Integer.toString(myVersion));
Set<String> options = myOptions.keySet();
String[] options = ArrayUtil.toStringArray(myOptions.keySet());
Arrays.sort(options);
for (String option : options) {
root.setAttribute(option, myOptions.get(option));
}
@@ -133,14 +133,14 @@ public class CodeStyleSchemeImpl implements JDOMExternalizable, CodeStyleScheme,
public static CodeStyleSchemeImpl readScheme(Document document) throws InvalidDataException, JDOMException, IOException{
Element root = document.getRootElement();
if (root == null){
throw new InvalidDataException();
throw new InvalidDataException("No root element in code style scheme file");
}
String schemeName = root.getAttributeValue(NAME);
String parentName = root.getAttributeValue(PARENT);
if (schemeName == null){
throw new InvalidDataException();
if (schemeName == null) {
throw new InvalidDataException("Name attribute missing in code style scheme file");
}
return new CodeStyleSchemeImpl(schemeName, parentName, root);
@@ -148,6 +148,11 @@ public abstract class InplaceVariableIntroducer<E extends PsiElement> extends In
protected void collectAdditionalElementsToRename(List<Pair<PsiElement, TextRange>> stringUsages) {
}
@Override
protected int restoreCaretOffset(int offset) {
return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset;
}
@Override
protected String getCommandName() {
return myTitle;
@@ -104,7 +104,7 @@ public abstract class InplaceRefactoring {
protected StartMarkAction myMarkAction;
protected PsiElement myScope;
private RangeMarker myCaretRangeMarker;
protected RangeMarker myCaretRangeMarker;
public InplaceRefactoring(Editor editor, PsiNamedElement elementToRename, Project project) {
this(editor, elementToRename, project, elementToRename != null ? elementToRename.getName() : null,
@@ -245,6 +245,10 @@ public abstract class InplaceRefactoring {
}
else {
revertState();
final TemplateState templateState = TemplateManagerImpl.getTemplateState(InjectedLanguageUtil.getTopLevelEditor(myEditor));
if (templateState != null) {
templateState.gotoEnd(true);
}
}
return false;
}
@@ -350,7 +354,7 @@ public abstract class InplaceRefactoring {
}
protected int restoreCaretOffset(int offset) {
return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset;
return offset;
}
protected void navigateToAlreadyStarted(Document oldDocument, int exitCode) {
@@ -44,6 +44,7 @@ import com.intellij.openapi.project.*;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.ex.VirtualFileManagerEx;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
@@ -280,6 +281,7 @@ public class FileBasedIndex implements ApplicationComponent {
versionChanged |= registerIndexer(extension, currentVersionCorrupted);
}
FileUtil.delete(corruptionMarker);
String rebuildNotification = null;
if (currentVersionCorrupted) {
rebuildNotification = "Index files on disk are corrupted. Indices will be rebuilt.";
@@ -287,10 +289,13 @@ public class FileBasedIndex implements ApplicationComponent {
else if (versionChanged) {
rebuildNotification = "Index file format has changed for some indices. These indices will be rebuilt.";
}
if (rebuildNotification != null && !ApplicationManager.getApplication().isHeadlessEnvironment()) {
if (rebuildNotification != null
&& !ApplicationManager.getApplication().isHeadlessEnvironment()
&& Registry.is("ide.showIndexRebuildMessage")) {
new NotificationGroup("Indexing", NotificationDisplayType.BALLOON, false)
.createNotification("Index Rebuild", rebuildNotification, NotificationType.INFORMATION, null).notify(null);
}
dropUnregisteredIndices();
// check if rebuild was requested for any index during registration
@@ -15,6 +15,7 @@
*/
package com.intellij.internal.statistic.connect;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.updateSettings.impl.UpdateChecker;
import com.intellij.openapi.util.text.StringUtil;
@@ -39,7 +40,7 @@ public class StatisticsHttpClientSender implements StatisticsDataSender {
post.setRequestBody(new NameValuePair[]{
new NameValuePair("content", content),
new NameValuePair("uuid", UpdateChecker.getInstallationUID()),
new NameValuePair("uuid", UpdateChecker.getInstallationUID(PropertiesComponent.getInstance())),
new NameValuePair("ide", ApplicationNamesInfo.getInstance().getProductName()),
});
@@ -165,7 +165,7 @@ public class EventLog implements Notifications {
content = title + (StringUtil.isNotEmpty(content) ? ": " + content : "");
}
content = StringUtil.replace(StringUtil.convertLineSeparators(content), "&nbsp;", " ");
content = StringUtil.convertLineSeparators(content);
boolean hasHtml = false;
while (true) {
Matcher tagMatcher = TAG_PATTERN.matcher(content);
@@ -248,6 +248,9 @@ public class EventLog implements Notifications {
}
private static void appendText(Document document, String text) {
text = StringUtil.replace(text, "&nbsp;", " ");
text = StringUtil.replace(text, "&raquo;", ">>");
text = StringUtil.replace(text, "&laquo;", "<<");
document.insertString(document.getTextLength(), StringUtil.unescapeXml(text));
}
@@ -154,7 +154,7 @@ public class NotificationsManagerImpl extends NotificationsManager implements No
case BALLOON:
default:
Balloon balloon = notifyByBalloon(notification, type, project);
if (!settings.isShouldLog()) {
if (!settings.isShouldLog() || type == NotificationDisplayType.STICKY_BALLOON) {
if (balloon == null) {
notification.expire();
} else {
@@ -32,6 +32,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.ReflectionCache;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +45,7 @@ import java.util.*;
abstract class ComponentStoreImpl implements IComponentStore {
private static final Logger LOG = Logger.getInstance("#com.intellij.components.ComponentStoreImpl");
private final Map<String, Object> myComponents = Collections.synchronizedMap(new TreeMap<String, Object>());
private final Map<String, Object> myComponents = Collections.synchronizedMap(new THashMap<String, Object>());
private final List<SettingsSavingComponent> mySettingsSavingComponents = Collections.synchronizedList(new ArrayList<SettingsSavingComponent>());
@Nullable private SaveSessionImpl mySession;
@@ -470,7 +471,8 @@ abstract class ComponentStoreImpl implements IComponentStore {
final StateStorageManager.ExternalizationSession session = storageManager.startExternalization();
final String[] names = ArrayUtil.toStringArray(myComponents.keySet());
String[] names = ArrayUtil.toStringArray(myComponents.keySet());
Arrays.sort(names);
for (String name : names) {
Object component = myComponents.get(name);
@@ -16,16 +16,16 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.StateStorage;
import gnu.trove.THashMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author mike
*/
public class CompoundExternalizationSession {
private final Map<StateStorage, StateStorage.ExternalizationSession> mySessions = new HashMap<StateStorage, StateStorage.ExternalizationSession>();
private final Map<StateStorage, StateStorage.ExternalizationSession> mySessions = new THashMap<StateStorage, StateStorage.ExternalizationSession>(1);
public StateStorage.ExternalizationSession getExternalizationSession(StateStorage stateStore) {
StateStorage.ExternalizationSession session = mySessions.get(stateStore);
@@ -31,6 +31,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
@@ -58,8 +59,8 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
private final Map<String, String> myMacros = new HashMap<String, String>();
private final Map<String, StateStorage> myStorages = new HashMap<String, StateStorage>();
private final Map<String, StateStorage> myPathToStorage = new HashMap<String, StateStorage>();
private final Map<String, StateStorage> myStorages = new THashMap<String, StateStorage>();
private final Map<String, StateStorage> myPathToStorage = new THashMap<String, StateStorage>();
private final TrackingPathMacroSubstitutor myPathMacroSubstitutor;
private final String myRootTagName;
private Object mySession;
@@ -160,7 +161,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
private Map<String, Long> loadVersions() {
TreeMap<String, Long> result = new TreeMap<String, Long>();
THashMap<String, Long> result = new THashMap<String, Long>();
String filePath = getNotNullVersionsFilePath();
if (filePath != null) {
try {
@@ -580,8 +581,10 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
public static Element createComponentVersionsXml(Map<String, Long> versions) {
Element vers = new Element("versions");
String[] componentNames = ArrayUtil.toStringArray(versions.keySet());
Arrays.sort(componentNames);
for (String name : versions.keySet()) {
for (String name : componentNames) {
long version = versions.get(name);
if (version != 0) {
Element element = new Element("component");
@@ -26,8 +26,10 @@ import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.StringInterner;
import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
@@ -62,7 +64,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
protected Integer myProviderUpToDateHash;
private boolean mySavingDisabled = false;
private final Map<String, Element> myStorageComponentStates = new TreeMap<String, Element>();
private final Map<String, Object> myStorageComponentStates = new THashMap<String, Object>(); // at loading we store Element, on setState Integer of hash// at loading we store Element, on setState Integer of hash
private final ComponentVersionProvider myLocalVersionProvider;
private final ComponentVersionProvider myRemoteVersionProvider;
@@ -126,8 +128,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
final StorageData storageData = getStorageData(false);
final Element state = storageData.getState(componentName);
if (state != null) {
if (!myStorageComponentStates.containsKey(componentName)) {
myStorageComponentStates.put(componentName, state);
@@ -309,19 +309,20 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
if (element.getAttributes().isEmpty() && element.getChildren().isEmpty()) return;
myStorageData.setState(componentName, element);
int hash = JDOMUtil.getTreeHash(element);
Element oldElement = myStorageComponentStates.get(componentName);
try {
if (oldElement != null && !JDOMUtil.areElementsEqual(oldElement, element)) {
Object oldElementState = myStorageComponentStates.get(componentName);
if (oldElementState instanceof Element && !JDOMUtil.areElementsEqual((Element)oldElementState, element) ||
oldElementState instanceof Integer && hash != (Integer)oldElementState
) {
myListener.componentStateChanged(componentName);
}
}
finally {
myStorageComponentStates.put(componentName, (Element)element.clone());
myStorageComponentStates.put(componentName, hash);
}
}
}
@@ -396,10 +397,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
protected abstract void doSave() throws StateStorageException;
public void clearHash() {
myUpToDateHash = null;
}
protected Integer calcHash() {
return null;
}
@@ -469,10 +466,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return myUpToDateHash != null && myUpToDateHash.equals(hash);
}
public boolean isHashUpToDate() {
return isHashUpToDate(calcHash());
}
protected Document getDocumentToSave() {
if (myDocumentToSave != null) return myDocumentToSave;
@@ -520,8 +513,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
private Map<String, Long> loadVersions(Document copy) {
HashMap<String, Long> result = new HashMap<String, Long>();
THashMap<String, Long> result = new THashMap<String, Long>();
List list = copy.getRootElement().getChildren(COMPONENT);
for (Object o : list) {
@@ -550,13 +542,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
private Integer myHash;
public StorageData(final String rootElementName) {
myComponentStates = new TreeMap<String, Element>();
myComponentStates = new THashMap<String, Element>();
myRootElementName = rootElementName;
}
protected StorageData(StorageData storageData) {
myRootElementName = storageData.myRootElementName;
myComponentStates = new TreeMap<String, Element>(storageData.myComponentStates);
myComponentStates = new THashMap<String, Element>(storageData.myComponentStates);
}
protected void load(@NotNull Element rootElement) throws IOException {
@@ -603,8 +595,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@NotNull
protected Element save() {
Element rootElement = new Element(myRootElementName);
for (String componentName : myComponentStates.keySet()) {
String[] componentNames = ArrayUtil.toStringArray(myComponentStates.keySet());
Arrays.sort(componentNames);
for (String componentName : componentNames) {
assert componentName != null;
final Element element = myComponentStates.get(componentName);
@@ -617,7 +610,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@Nullable
public Element getState(final String name) {
private Element getState(final String name) {
final Element e = myComponentStates.get(name);
if (e != null) {
@@ -628,7 +621,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return e;
}
public void removeState(final String componentName) {
private void removeState(final String componentName) {
myComponentStates.remove(componentName);
clearHash();
}
@@ -799,7 +792,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
private void loadProviderVersions() {
myProviderVersions = new TreeMap<String, Long>();
myProviderVersions = new THashMap<String, Long>();
for (RoamingType type : RoamingType.values()) {
Document doc = null;
if (myStreamProvider.isEnabled()) {
@@ -16,6 +16,7 @@
package com.intellij.openapi.updateSettings.impl;
import com.intellij.ide.plugins.PluginHostsConfigurable;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
@@ -46,7 +47,9 @@ public class CheckForUpdateAction extends AnAction implements DumbAware {
ProgressManager.getInstance().run(new Task.Modal(project, "Checking for updates", false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
final CheckForUpdateResult result = UpdateChecker.checkForUpdates(true);
final CheckForUpdateResult result = UpdateChecker.checkForUpdates(UpdateSettings.getInstance(), PropertiesComponent.getInstance(),
true
);
final List<PluginDownloader> updatedPlugins = UpdateChecker.updatePlugins(true, hostsConfigurable);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@@ -148,11 +148,12 @@ public final class UpdateChecker {
public static ActionCallback updateAndShowResult() {
final ActionCallback result = new ActionCallback();
final Application app = ApplicationManager.getApplication();
/*
final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance();
final UpdateSettings updateSettings = UpdateSettings.getInstance();
app.executeOnPooledThread(new Runnable() {
@Override
public void run() {
final CheckForUpdateResult checkForUpdateResult = checkForUpdates();
final CheckForUpdateResult checkForUpdateResult = checkForUpdates(updateSettings, propertiesComponent, false);
final List<PluginDownloader> updatedPlugins = updatePlugins(false, null);
app.invokeLater(new Runnable() {
@@ -164,7 +165,6 @@ public final class UpdateChecker {
});
}
});
*/
return result;
}
@@ -346,11 +346,11 @@ public final class UpdateChecker {
}
@NotNull
public static CheckForUpdateResult doCheckForUpdates(final UpdateSettings settings) {
public static CheckForUpdateResult doCheckForUpdates(final UpdateSettings settings, final PropertiesComponent instance) {
ApplicationInfo appInfo = ApplicationInfo.getInstance();
BuildNumber currentBuild = appInfo.getBuild();
int majorVersion = Integer.parseInt(appInfo.getMajorVersion());
final UpdatesXmlLoader loader = new UpdatesXmlLoader(getUpdateUrl(), getInstallationUID(), null);
final UpdatesXmlLoader loader = new UpdatesXmlLoader(getUpdateUrl(), getInstallationUID(instance), null);
final UpdatesInfo info;
try {
info = loader.loadUpdatesInfo();
@@ -366,25 +366,21 @@ public final class UpdateChecker {
return strategy.checkForUpdates();
}
@NotNull
public static CheckForUpdateResult checkForUpdates() {
return checkForUpdates(false);
}
@NotNull
public static CheckForUpdateResult checkForUpdates(final boolean disregardIgnoredBuilds) {
public static CheckForUpdateResult checkForUpdates(final UpdateSettings updateSettings,
final PropertiesComponent propertiesComponent,
final boolean disregardIgnoredBuilds) {
if (LOG.isDebugEnabled()) {
LOG.debug("enter: auto checkForUpdates()");
}
UserUpdateSettings settings = UpdateSettings.getInstance();
UserUpdateSettings settings = updateSettings;
if (disregardIgnoredBuilds) {
settings = new UserUpdateSettings() {
@NotNull
@Override
public List<String> getKnownChannelsIds() {
return UpdateSettings.getInstance().getKnownChannelsIds();
return updateSettings.getKnownChannelsIds();
}
@Override
@@ -394,21 +390,21 @@ public final class UpdateChecker {
@Override
public void setKnownChannelIds(List<String> ids) {
UpdateSettings.getInstance().setKnownChannelIds(ids);
updateSettings.setKnownChannelIds(ids);
}
@NotNull
@Override
public ChannelStatus getSelectedChannelStatus() {
return UpdateSettings.getInstance().getSelectedChannelStatus();
return updateSettings.getSelectedChannelStatus();
}
};
}
final CheckForUpdateResult result = doCheckForUpdates(UpdateSettings.getInstance());
final CheckForUpdateResult result = doCheckForUpdates(updateSettings, propertiesComponent);
if (result.getState() == UpdateStrategy.State.LOADED) {
UpdateSettings.getInstance().LAST_TIME_CHECKED = System.currentTimeMillis();
updateSettings.LAST_TIME_CHECKED = System.currentTimeMillis();
settings.setKnownChannelIds(result.getAllChannelsIds());
}
@@ -444,12 +440,13 @@ public final class UpdateChecker {
}
final InputStream[] inputStreams = new InputStream[]{null};
final Exception[] exception = new Exception[]{null};
final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance();
Future<?> downloadThreadFuture = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
try {
HttpConfigurable.getInstance().prepareURL(url);
String uid = getInstallationUID();
String uid = getInstallationUID(propertiesComponent);
final URL requestUrl =
new URL(url + "?build=" + ApplicationInfo.getInstance().getBuild().asString() + "&uid=" + uid + ADDITIONAL_REQUEST_OPTIONS);
@@ -477,8 +474,7 @@ public final class UpdateChecker {
return inputStreams[0];
}
public static String getInstallationUID() {
final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance();
public static String getInstallationUID(final PropertiesComponent propertiesComponent) {
String uid = "";
if (!propertiesComponent.isValueSet(INSTALLATION_UID)) {
try {
@@ -200,7 +200,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
}
public void fileClosed(FileEditorManager source, VirtualFile file) {
getFocusManagerImpl().doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) {
getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) {
public void run() {
if (!hasOpenEditorFiles()) {
focusToolWinowByDefault(null);
@@ -351,8 +351,8 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
return myFileEditorManager.getOpenFiles().length > 0;
}
private static FocusManagerImpl getFocusManagerImpl() {
return FocusManagerImpl.getInstance();
private static IdeFocusManager getFocusManagerImpl(Project project) {
return IdeFocusManager.getInstance(project);
}
public Project getProject() {
@@ -619,7 +619,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
}).doWhenRejected(new Runnable() {
public void run() {
if (forced) {
getFocusManagerImpl().requestFocus(new FocusCommand() {
getFocusManagerImpl(myProject).requestFocus(new FocusCommand() {
public ActionCallback run() {
final ArrayList<FinalizableCommand> cmds = new ArrayList<FinalizableCommand>();
@@ -719,7 +719,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
final ArrayList<FinalizableCommand> commandList,
boolean forced,
boolean autoFocusContents) {
if (!getFocusManagerImpl().isUnforcedRequestAllowed() && !forced) return;
if (!FocusManagerImpl.getInstance().isUnforcedRequestAllowed() && !forced) return;
if (LOG.isDebugEnabled()) {
LOG.debug("enter: activateToolWindowImpl(" + id + ")");
@@ -2002,15 +2002,15 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
return;
}
final WindowInfoImpl info = getInfo(myId);
getFocusManagerImpl().myFocusedComponentAlaram.cancelAllRequests();
//getFocusManagerImpl(myProject)..cancelAllRequests();
if (!info.isActive()) {
getFocusManagerImpl().myFocusedComponentAlaram.addRequest(new EdtRunnable() {
getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new EdtRunnable() {
public void runEdt() {
if (!myLayout.isToolWindowRegistered(myId)) return;
activateToolWindow(myId, false, false);
}
}, 100);
});
}
}
}
@@ -2128,7 +2128,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
}
public ActionCallback requestDefaultFocus(final boolean forced) {
return getFocusManagerImpl().requestFocus(new FocusCommand() {
return getFocusManagerImpl(myProject).requestFocus(new FocusCommand() {
public ActionCallback run() {
return processDefaultFocusRequest(forced);
}
@@ -246,7 +246,7 @@ message.nothing.to.show.in.structure.view=Nothing to show in the Structure View
error.license.collision=This license is being used elsewhere on the network by {0}.\nOnly one active computer at a time can use the license.\nWould you like to re-activate this computer?\nClick Yes to re-activate, or No to shutdown {1}.
title.license.collision.detected=License Collision Detected
message.licensed.to=Licensed to {0}
title.enter.license.data=Enter License Data
title.enter.license.data=Enter {0} License
message.purchase.or.upgrade=For information on how to upgrade your evaluation software please go to {0}
message.expiration.date=Expiration date: {0}
message.educational.license=1-Year Educational License. {0}
@@ -99,6 +99,8 @@ editor.mouseSelectionStateResetDeadzone=4
editor.use.new.tabs=true
editor.smarterSelectionQuoting=true
ide.showIndexRebuildMessage=false
ide.tabbedPane.bufferedPaint=true
ide.tabbedPane.dragOutMultiplier=1.2
@@ -108,6 +110,7 @@ ide.mac.message.dialogs.as.sheets=true
ide.mac.inplaceDialogMnemonicsFix=true
ide.mac.hide.cursor.when.typing=false
ide.mac.show.native.help=false
ide.mac.useNativeClipboard=false
debugger.valueTooltipAutoShow=true
debugger.valueTooltipAutoShow.description=Auto show tooltip on mouse over
@@ -171,8 +174,6 @@ projectView.hide.dot.idea=true
show.live.templates.in.completion=false
documentation.component.editor.font=false
ide.mac.useNativeClipboard=false
show.all.classes.on.first.completion=false
ide.enable.toolwindow.stack=false
@@ -29,9 +29,9 @@ class EventLogTest extends LightPlatformTestCase {
PlatformTestCase.initPlatformLangPrefix()
}
public void testNbsp() {
def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello&nbsp;world", NotificationType.ERROR))
assert entry.message == 'Title: Hello world'
public void testHtmlEntities() {
def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello&nbsp;world&laquo;&raquo;", NotificationType.ERROR))
assert entry.message == 'Title: Hello world<<>>'
}
public void testParseMultilineText() {
@@ -68,6 +68,11 @@ class UsageViewTreeCellRenderer extends ColoredTreeCellRenderer {
if (userObject instanceof UsageTarget) {
UsageTarget usageTarget = (UsageTarget)userObject;
if (!usageTarget.isValid()) {
append(UsageViewBundle.message("node.invalid"), ourInvalidAttributes);
return;
}
final ItemPresentation presentation = usageTarget.getPresentation();
LOG.assertTrue(presentation != null);
if (showAsReadOnly) {
@@ -36,6 +36,7 @@ import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import java.io.*;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
@@ -47,17 +48,7 @@ import java.util.List;
*/
@SuppressWarnings({"HardCodedStringLiteral"})
public class JDOMUtil {
private static final ThreadLocal<SAXBuilder> ourSaxBuilder = new ThreadLocal<SAXBuilder>(){
protected SAXBuilder initialValue() {
SAXBuilder saxBuilder = new SAXBuilder();
saxBuilder.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new CharArrayReader(ArrayUtil.EMPTY_CHAR_ARRAY));
}
});
return saxBuilder;
}
};
private static final ThreadLocal<SoftReference<SAXBuilder>> ourSaxBuilder = new ThreadLocal<SoftReference<SAXBuilder>>();
private JDOMUtil() { }
@@ -317,14 +308,27 @@ public class JDOMUtil {
@NotNull
public static Document loadDocument(char[] chars, int length) throws IOException, JDOMException {
SAXBuilder builder = ourSaxBuilder.get();
return builder.build(new CharArrayReader(chars, 0, length));
return getSaxBuilder().build(new CharArrayReader(chars, 0, length));
}
private static SAXBuilder getSaxBuilder() {
SoftReference<SAXBuilder> reference = ourSaxBuilder.get();
SAXBuilder saxBuilder = reference != null ? reference.get() : null;
if (saxBuilder == null) {
saxBuilder = new SAXBuilder();
saxBuilder.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new CharArrayReader(ArrayUtil.EMPTY_CHAR_ARRAY));
}
});
ourSaxBuilder.set(new SoftReference<SAXBuilder>(saxBuilder));
}
return saxBuilder;
}
@NotNull
public static Document loadDocument(CharSequence seq) throws IOException, JDOMException {
SAXBuilder builder = ourSaxBuilder.get();
return builder.build(new CharSequenceReader(seq));
return getSaxBuilder().build(new CharSequenceReader(seq));
}
@NotNull
@@ -351,10 +355,9 @@ public class JDOMUtil {
@NotNull
public static Document loadDocument(@NotNull InputStream stream) throws JDOMException, IOException {
SAXBuilder saxBuilder = ourSaxBuilder.get();
InputStreamReader reader = new InputStreamReader(stream, ENCODING);
try {
return saxBuilder.build(reader);
return getSaxBuilder().build(reader);
}
finally {
reader.close();
@@ -151,5 +151,43 @@ public class StringHash {
return h;
}
public static int murmur(String data, int seed) {
final int length = data.length();
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
final int m = 0x5bd1e995;
final int r = 24;
// Initialize the hash to a random value
int h = seed ^ length;
int length4 = length >> 2;
for (int i = 0; i < length4; i++) {
final int i4 = i << 2;
int k = data.charAt(i4) + (data.charAt(i4 + 1) << 8) +
(data.charAt(i4 + 2) << 16) + (data.charAt(i4 + 3) << 24);
k *= m;
k ^= k >>> r;
k *= m;
h *= m;
h ^= k;
}
// Handle the last few bytes of the input array
switch (length % 4) {
case 3:
h ^= data.charAt((length & ~3) + 2) << 16;
case 2:
h ^= data.charAt((length & ~3) + 1) << 8;
case 1:
h ^= data.charAt(length & ~3);
h *= m;
}
h ^= h >>> 13;
h *= m;
h ^= h >>> 15;
return h;
}
}
@@ -19,6 +19,7 @@
*/
package com.intellij.util.lang;
import com.intellij.openapi.util.text.StringHash;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.HashMap;
@@ -273,7 +274,7 @@ public class ClasspathCache {
}
private boolean maybeContains(String name, Loader loader) {
int hash = hashFromNameAndLoader(name, loader, murmur(name, SEED));
int hash = hashFromNameAndLoader(name, loader, StringHash.murmur(name, SEED));
int hash2 = hashFromNameAndLoader(name, loader, hash);
for (int i = 0; i < myHashFunctionCount; ++i) {
@@ -283,7 +284,7 @@ public class ClasspathCache {
}
public void add(String name, Loader loader) {
int hash1 = hashFromNameAndLoader(name, loader, murmur(name, SEED));
int hash1 = hashFromNameAndLoader(name, loader, StringHash.murmur(name, SEED));
int hash2 = hashFromNameAndLoader(name, loader, hash1);
for (int i = 0; i < myHashFunctionCount; ++i) {
@@ -292,7 +293,7 @@ public class ClasspathCache {
}
private int hashFromNameAndLoader(String name, Loader loader, int n) {
int hash = murmur(name, n);
int hash = StringHash.murmur(name, n);
int i = loader.getIndex();
while (i > 0) {
hash = hash * n + ((i % 10) + '0');
@@ -300,45 +301,6 @@ public class ClasspathCache {
}
return hash;
}
private static int murmur(String data, int seed) {
final int length = data.length();
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
final int m = 0x5bd1e995;
final int r = 24;
// Initialize the hash to a random value
int h = seed ^ length;
int length4 = length >> 2;
for (int i = 0; i < length4; i++) {
final int i4 = i << 2;
int k = data.charAt(i4) + (data.charAt(i4 + 1) << 8) +
(data.charAt(i4 + 2) << 16) + (data.charAt(i4 + 3) << 24);
k *= m;
k ^= k >>> r;
k *= m;
h *= m;
h ^= k;
}
// Handle the last few bytes of the input array
switch (length % 4) {
case 3:
h ^= data.charAt((length & ~3) + 2) << 16;
case 2:
h ^= data.charAt((length & ~3) + 1) << 8;
case 1:
h ^= data.charAt(length & ~3);
h *= m;
}
h ^= h >>> 13;
h *= m;
h ^= h >>> 15;
return h;
}
}
static class DebugInfo {
@@ -564,7 +564,7 @@ public class PathsVerifier<BinaryType extends FilePatch> {
public Collection<FilePatch> doDelayed() {
final List<FilePatch> result = new LinkedList<FilePatch>();
if (! myOverrideExisting.isEmpty()) {
final String title = "Overwrite existing files";
final String title = "Overwrite Existing Files";
final Collection<FilePath> selected = AbstractVcsHelper.getInstance(myProject).selectFilePathsToProcess(
new ArrayList<FilePath>(myOverrideExisting.keySet()), title,
"\nThe following files should be created by patch, but they already exist.\nDo you want to overwrite them?\n", title,
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
@@ -32,6 +33,7 @@ import com.intellij.util.Consumer;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.reflect.Reflection;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,6 +42,8 @@ import java.util.Collection;
* @author max
*/
public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements ProjectComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.VcsDirtyScopeManagerImpl");
private final Project myProject;
private final ChangeListManager myChangeListManager;
private final ProjectLevelVcsManager myVcsManager;
@@ -100,6 +104,10 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
public void markEverythingDirty() {
if ((! myProject.isOpen()) || myProject.isDisposed() || myVcsManager.getAllActiveVcss().length == 0) return;
if (LOG.isDebugEnabled()) {
LOG.debug("everything dirty: " + Reflection.getCallerClass(1));
}
final LifeDrop lifeDrop = myLife.doIfAlive(new Runnable() {
public void run() {
myDirtBuilder.everythingDirty();
@@ -160,6 +168,10 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
|| dirsConverted != null && ! dirsConverted.isEmpty();
if (! haveStuff) return;
if (LOG.isDebugEnabled()) {
LOG.debug("paths dirty: " + filesConverted + "; " + dirsConverted + "; " + Reflection.getCallerClass(2));
}
takeDirt(new Consumer<DirtBuilder>() {
public void consume(final DirtBuilder dirt) {
if (filesConverted != null) {
@@ -218,6 +230,10 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
final boolean haveStuff = filesConverted != null && ! filesConverted.isEmpty() || dirsConverted != null && ! dirsConverted.isEmpty();
if (! haveStuff) return;
if (LOG.isDebugEnabled()) {
LOG.debug("files dirty: " + filesConverted + "; " + dirsConverted + "; " + Reflection.getCallerClass(2));
}
takeDirt(new Consumer<DirtBuilder>() {
public void consume(final DirtBuilder dirt) {
if (filesConverted != null) {
@@ -240,6 +256,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
try {
final AbstractVcs vcs = myGuess.getVcsForDirty(file);
if (vcs == null) return;
if (LOG.isDebugEnabled()) {
LOG.debug("file dirty: " + file + "; " + Reflection.getCallerClass(2));
}
final VcsRoot root = new VcsRoot(vcs, file);
takeDirt(new Consumer<DirtBuilder>() {
public void consume(DirtBuilder dirtBuilder) {
@@ -254,6 +273,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
try {
final AbstractVcs vcs = myGuess.getVcsForDirty(file);
if (vcs == null) return;
if (LOG.isDebugEnabled()) {
LOG.debug("file dirty: " + file + "; " + Reflection.getCallerClass(1));
}
final FilePathUnderVcs root = new FilePathUnderVcs(file, vcs);
takeDirt(new Consumer<DirtBuilder>() {
public void consume(DirtBuilder dirtBuilder) {
@@ -272,6 +294,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
try {
final AbstractVcs vcs = myGuess.getVcsForDirty(dir);
if (vcs == null) return;
if (LOG.isDebugEnabled()) {
LOG.debug("dir dirty recursively: " + dir + "; " + Reflection.getCallerClass(2));
}
final VcsRoot root = new VcsRoot(vcs, dir);
takeDirt(new Consumer<DirtBuilder>() {
public void consume(DirtBuilder dirtBuilder) {
@@ -286,6 +311,9 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
try {
final AbstractVcs vcs = myGuess.getVcsForDirty(path);
if (vcs == null) return;
if (LOG.isDebugEnabled()) {
LOG.debug("dir dirty recursively: " + path + "; " + Reflection.getCallerClass(2));
}
final FilePathUnderVcs root = new FilePathUnderVcs(path, vcs);
takeDirt(new Consumer<DirtBuilder>() {
public void consume(DirtBuilder dirtBuilder) {
@@ -15,8 +15,12 @@
*/
package com.intellij.android.designer;
import com.intellij.android.designer.designSurface.AndroidDesignerEditorPanel;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.openapi.fileEditor.FileEditorState;
import com.intellij.openapi.fileEditor.FileEditorStateLevel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.designer.DesignerEditor;
@@ -30,6 +34,11 @@ public final class AndroidDesignerEditor extends DesignerEditor {
super(project, file);
}
@Override
protected DesignerEditorPanel createDesignerPanel(Module module, VirtualFile file) {
return new AndroidDesignerEditorPanel(module, file);
}
@NotNull
@Override
public String getName() {
@@ -0,0 +1,32 @@
/*
* 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.android.designer.componentTree;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.model.RadComponent;
import com.intellij.ui.ColoredTreeCellRenderer;
/**
* @author Alexander Lobas
*/
public final class AndroidTreeDecorator extends TreeComponentDecorator {
@Override
public void decorate(RadComponent component, ColoredTreeCellRenderer renderer) {
RadViewComponent view = (RadViewComponent)component;
renderer.append(view.getTitle());
}
}
@@ -0,0 +1,79 @@
/*
* 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.android.designer.designSurface;
import com.intellij.android.designer.componentTree.AndroidTreeDecorator;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.designer.model.RadComponent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
/**
* @author Alexander Lobas
*/
public final class AndroidDesignerEditorPanel extends DesignerEditorPanel {
private final TreeComponentDecorator myTreeDecorator = new AndroidTreeDecorator();
public AndroidDesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) {
super(module, file);
// (temp code) TODO: use platform DOM
try {
InputStream stream = file.getInputStream();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(stream, new DefaultHandler() {
RadViewComponent myComponent;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
myComponent = new RadViewComponent(myComponent, qName);
if (myRootComponent == null) {
myRootComponent = myComponent;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (myComponent != null) {
myComponent = (RadViewComponent)myComponent.getParent();
}
}
});
stream.close();
}
catch (Throwable e) {
e.printStackTrace(); // TODO
}
}
@Override
public TreeComponentDecorator getTreeDecorator() {
return myTreeDecorator;
}
}
@@ -0,0 +1,48 @@
/*
* 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.android.designer.model;
import com.intellij.designer.model.RadComponent;
import java.util.ArrayList;
import java.util.List;
/**
* TODO: now dummy implementation for tests
*
* @author Alexander Lobas
*/
public class RadViewComponent extends RadComponent {
private final String myTitle;
private final List<RadComponent> myChildren = new ArrayList<RadComponent>();
public RadViewComponent(RadViewComponent parent, String title) {
myTitle = title;
setParent(parent);
if (parent != null) {
parent.getChildren().add(this);
}
}
@Override
public List<RadComponent> getChildren() {
return myChildren;
}
public String getTitle() {
return myTitle;
}
}
+11 -5
View File
@@ -17,6 +17,7 @@ package git4idea;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
@@ -91,11 +92,16 @@ public class GitBranch extends GitReference {
*/
@NotNull
public String getShortName() {
String name = getName();
if (myRemote) {
return name.substring(name.indexOf('/') + 1);
}
return name;
return splitNameOfRemoteBranch(getName()).getSecond();
}
/**
* Returns the remote and the "local" name of a remote branch.
* Expects branch in format "origin/master", i.e. remote/branch
*/
public static Pair<String, String> splitNameOfRemoteBranch(String branchName) {
int firstSlash = branchName.indexOf('/');
return Pair.create(branchName.substring(0, firstSlash), branchName.substring(firstSlash + 1));
}
/**
@@ -21,6 +21,7 @@ import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,6 +38,12 @@ public class NotificationManager {
public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message,
@NotNull NotificationType type, @Nullable NotificationListener listener) {
// title can be empty; description can't be neither null, nor empty
if (StringUtil.isEmptyOrSpaces(message)) {
message = title;
title = "";
}
// if both title and description were empty, then it is a problem in the calling code => Notifications engine assertion will notify.
createNotification(notificationGroup, title, message, type, listener).notify(myProject);
}
@@ -15,18 +15,25 @@
*/
package git4idea.branch;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ui.UIUtil;
import git4idea.GitBranch;
import git4idea.GitExecutionException;
import git4idea.GitVcs;
import git4idea.NotificationManager;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
import git4idea.commands.GitCompoundResult;
import git4idea.history.GitHistoryUtils;
import git4idea.history.browser.GitCommit;
import git4idea.repo.GitRepository;
@@ -38,10 +45,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Executor of Git branching operations.
@@ -168,13 +173,147 @@ public final class GitBranchOperationsProcessor {
public void deleteBranch(final String branchName) {
new CommonBackgroundTask(myProject, "Deleting " + branchName, myCallInAwtAfterExecution) {
@Override public void execute(@NotNull ProgressIndicator indicator) {
doDelete(branchName, indicator);
new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute();
}
}.runInBackground();
}
private void doDelete(final String branchName, ProgressIndicator indicator) {
new GitDeleteBranchOperation(myProject, myRepositories, branchName, getCurrentBranchOrRev(), indicator).execute();
public void deleteRemoteBranch(@NotNull final String branchName) {
final Collection<String> trackingBranches = findTrackingBranches(branchName);
String currentBranch = getCurrentBranchOrRev();
boolean currentBranchTracksBranchToDelete = false;
if (trackingBranches.contains(currentBranch)) {
currentBranchTracksBranchToDelete = true;
trackingBranches.remove(currentBranch);
}
final DeleteRemoteBranchDecision decision = confirmBranchDeletion(branchName, trackingBranches, currentBranchTracksBranchToDelete);
if (decision.delete()) {
new CommonBackgroundTask(myProject, "Deleting " + branchName, myCallInAwtAfterExecution) {
@Override public void execute(@NotNull ProgressIndicator indicator) {
boolean deletedSuccessfully = doDeleteRemote(branchName);
if (deletedSuccessfully) {
final Collection<String> successfullyDeletedLocalBranches = new ArrayList<String>(1);
if (decision.deleteTracking()) {
for (final String branch : trackingBranches) {
indicator.setText("Deleting " + branch);
new GitDeleteBranchOperation(myProject, myRepositories, branch, getCurrentBranchOrRev(), indicator) {
@Override
protected void notifySuccess(@NotNull String message) {
// do nothing - will display a combo notification for all deleted branches below
successfullyDeletedLocalBranches.add(branch);
}
}.execute();
}
}
notifySuccessfulDeletion(branchName, successfullyDeletedLocalBranches);
}
}
}.runInBackground();
}
}
@NotNull
private Collection<String> findTrackingBranches(@NotNull String remoteBranch) {
return new GitMultiRootBranchConfig(myRepositories).getTrackingBranches(remoteBranch);
}
private boolean doDeleteRemote(String branchName) {
GitCompoundResult result = new GitCompoundResult(myProject);
for (GitRepository repository : myRepositories) {
Pair<String, String> pair = GitBranch.splitNameOfRemoteBranch(branchName);
GitCommandResult res = Git.push(repository, pair.getFirst(), ":" + pair.getSecond());
result.append(repository, res);
repository.update(GitRepository.TrackedTopic.BRANCHES);
}
if (!result.totalSuccess()) {
NotificationManager.getInstance(myProject).notifyError("Failed to delete remote branch " + branchName,
result.getErrorOutputWithReposIndication());
}
return result.totalSuccess();
}
private void notifySuccessfulDeletion(@NotNull String remoteBranchName, @NotNull Collection<String> localBranches) {
String message = "";
if (!localBranches.isEmpty()) {
message = "Also deleted local " + StringUtil.pluralize("branch", localBranches.size()) + ": " + StringUtil.join(localBranches, ", ");
}
NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "Deleted remote branch " + remoteBranchName,
message, NotificationType.INFORMATION);
}
private DeleteRemoteBranchDecision confirmBranchDeletion(@NotNull String branchName, @NotNull Collection<String> trackingBranches,
boolean currentBranchTracksBranchToDelete) {
String title = "Delete Remote Branch";
String message = "Delete remote branch " + branchName;
boolean delete;
final boolean deleteTracking;
if (trackingBranches.isEmpty()) {
delete = Messages.showYesNoDialog(myProject, message, title, "Delete", "Cancel", Messages.getQuestionIcon()) == Messages.OK;
deleteTracking = false;
}
else {
if (currentBranchTracksBranchToDelete) {
message += "\n\nCurrent branch " + getCurrentBranchOrRev() + " tracks " + branchName + " but won't be deleted.";
}
final String checkboxMessage;
if (trackingBranches.size() == 1) {
checkboxMessage = "Delete tracking local branch " + trackingBranches.iterator().next() + " as well";
}
else {
checkboxMessage = "Delete tracking local branches " + StringUtil.join(trackingBranches, ", ");
}
final AtomicBoolean deleteChoice = new AtomicBoolean();
delete = Messages.OK == Messages.showYesNoDialog(message, title, "Delete", "Cancel", Messages.getQuestionIcon(), new DialogWrapper.DoNotAskOption() {
@Override
public boolean isToBeShown() {
return true;
}
@Override
public void setToBeShown(boolean value, int exitCode) {
deleteChoice.set(!value);
}
@Override
public boolean canBeHidden() {
return true;
}
@Override
public boolean shouldSaveOptionsOnCancel() {
return false;
}
@Override
public String getDoNotShowMessage() {
return checkboxMessage;
}
});
deleteTracking = deleteChoice.get();
}
return new DeleteRemoteBranchDecision(delete, deleteTracking);
}
private static class DeleteRemoteBranchDecision {
private final boolean delete;
private final boolean deleteTracking;
private DeleteRemoteBranchDecision(boolean delete, boolean deleteTracking) {
this.delete = delete;
this.deleteTracking = deleteTracking;
}
public boolean delete() {
return delete;
}
public boolean deleteTracking() {
return deleteTracking;
}
}
/**
@@ -256,19 +256,27 @@ public class Git {
return run(h);
}
public static GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec, @NotNull GitLineHandlerListener... listeners) {
final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(), GitCommand.PUSH);
@NotNull
public static GitCommandResult push(@NotNull GitRepository repository, @NotNull String remote, @NotNull String spec,
@NotNull GitLineHandlerListener... listeners) {
final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(repository.getProject(), repository.getRoot(),
GitCommand.PUSH);
h.setSilent(false);
for (GitLineHandlerListener listener : listeners) {
h.addLineListener(listener);
}
h.addParameters(remote);
h.addParameters(spec);
return run(h, true);
}
@NotNull
public static GitCommandResult push(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec,
@NotNull GitLineHandlerListener... listeners) {
GitRemote remote = pushSpec.getRemote();
h.addParameters(remote.getName());
GitBranch remoteBranch = pushSpec.getDest();
String destination = remoteBranch.getName().replaceFirst(remote.getName() + "/", "");
h.addParameters(pushSpec.getSource().getName() + ":" + destination);
return run(h, true);
return push(repository, remote.getName(), pushSpec.getSource().getName() + ":" + destination);
}
private static GitCommandResult run(@NotNull GitLineHandler handler) {
@@ -251,9 +251,6 @@ class GitBranchPopupActions {
}
/**
* Action to delete a branch.
*/
private static class DeleteAction extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
@@ -302,6 +299,7 @@ class GitBranchPopupActions {
new CheckoutRemoteBranchAction(myProject, myRepositories, myBranchName, mySelectedRepository),
new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository),
new MergeAction(myProject, myRepositories, myBranchName, mySelectedRepository),
new RemoteDeleteAction(myProject, myRepositories, myBranchName, mySelectedRepository)
};
}
@@ -336,6 +334,28 @@ class GitBranchPopupActions {
return myRemoteBranchName.substring(slashPosition+1);
}
}
private static class RemoteDeleteAction extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
private final String myBranchName;
private final GitRepository mySelectedRepository;
RemoteDeleteAction(@NotNull Project project, @NotNull List<GitRepository> repositories, @NotNull String branchName,
@NotNull GitRepository selectedRepository) {
super("Delete");
myProject = project;
myRepositories = repositories;
myBranchName = branchName;
mySelectedRepository = selectedRepository;
}
@Override
public void actionPerformed(AnActionEvent e) {
new GitBranchOperationsProcessor(myProject, myRepositories, mySelectedRepository).deleteRemoteBranch(myBranchName);
}
}
}
private static class CompareAction extends DumbAwareAction {

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