From bc7167b31ff3357d70d8c15c768f693788157e66 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 12:29:51 +0100 Subject: [PATCH 01/46] fix css completion test --- .../intellij/codeInsight/completion/TemplateInsertHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java index 4d15a58b1740..531c28aff3ee 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java @@ -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); From cd463262bbfc1d016e921896b29cd92d83cf86a6 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 12:42:39 +0100 Subject: [PATCH 02/46] less invasive logging for component creation failures --- .../intellij/openapi/components/impl/ComponentManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index d0153c3796aa..c26dd1c90dc2 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -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; } From 9ab4753e354d0192e30d4fc85f52b87131d18b33 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 13:04:17 +0100 Subject: [PATCH 03/46] correctly cleanup round context --- .../jps/incremental/CompileContext.java | 17 +++++++++-------- .../org/jetbrains/jps/incremental/FSState.java | 5 ++++- .../jps/incremental/IncProjectBuilder.java | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index 994633a6ecb0..f4d3ba5dcce7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -163,20 +163,21 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler 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(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java index 1c2874f47004..63874bc38d67 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FSState.java @@ -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) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 45a26b84ca8a..7d65af0c3949 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -389,7 +389,7 @@ public class IncProjectBuilder { boolean nextPassRequired; do { nextPassRequired = false; - context.beforeNextCompileRound(chunk); + context.beforeCompileRound(chunk); if (!context.isProjectRebuild()) { syncOutputFiles(context, chunk); @@ -440,7 +440,7 @@ public class IncProjectBuilder { } while (nextPassRequired); - context.clearContextRoundData(); + context.afterCompileRound(); } } From 25c2fcbeb6867f4f85dc8abfcdb518e925e2a95f Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 10 Feb 2012 16:05:42 +0400 Subject: [PATCH 04/46] getting context fixed --- .../src/com/intellij/codeInspection/ex/InspectionTool.java | 2 +- .../intellij/codeInspection/ex/InspectionToolRegistrar.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java index 9733185e63c3..279ef0b60f33 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionTool.java @@ -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); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java index 6cd4ec9b9344..acaa6fbee662 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java @@ -339,6 +339,11 @@ public class InspectionToolRegistrar { getTool().runInspection(scope, manager); } + @Override + public GlobalInspectionContextImpl getContext() { + return getTool().getContext(); + } + @NotNull @Override public JobDescriptor[] getJobDescriptors(GlobalInspectionContext globalInspectionContext) { From 40cc655a84946938504ecb45793829dd06808689 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Fri, 10 Feb 2012 13:16:58 +0100 Subject: [PATCH 05/46] Do not show 'Index Rebuild' balloon by default. Whose who desperately need to see it, please set Registry->ide.showIndexRebuildMessage=true --- .../src/com/intellij/util/indexing/FileBasedIndex.java | 7 ++++++- .../platform-resources-en/src/misc/registry.properties | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 920ccaba4933..619ac7132312 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -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 diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 45a72e198390..8cc86d0f4215 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -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 From 377c95ee90b18686a6ece83d5844903377817808 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 13:35:41 +0100 Subject: [PATCH 06/46] correct fix for deadlock: register Maven file type via FileTypeFactory --- .../updateSettings/impl/UpdateChecker.java | 2 -- .../utils/MavenEnvironmentRegistrar.java | 20 ----------- .../maven/utils/MavenFileTypeFactory.java | 34 +++++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 1 + 4 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index ec767c5fd4c7..dd6d07f04f75 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -148,7 +148,6 @@ public final class UpdateChecker { public static ActionCallback updateAndShowResult() { final ActionCallback result = new ActionCallback(); final Application app = ApplicationManager.getApplication(); - /* app.executeOnPooledThread(new Runnable() { @Override public void run() { @@ -164,7 +163,6 @@ public final class UpdateChecker { }); } }); - */ return result; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java index 90daa24baf34..dac328542705 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenEnvironmentRegistrar.java @@ -16,15 +16,9 @@ package org.jetbrains.idea.maven.utils; -import com.intellij.ide.highlighter.XmlFileType; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathMacros; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.components.ApplicationComponent; -import com.intellij.openapi.fileTypes.FileTypeManager; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.model.MavenConstants; import java.io.File; @@ -37,23 +31,9 @@ public class MavenEnvironmentRegistrar implements ApplicationComponent { } public void initComponent() { - registerFileTypes(); registerPathVariable(); } - private void registerFileTypes() { - // we should not change file types in unit test mode - if (ApplicationManager.getApplication().isUnitTestMode()) return; - - AccessToken accessToken = WriteAction.start(); - try { - FileTypeManager.getInstance().associateExtension(XmlFileType.INSTANCE, MavenConstants.POM_EXTENSION); - } - finally { - accessToken.finish(); - } - } - private void registerPathVariable() { File repository = MavenUtil.resolveLocalRepository(null, null, null); PathMacros macros = PathMacros.getInstance(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java new file mode 100644 index 000000000000..05b51b4ea8ac --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenFileTypeFactory.java @@ -0,0 +1,34 @@ +/* + * 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 org.jetbrains.idea.maven.utils; + +import com.intellij.ide.highlighter.XmlFileType; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenConstants; + +/** + * @author yole + */ +public class MavenFileTypeFactory extends FileTypeFactory { + @Override + public void createFileTypes(@NotNull FileTypeConsumer consumer) { + if (ApplicationManager.getApplication().isUnitTestMode()) return; + consumer.consume(XmlFileType.INSTANCE, MavenConstants.POM_EXTENSION); + } +} diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 8d1e661b9d57..3857f71c8f87 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -15,6 +15,7 @@ org.intellij.groovy + From 992515d6815f162690c5ab1ce6c393e534b45447 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 10 Feb 2012 14:08:49 +0100 Subject: [PATCH 07/46] several memory leaks IDEA-75220, IDEA-80916, IDEA-80009, IDEA-76082 --- .../ide/impl/StructureViewWrapperImpl.java | 9 ++++++++- .../openapi/wm/impl/ToolWindowManagerImpl.java | 18 +++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java index 911ec07db1db..20cf9e787b77 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java @@ -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() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index c7ac33742fe9..c5f32e12a57f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -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 cmds = new ArrayList(); @@ -719,7 +719,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final ArrayList commandList, boolean forced, boolean autoFocusContents) { - if (!getFocusManagerImpl().isUnforcedRequestAllowed() && !forced) return; + if (/*!getFocusManagerImpl(myProject).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); } From cb0442de53dc10eb4b4d2373db6c58062745b815 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 12:14:32 +0100 Subject: [PATCH 08/46] IDEA-76599 Quickfix to change a double literal to a float literal --- .../impl/analysis/HighlightMethodUtil.java | 2 + .../daemon/impl/analysis/HighlightUtil.java | 2 +- .../quickfix/ConvertDoubleToFloatFix.java | 109 ++++++++++++++++++ .../quickFix/convertDoubleToFloat/after1.java | 7 ++ .../quickFix/convertDoubleToFloat/after2.java | 7 ++ .../quickFix/convertDoubleToFloat/after3.java | 7 ++ .../quickFix/convertDoubleToFloat/after4.java | 7 ++ .../quickFix/convertDoubleToFloat/after5.java | 7 ++ .../convertDoubleToFloat/before1.java | 7 ++ .../convertDoubleToFloat/before2.java | 7 ++ .../convertDoubleToFloat/before3.java | 7 ++ .../convertDoubleToFloat/before4.java | 7 ++ .../convertDoubleToFloat/before5.java | 7 ++ .../convertDoubleToFloat/before6.java | 7 ++ .../convertDoubleToFloat/before7.java | 7 ++ .../quickFix/ConvertDoubleToFloatFixTest.java | 29 +++++ 16 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 90ffa0ab8fcf..e8a00be3524b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -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); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 1ac11d19ccaf..5d6a82078bc7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -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; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java new file mode 100644 index 000000000000..cb8122b75a75 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertDoubleToFloatFix.java @@ -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); + } + } + } + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java new file mode 100644 index 000000000000..150bd12f3c60 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after1.java @@ -0,0 +1,7 @@ +// "Convert '1e1' to float" "true" +class Test { + void bar() { + foo(1e1f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java new file mode 100644 index 000000000000..99cdfdf2f2af --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after2.java @@ -0,0 +1,7 @@ +// "Convert '2.' to float" "true" +class Test { + void bar() { + foo(2.f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java new file mode 100644 index 000000000000..9272f41b2410 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after3.java @@ -0,0 +1,7 @@ +// "Convert '.3' to float" "true" +class Test { + void bar() { + foo(.3f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java new file mode 100644 index 000000000000..9d3993fd0f27 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after4.java @@ -0,0 +1,7 @@ +// "Convert '0.0' to float" "true" +class Test { + void bar() { + foo(0.0f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java new file mode 100644 index 000000000000..7e70cf492967 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/after5.java @@ -0,0 +1,7 @@ +// "Convert '3.14' to float" "true" +class Test { + void bar() { + foo(3.14f); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java new file mode 100644 index 000000000000..e476b77bc9e0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before1.java @@ -0,0 +1,7 @@ +// "Convert '1e1' to float" "true" +class Test { + void bar() { + foo(1e1); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java new file mode 100644 index 000000000000..fa67aa86c9bf --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before2.java @@ -0,0 +1,7 @@ +// "Convert '2.' to float" "true" +class Test { + void bar() { + foo(2.); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java new file mode 100644 index 000000000000..3f6fb07e7b48 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before3.java @@ -0,0 +1,7 @@ +// "Convert '.3' to float" "true" +class Test { + void bar() { + foo(.3); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java new file mode 100644 index 000000000000..92cb59d6872e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before4.java @@ -0,0 +1,7 @@ +// "Convert '0.0' to float" "true" +class Test { + void bar() { + foo(0.0); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java new file mode 100644 index 000000000000..9541ec5647fe --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before5.java @@ -0,0 +1,7 @@ +// "Convert '3.14' to float" "true" +class Test { + void bar() { + foo(3.14); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java new file mode 100644 index 000000000000..1799fb8943ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before6.java @@ -0,0 +1,7 @@ +// "Convert '1e-9d' to float" "false" +class Test { + void bar() { + foo(1e-9d); + } + void foo(float f){} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java new file mode 100644 index 000000000000..fe93892a6b6d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertDoubleToFloat/before7.java @@ -0,0 +1,7 @@ +// "Convert '1e137' to float" "false" +class Test { + void bar() { + foo(1e137); + } + void foo(float f){} +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java new file mode 100644 index 000000000000..1f57ad9d67a7 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertDoubleToFloatFixTest.java @@ -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"; + } +} From fbf99fd29b26439b02d22fd488b59964b28de78e Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 14:27:15 +0100 Subject: [PATCH 09/46] show autopopup after completing a package when and only when there was a dot inserted after the previous package --- .../intellij/codeInsight/editorActions/JavaTypedHandler.java | 2 +- .../com/intellij/codeInsight/lookup/PackageLookupItem.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index d684041bc68b..bd44b70fdc28 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -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 { diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java index 4374d9f6b3f4..168d5444ca71 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PackageLookupItem.java @@ -33,6 +33,8 @@ class PackageLookupItem extends LookupItem { @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); + } } } From a58a8ec63760670691e02b19478a3781cf52b127 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 14:28:42 +0100 Subject: [PATCH 10/46] EA-33623 - AIOOBE: ExpectedTypesProvider$MyParentVisitor.visitPolyadicExpression --- .../src/com/intellij/codeInsight/ExpectedTypesProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 128276a52113..dfba4c4c2224 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -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 || From 4900a53a49e956689ac52ba4a31048660d414a77 Mon Sep 17 00:00:00 2001 From: Serega Vasiliev Date: Fri, 10 Feb 2012 15:22:13 +0100 Subject: [PATCH 11/46] dom perfomance improvements (peter) --- .../psi/util/CachedValuesManager.java | 7 +++++-- .../intellij/util/xml/impl/DomImplUtil.java | 20 ++++++++++++------- .../util/xml/impl/DomInvocationHandler.java | 4 ---- .../xml/impl/DomRootInvocationHandler.java | 1 - .../xml/impl/FixedChildDescriptionImpl.java | 1 - .../GetCompositeCollectionInvocation.java | 1 - .../xml/impl/GetFixedChildInvocation.java | 1 - .../intellij/util/xml/impl/GetInvocation.java | 1 - 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java index e2c805e5cc5e..49391709ed00 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java @@ -93,17 +93,20 @@ public abstract class CachedValuesManager { } public static class MemoizationKey extends Key { + 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); } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java index d7d5bfb5d9dc..822aa9f0c701 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomImplUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiInvalidElementAccessException; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.xml.*; import com.intellij.util.ReflectionCache; @@ -149,14 +150,19 @@ public class DomImplUtil { } return ContainerUtil.findAll(tag.getSubTags(), new Condition() { public boolean value(XmlTag childTag) { - if (!childTag.isValid()) { - LOG.error("tag.getSubTags() returned invalid, " + - "tag=" + tag + ", " + - "containing file: " + tag.getContainingFile() + - "subTag.parent=" + childTag.getNode().getTreeParent()); - return false; + try { + return isNameSuitable(name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file); + } + catch (PsiInvalidElementAccessException e) { + if (!childTag.isValid()) { + LOG.error("tag.getSubTags() returned invalid, " + + "tag=" + tag + ", " + + "containing file: " + tag.getContainingFile() + + "subTag.parent=" + childTag.getNode().getTreeParent()); + return false; + } + throw e; } - return isNameSuitable(name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file); } }); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java index 44d69049c9a7..b7480910ed49 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java @@ -132,8 +132,6 @@ public abstract class DomInvocationHandler subTags = tagsGetter.fun(this); if (subTags.isEmpty()) return Collections.emptyList(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java index f03e9b9b3782..d504a0a14401 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomRootInvocationHandler.java @@ -89,7 +89,6 @@ public class DomRootInvocationHandler extends DomInvocationHandler result = new SmartList(); final DomInvocationHandler handler = DomManagerImpl.getDomInvocationHandler(element); if (handler != null) { - handler.assertValid(); for (int i = 0; i < myCount; i++) { result.add(handler.getFixedChild(Pair.create(this, i)).getProxy()); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java index b4457905f8c6..37c6602922c4 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetCompositeCollectionInvocation.java @@ -33,7 +33,6 @@ class GetCompositeCollectionInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); Map map = new THashMap(); for (final CollectionChildDescriptionImpl qname : myQnames) { for (DomElement element : handler.getCollectionChildren(qname, qname.getTagsGetter())) { diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java index fb22399fdf08..689a01f5a22f 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetFixedChildInvocation.java @@ -13,7 +13,6 @@ public class GetFixedChildInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); return handler.getFixedChild(myPair).getProxy(); } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java index 9f833cf1fd63..a59f30d4dd7d 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/GetInvocation.java @@ -30,7 +30,6 @@ public class GetInvocation implements Invocation { } public Object invoke(final DomInvocationHandler handler, final Object[] args) throws Throwable { - handler.assertValid(); if (myConverter == Converter.EMPTY_CONVERTER) { return getValueInner(handler, myConverter); } From 01ee49fb8b81f4b491296703ecf315daf52a11d5 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 15:07:33 +0100 Subject: [PATCH 12/46] usage targets may become invalid (EA-33613) --- .../com/intellij/usages/impl/UsageViewTreeCellRenderer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java index a4fbf29eccce..33e6e09a3dba 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewTreeCellRenderer.java @@ -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) { From c83cc1970e4624423aa7de3d3ecbbf5a7a0577f8 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 15:32:52 +0100 Subject: [PATCH 13/46] IDEA-81192 Event Log: special html characters are not replaced (see screenshot) --- .../src/com/intellij/notification/EventLog.java | 5 ++++- .../testSrc/com/intellij/notification/EventLogTest.groovy | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index 88c37d54a8f3..acb1dd32c986 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -165,7 +165,7 @@ public class EventLog implements Notifications { content = title + (StringUtil.isNotEmpty(content) ? ": " + content : ""); } - content = StringUtil.replace(StringUtil.convertLineSeparators(content), " ", " "); + 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, " ", " "); + text = StringUtil.replace(text, "»", ">>"); + text = StringUtil.replace(text, "«", "<<"); document.insertString(document.getTextLength(), StringUtil.unescapeXml(text)); } diff --git a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy index 3b1360036d49..baf2f08ef1d4 100644 --- a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy @@ -29,9 +29,9 @@ class EventLogTest extends LightPlatformTestCase { PlatformTestCase.initPlatformLangPrefix() } - public void testNbsp() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world", NotificationType.ERROR)) - assert entry.message == 'Title: Hello world' + public void testHtmlEntities() { + def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world«»", NotificationType.ERROR)) + assert entry.message == 'Title: Hello world<<>>' } public void testParseMultilineText() { From 0d36f69fdfb9219f2ebb3de7adf82d35fb72d6a4 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 15:42:02 +0100 Subject: [PATCH 14/46] fix CCE in tests --- .../codeInspection/local/GroovyPostHighlightingPass.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index c61ef6fb13b9..b29f0906545b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java @@ -25,7 +25,6 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; -import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationSession; @@ -87,8 +86,7 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { if (!fileIndex.isInContent(virtualFile)) { return; } - final InspectionToolWrapper wrapper = (InspectionToolWrapper)profile.getInspectionTool(UnusedDeclarationInspection.SHORT_NAME, myFile); - final UnusedDeclarationInspection deadCodeInspection = wrapper != null ? (UnusedDeclarationInspection)wrapper.getTool() : null; + final UnusedDeclarationInspection deadCodeInspection = (UnusedDeclarationInspection)profile.getUnwrappedTool(UnusedDeclarationInspection.SHORT_NAME, myFile); final GlobalUsageHelper usageHelper = new GlobalUsageHelper() { public boolean isCurrentFileAlreadyChecked() { return false; From 13242b71c3edf2ac31e5a2704ba384038a16721a Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 10 Feb 2012 18:47:40 +0400 Subject: [PATCH 15/46] initializing context fixed --- .../intellij/codeInspection/ex/InspectionToolRegistrar.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java index acaa6fbee662..3cf54d5b3cee 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java @@ -340,8 +340,8 @@ public class InspectionToolRegistrar { } @Override - public GlobalInspectionContextImpl getContext() { - return getTool().getContext(); + public void initialize(@NotNull GlobalInspectionContextImpl context) { + getTool().initialize(context); } @NotNull From 446f677828dec2a936e20cb0459720bb3cff0b7b Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 18:48:29 +0400 Subject: [PATCH 16/46] Git NotificationManager: defend against empty content in notifications --- plugins/git4idea/src/git4idea/NotificationManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/git4idea/src/git4idea/NotificationManager.java b/plugins/git4idea/src/git4idea/NotificationManager.java index 7977bca38c30..fa1290128cbf 100644 --- a/plugins/git4idea/src/git4idea/NotificationManager.java +++ b/plugins/git4idea/src/git4idea/NotificationManager.java @@ -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); } From 226c141009ee96c9bda65f97b5d1cb6d88e684df Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 10 Feb 2012 18:53:40 +0400 Subject: [PATCH 17/46] IDEA-78011 Git: Deleting remote branch Show confirmation. Also propose to delete local branch(es) tracking the remote branch via checkbox. Don't propose to delete current branch, but warn about it. Join notifications about remote and local branch deletetions into a single one - for this call GitDeleteOperation with an overridden notifySuccess(). --- plugins/git4idea/src/git4idea/GitBranch.java | 16 +- .../branch/GitBranchOperationsProcessor.java | 153 +++++++++++++++++- .../git4idea/src/git4idea/commands/Git.java | 20 ++- .../ui/branch/GitBranchPopupActions.java | 26 ++- .../ui/branch/GitMultiRootBranchConfig.java | 30 ++++ 5 files changed, 224 insertions(+), 21 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitBranch.java b/plugins/git4idea/src/git4idea/GitBranch.java index 1714fe74e304..e04e9cc1677b 100644 --- a/plugins/git4idea/src/git4idea/GitBranch.java +++ b/plugins/git4idea/src/git4idea/GitBranch.java @@ -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 splitNameOfRemoteBranch(String branchName) { + int firstSlash = branchName.indexOf('/'); + return Pair.create(branchName.substring(0, firstSlash), branchName.substring(firstSlash + 1)); } /** diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index 887983904b2c..c8eaed476653 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -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 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 successfullyDeletedLocalBranches = new ArrayList(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 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 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 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 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; + } } /** diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 27f94bf775b9..bbe265ba0977 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -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) { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java index fa6e23495187..692bd47d525d 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopupActions.java @@ -251,9 +251,6 @@ class GitBranchPopupActions { } - /** - * Action to delete a branch. - */ private static class DeleteAction extends DumbAwareAction { private final Project myProject; private final List 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 myRepositories; + private final String myBranchName; + private final GitRepository mySelectedRepository; + + RemoteDeleteAction(@NotNull Project project, @NotNull List 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 { diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java index a4040993053e..9aedb95d9477 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java @@ -24,6 +24,7 @@ import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -110,6 +111,35 @@ public class GitMultiRootBranchConfig { return trackedRemote + "/" + trackedBranch; } + /** + * Returns local branches which track the given remote branch. Usually there is 0 or 1 such branches. + */ + @NotNull + public Collection getTrackingBranches(@NotNull String remoteBranch) { + Collection trackingBranches = null; + for (GitRepository repository : myRepositories) { + Collection tb = getTrackingBranches(repository, remoteBranch); + if (trackingBranches == null) { + trackingBranches = tb; + } + else { + trackingBranches.retainAll(tb); + } + } + return trackingBranches == null ? Collections.emptyList() : trackingBranches; + } + + @NotNull + public static Collection getTrackingBranches(@NotNull GitRepository repository, @NotNull String remoteBranch) { + Collection trackingBranches = new ArrayList(1); + for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { + if (remoteBranch.equals(trackInfo.getRemote().getName() + "/" + trackInfo.getRemoteBranch())) { + trackingBranches.add(trackInfo.getBranch()); + } + } + return trackingBranches; + } + @Nullable private static Pair getTrackedBranchAndRemote(@NotNull GitRepository repository, @NotNull String branch) { for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { From cf843a27864cc2fd951a4574df5809f984cfd45f Mon Sep 17 00:00:00 2001 From: "kirill.safonov" Date: Fri, 10 Feb 2012 18:45:52 +0400 Subject: [PATCH 18/46] all capitals --- .../intellij/openapi/diff/impl/patch/formove/PathsVerifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java index ffca0ed834c2..7ab196a1b4b1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PathsVerifier.java @@ -564,7 +564,7 @@ public class PathsVerifier { public Collection doDelayed() { final List result = new LinkedList(); if (! myOverrideExisting.isEmpty()) { - final String title = "Overwrite existing files"; + final String title = "Overwrite Existing Files"; final Collection selected = AbstractVcsHelper.getInstance(myProject).selectFilePathsToProcess( new ArrayList(myOverrideExisting.keySet()), title, "\nThe following files should be created by patch, but they already exist.\nDo you want to overwrite them?\n", title, From 54c030e9beb8bec7a688886220e0f671837d39c5 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 16:24:48 +0100 Subject: [PATCH 19/46] diagnostics --- .../psi/impl/source/codeStyle/CodeStyleSchemeImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java index b358c506ae5b..0971828fc653 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java @@ -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); From 4840d541ed7b10008dc5532b7d82709deb680ca8 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 10 Feb 2012 17:14:31 +0400 Subject: [PATCH 20/46] fix memory leak: [thread local] strong ref for SaxBuilder also references Element processed --- .../com/intellij/openapi/util/JDOMUtil.java | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java index a7826308a2c6..02076e7106a6 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java @@ -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 ourSaxBuilder = new ThreadLocal(){ - 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> ourSaxBuilder = new ThreadLocal>(); 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 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)); + } + 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(); From 849bc0e7071e37b1e61d157cf13ef35080d196d9 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 10 Feb 2012 19:31:39 +0400 Subject: [PATCH 21/46] prefer to use THashMap instead of TreeMap & do not store JDOM's Element for read-only components state --- .../impl/stores/ModuleStoreImpl.java | 9 ++-- .../impl/stores/ComponentStoreImpl.java | 6 ++- .../CompoundExternalizationSession.java | 4 +- .../impl/stores/StateStorageManagerImpl.java | 11 +++-- .../impl/stores/XmlElementStorage.java | 45 ++++++++----------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java index 5d0e994a317c..c7304c1774ea 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java @@ -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(); + myOptions = new THashMap(2); } protected ModuleFileData(final ModuleFileData storageData) { super(storageData); - myOptions = new TreeMap(storageData.myOptions); + myOptions = new THashMap(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 options = myOptions.keySet(); + String[] options = ArrayUtil.toStringArray(myOptions.keySet()); + Arrays.sort(options); for (String option : options) { root.setAttribute(option, myOptions.get(option)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java index 2a4de0fe062f..ad9042e4212c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java @@ -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 myComponents = Collections.synchronizedMap(new TreeMap()); + private final Map myComponents = Collections.synchronizedMap(new THashMap()); private final List mySettingsSavingComponents = Collections.synchronizedList(new ArrayList()); @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); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java index f01ebe3fd15f..9e1b202676ac 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundExternalizationSession.java @@ -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 mySessions = new HashMap(); + private final Map mySessions = new THashMap(1); public StateStorage.ExternalizationSession getExternalizationSession(StateStorage stateStore) { StateStorage.ExternalizationSession session = mySessions.get(stateStore); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index c30837efe7a9..a8f94b8a3fb5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -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 myMacros = new HashMap(); - private final Map myStorages = new HashMap(); - private final Map myPathToStorage = new HashMap(); + private final Map myStorages = new THashMap(); + private final Map myPathToStorage = new THashMap(); private final TrackingPathMacroSubstitutor myPathMacroSubstitutor; private final String myRootTagName; private Object mySession; @@ -160,7 +161,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } private Map loadVersions() { - TreeMap result = new TreeMap(); + THashMap result = new THashMap(); String filePath = getNotNullVersionsFilePath(); if (filePath != null) { try { @@ -580,8 +581,10 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di public static Element createComponentVersionsXml(Map 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"); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index 4b9d7324ba75..b439c3e212dc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -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 myStorageComponentStates = new TreeMap(); + private final Map myStorageComponentStates = new THashMap(); // 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 loadVersions(Document copy) { - - HashMap result = new HashMap(); + THashMap result = new THashMap(); 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(); + myComponentStates = new THashMap(); myRootElementName = rootElementName; } protected StorageData(StorageData storageData) { myRootElementName = storageData.myRootElementName; - myComponentStates = new TreeMap(storageData.myComponentStates); + myComponentStates = new THashMap(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(); + myProviderVersions = new THashMap(); for (RoamingType type : RoamingType.values()) { Document doc = null; if (myStreamProvider.isEnabled()) { From b902b14fc4a59f6da828fd77e4d39ece282a8c35 Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 10 Feb 2012 19:33:01 +0400 Subject: [PATCH 22/46] better logging --- .../org/jetbrains/idea/maven/project/MavenProject.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 767438724e2a..6503756ea1c7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -802,14 +802,17 @@ public class MavenProject { @NotNull public ModuleType getModuleType() { + MavenImporter mavenImporter = null; ModuleType typeFromImporter = null; + for (MavenImporter each : getSuitableImporters()) { final ModuleType moduleType = each.getModuleType(); if (typeFromImporter != null && !typeFromImporter.equals(moduleType)) { MavenLog.LOG.error("Incompatible plugins: " + each.getClass().getName() + " wants to create " + - moduleType.getName() + " for project " + getName() + " whereas some other importer requires " + - typeFromImporter.getName()); + moduleType.getName() + " for project " + getName() + + " whereas " + mavenImporter.getClass().getName() + " requires " + typeFromImporter.getName()); } + mavenImporter = each; typeFromImporter = moduleType; } return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; From cb907f41286dec974dba53d8c77187f684bb2adf Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 16:09:18 +0100 Subject: [PATCH 23/46] visibility inspection: do not suggest private for constants used in class modifier lists and for inner classes used in extends/implements (IDEA-81161) --- .../visibility/VisibilityInspection.java | 21 ++++++++++++++++++ .../expected.xml | 22 +++++++++++++++++++ .../src/ThisClass.java | 9 ++++++++ .../VisibilityInspectionTest.java | 7 ++++++ 4 files changed, 59 insertions(+) create mode 100644 java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml create mode 100644 java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index d8028dee779f..c1f79c9a9e33 100644 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -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) { diff --git a/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml new file mode 100644 index 000000000000..81532476144b --- /dev/null +++ b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/expected.xml @@ -0,0 +1,22 @@ + + + + ThisClass.java + 5 + Declaration access can be weaker + + + + Can be package local + + + ThisClass.java + 4 + Declaration access can be weaker + + + + Can be package local + + + diff --git a/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java new file mode 100644 index 000000000000..67433f26feee --- /dev/null +++ b/java/java-tests/testData/inspection/visibility/usedFromAnnotationsExtendsList/src/ThisClass.java @@ -0,0 +1,9 @@ +import java.util.ArrayList; +@SuppressWarnings(ThisClass.PUBLICFINALNAME) +public class ThisClass extends ArrayList { + public static final String PUBLICFINALNAME = "stuff"; + public static class FF {} + + public static void main(String[] args) { + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java index 4eb8bd32ef39..9cbb9ef2f697 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/VisibilityInspectionTest.java @@ -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); + } } From ba961d59adbd9e907be46397e004c444307ada18 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 16:47:41 +0100 Subject: [PATCH 24/46] highlight error: access to a private field from a class annotation is not possible --- .../analysis/AnnotationsHighlightUtil.java | 33 +++++++++++++++++++ .../impl/analysis/HighlightVisitorImpl.java | 1 + ...ightInaccessibleFromClassModifierList.java | 4 +++ .../daemon/LightAdvHighlightingJdk7Test.java | 4 +++ 4 files changed, 42 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 8f9282affd6f..017ec0dea27d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -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++) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 8703ff06fd77..1c6f41d71759 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -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) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java new file mode 100644 index 000000000000..e02db8fb902f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/HighlightInaccessibleFromClassModifierList.java @@ -0,0 +1,4 @@ +@SuppressWarnings(ThisClass.FOO) +public class ThisClass { + private static final String FOO = "foo"; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 7e2951ec1186..55a041c9e77c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -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 point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL); EntryPoint extension = new EntryPoint() { From 0a1488ecf08694ab426defad9d6ae41f6073d2c5 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 10 Feb 2012 16:46:59 +0100 Subject: [PATCH 25/46] don't go deeper than it's needed when searching --- .../fileStructure/filtering/SelectLeafFirst.java | 13 +++++++++++++ .../fileStructure/filtering/SelectLeafFirst.tree | 5 +++++ .../fileStructure/filtering/SelectLeafFirst2.java | 13 +++++++++++++ .../fileStructure/filtering/SelectLeafFirst2.tree | 5 +++++ .../JavaFileStructureFilteringTest.java | 2 ++ .../com/intellij/ide/util/FileStructurePopup.java | 5 +++++ 6 files changed, 43 insertions(+) create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java create mode 100644 java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java new file mode 100644 index 000000000000..45eda4e21e07 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.java @@ -0,0 +1,13 @@ +class SelectLeafFirst { + void aaa(){} + + void bbb(){} + void clear(){} + void zzz(){} + class ClearClass { + void kkk(){} + void www(){} + void clear(){} + void yyy(){} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree new file mode 100644 index 000000000000..69af4146c71c --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst.tree @@ -0,0 +1,5 @@ +-SelectLeafFirst.java + -SelectLeafFirst + [clear():void] + -ClearClass + clear():void \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java new file mode 100644 index 000000000000..06d505284632 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.java @@ -0,0 +1,13 @@ +class SelectLeafFirst2 { + void aaa(){} + void bbb(){} + void clear(){} + void zzz(){} + class ClearClass { + void kkk(){} + + void www(){} + void clear(){} + void yyy(){} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree new file mode 100644 index 000000000000..cb8224d167d5 --- /dev/null +++ b/java/java-tests/testData/fileStructure/filtering/SelectLeafFirst2.tree @@ -0,0 +1,5 @@ +-SelectLeafFirst2.java + -SelectLeafFirst2 + clear():void + -ClearClass + [clear():void] \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java index 848828f915b6..7875a69ed5b1 100644 --- a/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java +++ b/java/java-tests/testSrc/com/intellij/ide/fileStructure/JavaFileStructureFilteringTest.java @@ -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");} } diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 1d6b184ad403..e3658fde5afa 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -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(); From db59b7c021039830fe9137f955a275fa932e8c4f Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:31:45 +0100 Subject: [PATCH 26/46] allow specifying fixed file name via AttributesDefaults --- .../ide/fileTemplates/actions/AttributesDefaults.java | 10 ++++++++++ .../actions/CreateFromTemplateActionBase.java | 1 + .../ide/fileTemplates/ui/CreateFromTemplateDialog.java | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java index 38f85cb9e1bb..3a53701e0500 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/AttributesDefaults.java @@ -32,6 +32,7 @@ public class AttributesDefaults { private final String myDefaultName; private final TextRange myDefaultRange; private final Map> myNamesToValueAndRangeMap = new HashMap>(); + private boolean myFixedName; public AttributesDefaults(@NonNls @Nullable final String defaultName, @Nullable final TextRange defaultRange) { @@ -78,4 +79,13 @@ public class AttributesDefaults { final Pair valueAndRange = myNamesToValueAndRangeMap.get(attributeKey); return valueAndRange == null ? null : valueAndRange.first; } + + public boolean isFixedName() { + return myFixedName; + } + + public AttributesDefaults withFixedName(boolean fixedName) { + myFixedName = fixedName; + return this; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java index 93f0f2940212..4e71423b46ca 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java @@ -63,6 +63,7 @@ public abstract class CreateFromTemplateActionBase extends AnAction { } } + @Nullable protected PsiDirectory getTargetDirectory(DataContext dataContext, IdeView view) { return DirectoryChooserUtil.getOrChooseDirectory(view); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 4a22227d958a..a3506db2ffbd 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -65,6 +65,11 @@ public class CreateFromTemplateDialog extends DialogWrapper { myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties; FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory); + boolean mustEnterName = !myTemplate.isTemplateOfType(StdFileTypes.JAVA); + if (attributesDefaults != null && attributesDefaults.isFixedName()) { + myDefaultProperties.setProperty(FileTemplate.ATTRIBUTE_NAME, attributesDefaults.getDefaultFileName()); + mustEnterName = false; + } String[] unsetAttributes = null; try { @@ -75,7 +80,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(); } From 9beb9183826e6f482e7223a4dd3e2f9e9e1d7cfe Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:37:50 +0100 Subject: [PATCH 27/46] order of fields in create from template dialog is same as order of unset attributes in template --- .../src/com/intellij/ide/fileTemplates/FileTemplateUtil.java | 2 +- .../intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 3ed275e3a9f0..eab211ad86d0 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -118,7 +118,7 @@ public class FileTemplateUtil{ } public static String[] calculateAttributes(String templateContent, Properties properties, boolean includeDummies) throws ParseException { - final Set unsetAttributes = new HashSet(); + final Set unsetAttributes = new LinkedHashSet(); final Set definedAttributes = new HashSet(); //noinspection HardCodedStringLiteral SimpleNode template = RuntimeSingleton.parse(new StringReader(templateContent), "MyTemplate"); diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index b42b97ab74f2..bfac28500a54 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -57,7 +57,6 @@ public class CreateFromTemplatePanel{ myMustEnterName = mustEnterName; myUnsetAttributes = unsetAttributes; myAttributesDefaults = attributesDefaults; - Arrays.sort(myUnsetAttributes); } public boolean hasSomethingToAsk() { From bc41299b51b6a5e615f6da29b93df4187974aefc Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:51:00 +0100 Subject: [PATCH 28/46] cleanup --- .../ui/CreateFromTemplateDialog.java | 2 +- .../ui/CreateFromTemplatePanel.java | 25 ++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index a3506db2ffbd..1bc050415a9a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -115,7 +115,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); diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index bfac28500a54..71068baeab5c 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -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; @@ -94,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){ @@ -133,7 +130,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 { @@ -193,17 +190,17 @@ public class CreateFromTemplatePanel{ } } - public Properties getProperties(Properties predefinedProperties){ + public Properties getProperties(Properties predefinedProperties) { Properties result = (Properties) predefinedProperties.clone(); for (Pair 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); } } From ef2af40b07fcc35ec7578087fdeb4ef1795d22ea Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 17:53:55 +0100 Subject: [PATCH 29/46] more deadlock avoidance (IDEA-81206) --- .../connect/StatisticsHttpClientSender.java | 3 +- .../impl/CheckForUpdateAction.java | 5 ++- .../updateSettings/impl/UpdateChecker.java | 36 +++++++++---------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java b/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java index 535b8ad9b53c..c3f3fb4d615d 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/connect/StatisticsHttpClientSender.java @@ -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()), }); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java index 006173d6e2d0..f9cd94fea2d6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java @@ -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 updatedPlugins = UpdateChecker.updatePlugins(true, hostsConfigurable); ApplicationManager.getApplication().invokeLater(new Runnable() { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index dd6d07f04f75..ebf23d0ca097 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -148,10 +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 updatedPlugins = updatePlugins(false, null); app.invokeLater(new Runnable() { @@ -344,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(); @@ -364,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 getKnownChannelsIds() { - return UpdateSettings.getInstance().getKnownChannelsIds(); + return updateSettings.getKnownChannelsIds(); } @Override @@ -392,21 +390,21 @@ public final class UpdateChecker { @Override public void setKnownChannelIds(List 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()); } @@ -442,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); @@ -475,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 { From 4dc22f8c877fe0cb144fa1291802e253d5dffff7 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 14:08:33 +0100 Subject: [PATCH 30/46] progress cleanup --- .../jps/incremental/java/JavaBuilder.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index ac1d7e09b598..acbd1140f795 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -257,7 +257,7 @@ public class JavaBuilder extends ModuleLevelBuilder { if (hasSourcesToCompile) { final Set sourcePath = TEMPORARY_SOURCE_ROOTS_KEY.get(context, Collections.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); @@ -316,6 +316,24 @@ public class JavaBuilder extends ModuleLevelBuilder { return exitCode; } + private static String getChunkPresentableName(ModuleChunk chunk) { + final Set modules = chunk.getModules(); + if (modules.isEmpty()) { + return ""; + } + 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 files, Collection classpath, Collection platformCp, From 2c7fecececb38540493d99578ce6579f1803f64a Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 17:47:38 +0100 Subject: [PATCH 31/46] javac canceling (embedded and external) checkCanceled convenience method in context waitFor() API for RequestFuture --- .../compiler/CompileServerManager.java | 10 +-- .../intellij/compiler/impl/CompileDriver.java | 36 ++-------- .../org/jetbrains/jps/api/RequestFuture.java | 29 ++++++-- .../jps/incremental/CompileContext.java | 13 +++- .../jps/incremental/IncProjectBuilder.java | 21 ++---- .../jps/incremental/java/JavaBuilder.java | 23 ++++--- .../jetbrains/jps/javac/JavacFileManager.java | 28 ++++++++ .../org/jetbrains/jps/javac/JavacMain.java | 15 +++-- .../org/jetbrains/jps/javac/JavacServer.java | 66 +++++++++++++++---- 9 files changed, 153 insertions(+), 88 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index ffbcdd9586d9..649db10233dd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -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; } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 857d42b0632b..0b1bf1f4605c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -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 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 fetchFiles(CompileContextImpl context) { if (context.isRebuild()) { return Collections.emptyList(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java b/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java index 7ff90b9cdc7a..7366541b20cd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/RequestFuture.java @@ -79,17 +79,34 @@ public class RequestFuture 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; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index f4d3ba5dcce7..90bd4e549c4e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -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,10 +156,20 @@ 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; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 7d65af0c3949..5270a2c7c27a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -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 filesToDelete = new ArrayList(); for (File outputRoot : rootsToDelete) { - if (myCancelStatus.isCanceled()) { - throw new ProjectBuildException(CANCELED_MESSAGE); - } + context.checkCanceled(); boolean okToDelete = true; if (PathUtil.isUnder(allSourceRoots, outputRoot)) { okToDelete = false; @@ -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 @@ -447,9 +438,7 @@ public class IncProjectBuilder { 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(); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index acbd1140f795..bfde575cf4d9 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -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 @@ -263,8 +263,13 @@ public class JavaBuilder extends ModuleLevelBuilder { final boolean compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink); final Map 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")); } @@ -356,14 +365,10 @@ public class JavaBuilder extends ModuleLevelBuilder { final RequestFuture 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(); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java index a7aac0fce6dc..73e238f9bdd7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java @@ -66,6 +66,18 @@ class JavacFileManager extends ForwardingJavaFileManager sourcePath, Map> 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 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() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java index 2b75d6dc7673..537cdf6a64e8 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java @@ -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 options, Collection files, Collection classpath, Collection platformCp, Collection sourcePath, Map> outs) { + public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, + final UUID sessionId, + List options, + Collection files, + Collection classpath, + Collection platformCp, + Collection sourcePath, + Map> 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 myCancelHandlers = Collections.synchronizedSet(new HashSet()); + + public void cancelBuilds() { + synchronized (myCancelHandlers) { + for (CancelHandler handler : myCancelHandlers) { + handler.cancel(); + } + } } private static List toFiles(List 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; + } + } } \ No newline at end of file From 31d0a6b540c34c640a67a9b241a102c0dcedc62f Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:18:32 +0100 Subject: [PATCH 32/46] put text fields to the right of, not under labels --- .../ide/fileTemplates/ui/CreateFromTemplatePanel.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java index 71068baeab5c..4fd7bb5a1e4f 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplatePanel.java @@ -115,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)); @@ -147,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); @@ -168,9 +169,9 @@ public class CreateFromTemplatePanel{ } } myAttributes.add(new Pair(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++; } From 51687bc9556c59416c455f450eda3c1e58a6d4c5 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 18:03:37 +0100 Subject: [PATCH 33/46] inplace: preserve caret position; stop template when dialog would be open --- .../introduce/inplace/InplaceVariableIntroducer.java | 5 +++++ .../refactoring/rename/inplace/InplaceRefactoring.java | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index 21f0e587b203..1a0027304954 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -148,6 +148,11 @@ public abstract class InplaceVariableIntroducer extends In protected void collectAdditionalElementsToRename(List> stringUsages) { } + @Override + protected int restoreCaretOffset(int offset) { + return myCaretRangeMarker.isValid() ? myCaretRangeMarker.getStartOffset() : offset; + } + @Override protected String getCommandName() { return myTitle; diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java index 9164e640fa5c..d27119aa63a6 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java @@ -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) { From 0ab60fac592d7790a05ed8f5175ea7103d3d24e8 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:43:24 +0100 Subject: [PATCH 34/46] extend create from template API: pass DataContext to getAttributesDefaults(), add callback after element was created --- .../actions/CreateFromTemplateActionBase.java | 10 ++++++++-- .../ide/fileTemplates/ui/CreateFromTemplateDialog.java | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java index 4e71423b46ca..4d700b0ae1d6 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/actions/CreateFromTemplateActionBase.java @@ -55,8 +55,11 @@ 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); } } @@ -74,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) { + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 1bc050415a9a..aaa153d3161e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -125,6 +125,10 @@ 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()); } From 75c48309a83be259942a698f12d2ff1037608097 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Fri, 10 Feb 2012 21:47:26 +0400 Subject: [PATCH 35/46] moved murmur String hash method into StringHash --- .../openapi/util/text/StringHash.java | 38 +++++++++++++++ .../intellij/util/lang/ClasspathCache.java | 46 ++----------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/text/StringHash.java b/platform/util/src/com/intellij/openapi/util/text/StringHash.java index 404a935616b5..e20c15f08a92 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringHash.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringHash.java @@ -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; + } } diff --git a/platform/util/src/com/intellij/util/lang/ClasspathCache.java b/platform/util/src/com/intellij/util/lang/ClasspathCache.java index 8b13a3f35a55..658cda05f986 100644 --- a/platform/util/src/com/intellij/util/lang/ClasspathCache.java +++ b/platform/util/src/com/intellij/util/lang/ClasspathCache.java @@ -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 { From 8a4916c1e91ac96ec53deea6fb3b753ce5ae6a2a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:51:02 +0100 Subject: [PATCH 36/46] decouple core file template logic from StdFileTypes.JAVA --- .../JavaCreateFromTemplateHandler.java | 21 +++++++++++++++++++ .../CreateFromTemplateHandler.java | 4 ++++ .../DefaultCreateFromTemplateHandler.java | 16 ++++++++++++++ .../ide/fileTemplates/FileTemplateUtil.java | 12 +++-------- .../ui/CreateFromTemplateDialog.java | 5 ++--- 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java b/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java index 56556548f0e4..7507f9dfd68b 100644 --- a/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java +++ b/java/java-impl/src/com/intellij/ide/fileTemplates/JavaCreateFromTemplateHandler.java @@ -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; } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java index 2caae4e51a95..0eb494ca6d3e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/CreateFromTemplateHandler.java @@ -35,4 +35,8 @@ public interface CreateFromTemplateHandler { Properties props) throws IncorrectOperationException; boolean canCreate(final PsiDirectory[] dirs); + boolean isNameRequired(); + String getErrorMessage(); + + Properties prepareProperties(Properties props); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java index 91bfa6dda7b9..bf61fb7d5c3a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/DefaultCreateFromTemplateHandler.java @@ -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; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index eab211ad86d0..d23ba3acea8f 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -279,13 +279,8 @@ 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); - } - } + final CreateFromTemplateHandler handler = findHandler(template); + props = handler.prepareProperties(props); final Properties props_ = props; String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(), @@ -304,7 +299,6 @@ 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); } catch (Exception ex){ @@ -322,7 +316,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; diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index aaa153d3161e..a73db7bcf071 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -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,7 +64,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties; FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory); - boolean mustEnterName = !myTemplate.isTemplateOfType(StdFileTypes.JAVA); + boolean mustEnterName = FileTemplateUtil.findHandler(template).isNameRequired(); if (attributesDefaults != null && attributesDefaults.isFixedName()) { myDefaultProperties.setProperty(FileTemplate.ATTRIBUTE_NAME, attributesDefaults.getDefaultFileName()); mustEnterName = false; @@ -134,7 +133,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { } 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 From 9cd1c49cb2b7cdfaa251f0cd34aaab28ad5123e7 Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Fri, 10 Feb 2012 21:46:35 +0400 Subject: [PATCH 37/46] Guarantee that different maven importers won't require different module types for one maven project --- .../idea/maven/importing/MavenImporter.java | 35 ++++++++++++++++--- .../idea/maven/project/MavenProject.java | 17 ++------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java index b46464c7fd95..843f8d2caa97 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java @@ -20,7 +20,10 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,10 +34,7 @@ import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; import org.jetbrains.idea.maven.utils.MavenJDOMUtil; import org.jetbrains.idea.maven.utils.MavenProcessCanceledException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; public abstract class MavenImporter { public static ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("org.jetbrains.idea.maven.importer"); @@ -48,12 +48,37 @@ public abstract class MavenImporter { public static List getSuitableImporters(MavenProject p) { final List result = new ArrayList(); + final Set moduleTypes = new THashSet(); for (MavenImporter importer : EXTENSION_POINT_NAME.getExtensions()) { if (importer.isApplicable(p)) { result.add(importer); + moduleTypes.add(importer.getModuleType()); } } - return result; + + if (moduleTypes.size() <= 1) { + return result; + } + + // This code is reached when several importers say that they are applicable but they want to have different module types. + // Now we select one module type and return only those importers that are ok with it. + // If possible - return at least one importer that explicitly supports packaging of the given maven project. + ModuleType moduleType = result.get(0).getModuleType(); + for (MavenImporter importer : result) { + final List supportedPackagings = new ArrayList(); + importer.getSupportedPackagings(supportedPackagings); + if (supportedPackagings.contains(p.getPackaging())) { + moduleType = importer.getModuleType(); + break; + } + } + + final ModuleType finalModuleType = moduleType; + return ContainerUtil.filter(result, new Condition() { + public boolean value(final MavenImporter importer) { + return importer.getModuleType() == finalModuleType; + } + }); } public boolean isApplicable(MavenProject mavenProject) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 6503756ea1c7..015bd7f96012 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -802,20 +802,9 @@ public class MavenProject { @NotNull public ModuleType getModuleType() { - MavenImporter mavenImporter = null; - ModuleType typeFromImporter = null; - - for (MavenImporter each : getSuitableImporters()) { - final ModuleType moduleType = each.getModuleType(); - if (typeFromImporter != null && !typeFromImporter.equals(moduleType)) { - MavenLog.LOG.error("Incompatible plugins: " + each.getClass().getName() + " wants to create " + - moduleType.getName() + " for project " + getName() + - " whereas " + mavenImporter.getClass().getName() + " requires " + typeFromImporter.getName()); - } - mavenImporter = each; - typeFromImporter = moduleType; - } - return typeFromImporter != null ? typeFromImporter : StdModuleTypes.JAVA; + final List importers = getSuitableImporters(); + // getSuitableImporters() guarantees that all returned importers require the same module type + return importers.size() > 0 ? importers.get(0).getModuleType() : StdModuleTypes.JAVA; } @NotNull From 70a933619c6958bc2cb701bcada5fdeac16d93a9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 10 Feb 2012 18:55:22 +0100 Subject: [PATCH 38/46] take name from properties if not specified as explicit parameter --- .../ide/fileTemplates/FileTemplateUtil.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index d23ba3acea8f..0d0ec3f10408 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -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,10 +286,10 @@ public class FileTemplateUtil{ props.setProperty(dummyRef, ""); } - final CreateFromTemplateHandler handler = findHandler(template); props = handler.prepareProperties(props); final Properties props_ = props; + final String fileName_ = fileName; String mergedText = ClassLoaderUtil.runWithClassLoader(classLoader != null ? classLoader : FileTemplateUtil.class.getClassLoader(), new ThrowableComputable() { @Override @@ -299,7 +306,7 @@ public class FileTemplateUtil{ ApplicationManager.getApplication().runWriteAction(new Runnable(){ public void run(){ try{ - 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; From c25e5f4ce6878615f6f1fcc473f4e3b54718cf7b Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 10 Feb 2012 19:43:54 +0100 Subject: [PATCH 39/46] show doc for correct parameter (IDEA-81184) --- .../hint/ParameterInfoComponent.java | 4 +++ .../hint/ParameterInfoController.java | 25 ++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java index 59f6ca91c914..dbc7dc81c0a4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java @@ -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, diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java index 9bf5c61e90cb..31401edbb0ed 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java @@ -113,20 +113,33 @@ public class ParameterInfoController { int selectedParameterIndex = myComponent.getCurrentParameterIndex(); List params = new ArrayList(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 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 getAllControllers(Editor editor) { ArrayList array = editor.getUserData(ALL_CONTROLLERS_KEY); if (array == null){ From b21b9d1d3fa71f9fe08f6f37bae8610ff5f40222 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Fri, 10 Feb 2012 23:01:53 +0400 Subject: [PATCH 40/46] Work on ComponentTree --- .../designer/AndroidDesignerEditor.java | 9 ++ .../componentTree/AndroidTreeDecorator.java | 32 +++++++ .../AndroidDesignerEditorPanel.java | 79 ++++++++++++++++++ .../designer/model/RadViewComponent.java | 48 +++++++++++ .../com/intellij/designer/DesignerEditor.java | 4 +- .../designer/DesignerToolWindowManager.java | 17 ++++ .../designer/componentTree/ComponentTree.java | 59 ++++++++++++- .../componentTree/ComponentTreeBuilder.java | 36 ++++++++ .../componentTree/TreeComponentDecorator.java | 26 ++++++ .../componentTree/TreeContentProvider.java | 83 +++++++++++++++++++ .../componentTree/TreeNodeDescriptor.java | 42 ++++++++++ .../designSurface/DesignerEditorPanel.java | 13 ++- .../intellij/designer/model/RadComponent.java | 19 ++++- 13 files changed, 462 insertions(+), 5 deletions(-) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java create mode 100644 plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java create mode 100644 plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java create mode 100644 plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java create mode 100644 plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java create mode 100644 plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java create mode 100644 plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java diff --git a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java index c9010998e262..10495dcd338d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java +++ b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerEditor.java @@ -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() { diff --git a/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java new file mode 100644 index 000000000000..adfb60d15977 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java @@ -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()); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java new file mode 100644 index 000000000000..07e1434d8dd0 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -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; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java new file mode 100644 index 000000000000..e0226f6c0320 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -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 myChildren = new ArrayList(); + + public RadViewComponent(RadViewComponent parent, String title) { + myTitle = title; + setParent(parent); + if (parent != null) { + parent.getChildren().add(this); + } + } + + @Override + public List getChildren() { + return myChildren; + } + + public String getTitle() { + return myTitle; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java index a6142f90d025..c245d1ae760f 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerEditor.java @@ -45,9 +45,11 @@ public abstract class DesignerEditor extends UserDataHolderBase implements FileE if (module == null) { throw new IllegalArgumentException("No module for file " + file + " in project " + project); } - myDesignerPanel = new DesignerEditorPanel(module, file); + myDesignerPanel = createDesignerPanel(module, file); } + protected abstract DesignerEditorPanel createDesignerPanel(Module module, VirtualFile file); + public final DesignerEditorPanel getDesignerPanel() { return myDesignerPanel; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java index d3f218f925f0..2c709447b264 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerToolWindowManager.java @@ -16,8 +16,10 @@ package com.intellij.designer; import com.intellij.designer.componentTree.ComponentTree; +import com.intellij.designer.componentTree.ComponentTreeBuilder; import com.intellij.designer.designSurface.DesignerEditorPanel; import com.intellij.designer.propertyTable.PropertyTablePanel; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -26,6 +28,7 @@ import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.Splitter; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; @@ -53,6 +56,7 @@ public final class DesignerToolWindowManager implements ProjectComponent { private final FileEditorManager myFileEditorManager; private ToolWindow myToolWindow; private ComponentTree myComponentTree; + private AbstractTreeBuilder myTreeBuilder; private PropertyTablePanel myPropertyTablePanel; private boolean myToolWindowReady; private boolean myToolWindowDisposed; @@ -91,12 +95,20 @@ public final class DesignerToolWindowManager implements ProjectComponent { public void projectClosed() { if (!myToolWindowDisposed) { myToolWindowDisposed = true; + clearTreeBuilder(); myComponentTree = null; myPropertyTablePanel = null; myToolWindow = null; } } + private void clearTreeBuilder() { + if (myTreeBuilder != null) { + Disposer.dispose(myTreeBuilder); + myTreeBuilder = null; + } + } + public static DesignerToolWindowManager getInstance(Project project) { return project.getComponent(DesignerToolWindowManager.class); } @@ -128,10 +140,15 @@ public final class DesignerToolWindowManager implements ProjectComponent { } initToolWindow(); } + clearTreeBuilder(); + myComponentTree.newModel(); if (designer == null) { + myComponentTree.setDecorator(null); myToolWindow.setAvailable(false, null); } else { + myComponentTree.setDecorator(designer.getTreeDecorator()); + myTreeBuilder = new ComponentTreeBuilder(myComponentTree, designer); myToolWindow.setAvailable(true, null); myToolWindow.show(null); } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java index d49a48b92079..742dc769f312 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java @@ -15,10 +15,15 @@ */ package com.intellij.designer.componentTree; +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.model.RadComponent; import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; +import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -26,12 +31,62 @@ import javax.swing.tree.DefaultTreeModel; * @author Alexander Lobas */ public final class ComponentTree extends Tree implements DataProvider { + private TreeComponentDecorator myDecorator; + public ComponentTree() { - super(new DefaultTreeModel(new DefaultMutableTreeNode())); + newModel(); + + installCellRenderer(); + + setRootVisible(false); + setShowsRootHandles(true); + + // Enable tooltips + ToolTipManager.sharedInstance().registerComponent(this); + + // Install convenient keyboard navigation + TreeUtil.installActions(this); + + // TODO: Popup menu + + // TODO: F2 should start inplace editing + + // TODO: DND + } + + public void newModel() { + setModel(new DefaultTreeModel(new DefaultMutableTreeNode())); + } + + public void setDecorator(TreeComponentDecorator decorator) { + myDecorator = decorator; } @Override public Object getData(@NonNls String dataId) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; //TODO + } + + private void installCellRenderer() { + setCellRenderer(new ColoredTreeCellRenderer() { + @Override + public void customizeCellRenderer(JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; + if (myDecorator != null && node.getUserObject() instanceof TreeNodeDescriptor) { + TreeNodeDescriptor descriptor = (TreeNodeDescriptor)node.getUserObject(); + if (descriptor.getElement() instanceof RadComponent) { + RadComponent component = (RadComponent)descriptor.getElement(); + // TODO: support more parameters and attributes + myDecorator.decorate(component, this); + } + } + } + }); } } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java new file mode 100644 index 000000000000..300ec7d98fe2 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.componentTree; + +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; +import com.intellij.ide.util.treeView.AbstractTreeStructure; +import com.intellij.ide.util.treeView.NodeDescriptor; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultTreeModel; +import java.util.Comparator; + +/** + * @author Alexander Lobas + */ +public final class ComponentTreeBuilder extends AbstractTreeBuilder { + public ComponentTreeBuilder(ComponentTree tree, DesignerEditorPanel designer) { + super(tree, (DefaultTreeModel)tree.getModel(), new TreeContentProvider(designer), null); // TODO: comparator? + initRootNode(); + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java new file mode 100644 index 000000000000..243cd6b0ed59 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeComponentDecorator.java @@ -0,0 +1,26 @@ +/* + * 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.designer.componentTree; + +import com.intellij.designer.model.RadComponent; +import com.intellij.ui.ColoredTreeCellRenderer; + +/** + * @author Alexander Lobas + */ +public abstract class TreeComponentDecorator { + public abstract void decorate(RadComponent component, ColoredTreeCellRenderer renderer); // TODO: more parameters and attributes +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java new file mode 100644 index 000000000000..0c30ca3c7b3e --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeContentProvider.java @@ -0,0 +1,83 @@ +/* + * 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.designer.componentTree; + +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.model.RadComponent; +import com.intellij.ide.util.treeView.AbstractTreeStructure; +import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author Alexander Lobas + */ +public final class TreeContentProvider extends AbstractTreeStructure { + private final DesignerEditorPanel myDesigner; + private final Object myTreeRoot = new Object(); + + public TreeContentProvider(DesignerEditorPanel designer) { + myDesigner = designer; + } + + @Override + public Object getRootElement() { + return myTreeRoot; + } + + @Override + public Object[] getChildElements(Object element) { + if (element == myTreeRoot) { + return myDesigner.getTreeRoots(); + } + else if (element instanceof RadComponent) { + RadComponent component = (RadComponent)element; + return component.getTreeChildren(); + } + else { + throw new IllegalArgumentException("Unknown element: " + element); + } + } + + @Override + public Object getParentElement(Object element) { + if (element instanceof RadComponent) { + RadComponent component = (RadComponent)element; + return component.getParent(); + } + return null; + } + + @NotNull + @Override + public NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) { + if (element == myTreeRoot || element instanceof RadComponent) { + return new TreeNodeDescriptor(parentDescriptor, element); + } + else { + throw new IllegalArgumentException("Unknown element: " + element); + } + } + + @Override + public boolean hasSomethingToCommit() { + return false; + } + + @Override + public void commit() { + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java new file mode 100644 index 000000000000..aea7d02606fc --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java @@ -0,0 +1,42 @@ +/* + * 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.designer.componentTree; + +import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; + +/** + * @author Alexander Lobas + */ +public final class TreeNodeDescriptor extends NodeDescriptor { + private final Object myElement; + + public TreeNodeDescriptor(@Nullable NodeDescriptor parentDescriptor, Object element) { + super(null, parentDescriptor); + myElement = element; + } + + @Override + public boolean update() { + return false; + } + + @Override + public Object getElement() { + return myElement; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java index ce2b88de7e52..1e7953eeae7d 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java @@ -15,9 +15,12 @@ */ package com.intellij.designer.designSurface; +import com.intellij.designer.componentTree.TreeComponentDecorator; +import com.intellij.designer.model.RadComponent; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.module.Module; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -27,7 +30,9 @@ import java.awt.*; /** * @author Alexander Lobas */ -public final class DesignerEditorPanel extends JPanel implements DataProvider { +public abstract class DesignerEditorPanel extends JPanel implements DataProvider { + protected RadComponent myRootComponent; + public DesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) { setLayout(new BorderLayout()); add(new JLabel("Design Surface", JLabel.CENTER), BorderLayout.CENTER); @@ -45,4 +50,10 @@ public final class DesignerEditorPanel extends JPanel implements DataProvider { public JComponent getPreferredFocusedComponent() { return null; // TODO: Auto-generated method stub } + + public Object[] getTreeRoots() { + return myRootComponent == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[]{myRootComponent}; + } + + public abstract TreeComponentDecorator getTreeDecorator(); } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java index 65488fd1e5a2..e208e5817728 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java @@ -16,14 +16,19 @@ package com.intellij.designer.model; import com.intellij.designer.propertyTable.Property; +import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.List; +import java.util.Map; /** * @author Alexander Lobas */ public abstract class RadComponent { private RadComponent myParent; + private final Map myClientProperties = new HashMap(); public RadComponent getRoot() { return myParent == null ? this : myParent.getRoot(); @@ -38,10 +43,22 @@ public abstract class RadComponent { } public List getChildren() { - return null; + return Collections.emptyList(); + } + + public Object[] getTreeChildren() { + return getChildren().toArray(); } public List getProperties() { return null; } + + public final Object getClientProperty(@NotNull Object key) { + return myClientProperties.get(key); + } + + public final void putClientProperty(@NotNull Object key, Object value) { + myClientProperties.put(key, value); + } } \ No newline at end of file From 106739bed1e052cef946ac1801eff308d28d13d6 Mon Sep 17 00:00:00 2001 From: Serge Baranov Date: Fri, 10 Feb 2012 23:57:11 +0400 Subject: [PATCH 41/46] Proper fix for IDEA-78076 --- .../platform-resources-en/src/messages/IdeBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index f985fba72fd6..77fc75407f13 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -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} From 80ca8dc18c40ab90cacdc6392e01fbe7d4b92626 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 19:26:53 +0100 Subject: [PATCH 42/46] some logging --- .../vcs/changes/VcsDirtyScopeManagerImpl.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java index 3fa1acb67898..decb13a4393a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java @@ -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() { 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() { 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() { 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() { 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() { 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() { public void consume(DirtBuilder dirtBuilder) { From a434a2807e48c551afd64ab887988de46a6355f9 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Fri, 10 Feb 2012 21:08:25 +0100 Subject: [PATCH 43/46] quick fix toolwindow activation --- .../src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index c5f32e12a57f..3cba80b1fe26 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -719,7 +719,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements final ArrayList commandList, boolean forced, boolean autoFocusContents) { - if (/*!getFocusManagerImpl(myProject).isUnforcedRequestAllowed() && */!forced) return; + if (!FocusManagerImpl.getInstance().isUnforcedRequestAllowed() && !forced) return; if (LOG.isDebugEnabled()) { LOG.debug("enter: activateToolWindowImpl(" + id + ")"); From e7285155992f64f524937691d08f83f14801bff4 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 10 Feb 2012 21:09:08 +0100 Subject: [PATCH 44/46] expire sticky balloons when hidden --- .../intellij/notification/impl/NotificationsManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java index f4475fd7937d..7af1d81950b4 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java @@ -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 { From e90b093156199a9ee7fb44e668cc63777a347520 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Sat, 11 Feb 2012 01:00:41 +0400 Subject: [PATCH 45/46] Overriden methods supported in a conservative manner (compile server). --- .../deleteMethodImplementation4.log | 2 + .../deleteMethodImplementation5.log | 6 ++ .../deleteMethodImplementation6.log | 6 ++ .../org/jetbrains/ether/GenericTest.java | 6 +- .../jetbrains/ether/IncrementalTestCase.java | 2 +- .../org/jetbrains/ether/MemberChangeTest.java | 2 - .../ether/dependencyView/Mappings.java | 78 ++++++++++--------- 7 files changed, 60 insertions(+), 42 deletions(-) diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log index 30038ec68e16..db72b0f2704d 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation4.log @@ -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 diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log index c8a95e08349b..a36940f74f64 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation5.log @@ -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 diff --git a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log index 0548319f9020..e4bd38375b69 100644 --- a/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log +++ b/java/java-tests/testData/compileServer/incremental/membersChange/deleteMethodImplementation6.log @@ -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 diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java index facc69d594e6..5fded763c906 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/GenericTest.java @@ -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(); diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java index 48ed13b9920e..6160a0126ced 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java @@ -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); diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java b/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java index 7fbcc9becf45..cfe091f05825 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/MemberChangeTest.java @@ -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(); diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index d5d3bd1957c0..cc586037d2b9 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -1103,47 +1103,55 @@ public class Mappings { } if ((m.access & Opcodes.ACC_ABSTRACT) == 0) { + final Collection> overriding = u.findOverridingMethods(m, it, false); + + for (final Pair 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> overridenInS = u.findOverridenMethods(m, s); + if (s != null) { + final Collection> 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 pp : overridenInS) { - final ClassRepr cc = pp.second; + for (Pair 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 classes = delta.mySourceFileToClasses.get(f); - if (classes != null){ + if (classes != null) { mySourceFileToClasses.put(f, classes); } mySourceFileToUsages.remove(f); final Collection clusters = delta.mySourceFileToUsages.get(f); - if (clusters != null){ + if (clusters != null) { mySourceFileToUsages.put(f, clusters); } mySourceFileToAnnotationUsages.remove(f); final Collection 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; } } From 95bc62e2358d84198befec020b50684f9b8f02c4 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Sat, 11 Feb 2012 01:01:57 +0400 Subject: [PATCH 46/46] Overriden methods supported in a conservative manner (compile server). --- .../generics/overrideAnnotatedAnonymousNotRecompile.log | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log b/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log index 4be3d1f3669d..33badcc6d70d 100644 --- a/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log +++ b/java/java-tests/testData/compileServer/incremental/generics/overrideAnnotatedAnonymousNotRecompile.log @@ -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