diff --git a/.idea/modules.xml b/.idea/modules.xml index 82283e971251..d94269431fdf 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -11,6 +11,7 @@ + diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index cd56346c2752..d1f251c179c3 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -172,6 +172,9 @@ def layoutFull(String home, String targetDirectory) { layoutPlugin("SpellChecker", "spellchecker", "spellchecker-core") + layoutPlugin("RelaxNG-Support", "relaxng") { + fileset(dir: "${home}/community/plugins/relaxng/lib", includes: "**/*.jar") + } layoutPlugin("maven") { jar("maven-facade-api.jar") { 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 6f6208583b93..b1f30cf4e2e5 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -97,6 +97,8 @@ import java.util.concurrent.TimeUnit; public class CompileDriver { private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompileDriver"); + // to be used in tests only for debug output + public static boolean ourDebugMode = false; private final Project myProject; private final Map, Pair> myGenerationCompilerModuleToOutputDirMap; // [IntermediateOutputCompiler, Module] -> [ProductionSources, TestSources] @@ -1558,12 +1560,20 @@ public class CompileDriver { if (toDelete.isEmpty() && toCompile.isEmpty()) { return false; } - if (LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled() || ourDebugMode) { if (!toDelete.isEmpty()) { - LOG.debug("Found items to delete, compiler " + compiler.getDescription()); + final String message = "Found items to delete, compiler " + compiler.getDescription(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } if (!toCompile.isEmpty()) { - LOG.debug("Found items to compile, compiler " + compiler.getDescription()); + final String message = "Found items to compile, compiler " + compiler.getDescription(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } } throw new ExitException(ExitStatus.CANCELLED); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java index f8d1381f2188..76de9729c7e7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/TranslatingCompilerFilesMonitor.java @@ -78,6 +78,7 @@ import java.util.*; public class TranslatingCompilerFilesMonitor implements ApplicationComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.TranslatingCompilerFilesMonitor"); + public static boolean ourDebugMode = false; @NonNls private static final String PATHS_TO_DELETE_FILENAME = "paths_to_delete.dat"; private static final String OUTPUT_ROOTS_FILENAME = "output_roots.dat"; @@ -163,8 +164,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { while (scopeSrcIterator.hasNext()) { final VirtualFile file = scopeSrcIterator.next(); if (!file.isValid()) { - if (LOG.isDebugEnabled()) { - LOG.debug("Skipping invalid file " + file.getPresentableUrl()); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "Skipping invalid file " + file.getPresentableUrl(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } continue; } @@ -212,11 +217,22 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { //noinspection UnnecessaryBoxing final File file = new File(outputPath); toDelete.add(new Trinity(file, classNamePair.getClassName(), Boolean.valueOf(sourcePresent))); - if (LOG.isDebugEnabled()) { - LOG.debug("Found file to delete: " + file); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "Found file to delete: " + file; + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } } else { + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "Found zombie entry marked for deletion: " + outputPath; + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } + } // must be gagbage entry, should cleanup zombieEntries.add(outputPath); } @@ -301,8 +317,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final long fileStamp = file.getTimeStamp(); info.updateTimestamp(projectId, fileStamp); saveSourceInfo(file, info); - if (LOG.isDebugEnabled()) { - LOG.debug("Unschedule recompilation (successfully compiled) " + file.getPresentableUrl()); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "Unschedule recompilation (successfully compiled) " + file.getPresentableUrl(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } removeSourceForRecompilation(projectId, Math.abs(getFileId(file))); if ((fileStamp > compilationStartStamp && !((CompileContextEx)context).isGenerated(file)) || forceRecompile.contains(file)) { @@ -365,8 +385,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { final String outputPath = FileUtil.toSystemIndependentName(CompilerIOUtil.readString(is)); final String srcUrl = CompilerIOUtil.readString(is); final String className = CompilerIOUtil.readString(is); - if (LOG.isDebugEnabled()) { - LOG.debug("INIT path to delete: " + outputPath); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "INIT path to delete: " + outputPath; + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } map.put(outputPath, new SourceUrlClassNamePair(srcUrl, className)); } @@ -1136,8 +1160,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { public void beforeFileDeletion(final VirtualFileEvent event) { final VirtualFile eventFile = event.getFile(); - if (LOG.isDebugEnabled() && eventFile.isDirectory()) { - LOG.debug("Processing file deletion: " + eventFile.getPresentableUrl()); + if ((LOG.isDebugEnabled() && eventFile.isDirectory()) || ourDebugMode) { + final String message = "Processing file deletion: " + eventFile.getPresentableUrl(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } processRecursively(eventFile, true, new FileProcessor() { public void execute(final VirtualFile file) { @@ -1167,8 +1195,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { for (int projectId : projects.toArray()) { // mark associated outputs for deletion srcInfo.processOutputPaths(projectId, deletionProc); - if (LOG.isDebugEnabled()) { - LOG.debug("Unschedule recompilation because of deletion " + file.getPresentableUrl()); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "Unschedule recompilation because of deletion " + file.getPresentableUrl(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } removeSourceForRecompilation(projectId, Math.abs(getFileId(file))); } @@ -1269,8 +1301,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { mySourcesToRecompile.put(projectId, set); } alreadyMarked = !set.add(Math.abs(getFileId(srcFile))); - if (!alreadyMarked && LOG.isDebugEnabled()) { - LOG.debug("Scheduled recompilation " + srcFile.getPresentableUrl()); + if (!alreadyMarked && (LOG.isDebugEnabled() || ourDebugMode)) { + final String message = "Scheduled recompilation " + srcFile.getPresentableUrl(); + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } } @@ -1336,8 +1372,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { myOutputsToDelete.put(projectId, map); } map.put(outputPath, new SourceUrlClassNamePair(srcUrl, classname)); - if (LOG.isDebugEnabled()) { - LOG.debug("ADD path to delete: " + outputPath + "; source: " + srcUrl); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "ADD path to delete: " + outputPath + "; source: " + srcUrl; + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } } } @@ -1349,8 +1389,12 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent { if (map != null) { final SourceUrlClassNamePair val = map.remove(outputPath); if (val != null) { - if (LOG.isDebugEnabled()) { - LOG.debug("REMOVE path to delete: " + outputPath); + if (LOG.isDebugEnabled() || ourDebugMode) { + final String message = "REMOVE path to delete: " + outputPath; + LOG.debug(message); + if (ourDebugMode) { + System.out.println(message); + } } if (map.isEmpty()) { myOutputsToDelete.remove(projectId); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index d5a4858d5c2b..1ec3ceb5e20d 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -1081,7 +1081,11 @@ public class ExtractMethodProcessor implements MatchProvider { } if (success) { myTargetClass = newTargetClass; - inputVariables.addAll(array); + for (PsiVariable variable : array) { + if (!inputVariables.contains(variable)) { + inputVariables.addAll(array); + } + } myNeedChangeContext = true; } } diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java index 5f10465e8a32..b9d681d4b408 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java @@ -18,6 +18,7 @@ package com.intellij.refactoring.inline; import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.lang.StdLanguages; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.patterns.ElementPattern; @@ -34,6 +35,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; /** @@ -50,17 +52,29 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler { return element instanceof PsiMethod || element instanceof PsiClass; } - public boolean canInlineElement(PsiElement element) { + public boolean canInlineElement(final PsiElement element) { if (element.getLanguage() != StdLanguages.JAVA) return false; if (element instanceof PsiMethod) { PsiMethod method = (PsiMethod)element; if (method.isConstructor() && !InlineMethodHandler.isChainingConstructor(method)) { final PsiClass containingClass = method.getContainingClass(); - return containingClass != null && ClassInheritorsSearch.search(containingClass).findAll().size() == 0; + if (containingClass == null) return false; + return findClassInheritors(containingClass); } } if (!(element instanceof PsiClass)) return false; - Collection inheritors = ClassInheritorsSearch.search((PsiClass)element).findAll(); + if (element instanceof PsiAnonymousClass) return false; + return findClassInheritors((PsiClass)element); + } + + private static boolean findClassInheritors(final PsiClass element) { + final Collection inheritors = new ArrayList(); + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable(){ + @Override + public void run() { + inheritors.addAll(ClassInheritorsSearch.search(element).findAll()); + } + }, "Searching for class \"" + element.getQualifiedName() + "\" inheritors ...", true, element.getProject())) return false; return inheritors.size() == 0; } @@ -78,9 +92,15 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler { return; } - String errorMessage = getCannotInlineMessage(psiClass); - if (errorMessage != null) { - CommonRefactoringUtil.showErrorHint(project, editor, errorMessage, RefactoringBundle.message("inline.to.anonymous.refactoring"), null); + final Ref errorMessage = new Ref(); + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable(){ + @Override + public void run() { + errorMessage.set(getCannotInlineMessage(psiClass)); + } + }, "Check if inline is possible...", true, project)) return; + if (errorMessage.get() != null) { + CommonRefactoringUtil.showErrorHint(project, editor, errorMessage.get(), RefactoringBundle.message("inline.to.anonymous.refactoring"), null); return; } diff --git a/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java b/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java index 55e137a4d9b9..bd2e176dd899 100644 --- a/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/memberPullUp/JavaPullUpHandler.java @@ -29,6 +29,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.psi.*; @@ -142,11 +143,17 @@ public class JavaPullUpHandler implements RefactoringActionHandler, PullUpDialog - public boolean checkConflicts(PullUpDialog dialog) { + public boolean checkConflicts(final PullUpDialog dialog) { final MemberInfo[] infos = dialog.getSelectedMemberInfos(); - PsiClass superClass = dialog.getSuperClass(); + final PsiClass superClass = dialog.getSuperClass(); if (!checkWritable(superClass, infos)) return false; - MultiMap conflicts = PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, null, null, dialog.getContainmentVerifier()); + final MultiMap conflicts = new MultiMap(); + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + public void run() { + conflicts + .putAllValues(PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, null, null, dialog.getContainmentVerifier())); + } + }, "Detecting possible conflicts...", true, myProject)) return false; if (!conflicts.isEmpty()) { ConflictsDialog conflictsDialog = new ConflictsDialog(myProject, conflicts); conflictsDialog.show(); diff --git a/java/java-tests/testData/refactoring/extractMethod/ParametersFromAnonymous.java b/java/java-tests/testData/refactoring/extractMethod/ParametersFromAnonymous.java new file mode 100644 index 000000000000..fc9dc3af5e2d --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ParametersFromAnonymous.java @@ -0,0 +1,12 @@ +class Test { + void f() { + new Runnable() { + public void run() { + int j = 0; + if (j == 0 && j < 0 && j > 0) { + assert false; + } + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/ParametersFromAnonymous_after.java b/java/java-tests/testData/refactoring/extractMethod/ParametersFromAnonymous_after.java new file mode 100644 index 000000000000..8768dbc565af --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ParametersFromAnonymous_after.java @@ -0,0 +1,16 @@ +class Test { + void f() { + new Runnable() { + public void run() { + int j = 0; + if (j == 0 && newMethod(j)) { + assert false; + } + } + }; + } + + private boolean newMethod(int j) { + return j < 0 && j > 0; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 873f5b27ffd3..c1dfde6cee68 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -9,10 +9,13 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiType; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.refactoring.extractMethod.ExtractMethodProcessor; import com.intellij.refactoring.extractMethod.PrepareFailedException; +import com.intellij.refactoring.introduceVariable.IntroduceVariableBase; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.duplicates.Match; import com.intellij.testFramework.LightCodeInsightTestCase; import com.intellij.util.IncorrectOperationException; @@ -448,6 +451,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doDuplicatesTest(); } + public void testParametersFromAnonymous() throws Exception { + doTest(); + } + private void doPrepareErrorTest(final String expectedMessage) throws Exception { String expectedError = null; try { @@ -503,6 +510,12 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { else { elements = CodeInsightUtil.findStatementsInRange(file, startOffset, endOffset); } + if (elements.length == 0) { + final PsiExpression expression = IntroduceVariableBase.getSelectedExpression(project, file, startOffset, endOffset); + if (expression != null) { + elements = new PsiElement[]{expression}; + } + } assertTrue(elements.length > 0); final ExtractMethodProcessor processor = diff --git a/platform/lang-api/src/com/intellij/ui/FileColorManager.java b/platform/lang-api/src/com/intellij/ui/FileColorManager.java index ed1cffff61da..3a770e21f712 100644 --- a/platform/lang-api/src/com/intellij/ui/FileColorManager.java +++ b/platform/lang-api/src/com/intellij/ui/FileColorManager.java @@ -30,6 +30,7 @@ import java.util.Collection; * @author spleaner */ public abstract class FileColorManager { + public static final String OUT_OF_PROJECT_SCOPE_COLOR = "OUT_OF_PROJECT_SCOPE"; public static FileColorManager getInstance(@NotNull final Project project) { return ServiceManager.getService(project, FileColorManager.class); @@ -41,6 +42,8 @@ public abstract class FileColorManager { public abstract boolean isEnabledForTabs(); + public abstract boolean isHighlightNonProjectFiles(); + @SuppressWarnings({"MethodMayBeStatic"}) @Nullable public abstract Color getColor(@NotNull String name); diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java index a32c0f2e0b61..bbc986621b1e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/CodeFoldingConfigurable.java @@ -23,14 +23,17 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; +import com.intellij.openapi.editor.impl.FoldingModelImpl; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.CompositeConfigurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.Nls; import javax.swing.*; import java.awt.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -57,8 +60,9 @@ public class CodeFoldingConfigurable extends CompositeConfigurable> toUpdate = new ArrayList>(); for (final Editor editor : EditorFactory.getInstance().getAllEditors()) { final Project project = editor.getProject(); if (project != null && !project.isDefault()) { - final CodeFoldingManager foldingManager = CodeFoldingManager.getInstance(project); - if (foldingManager != null) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - foldingManager.forceDefaultState(editor); - } - }, ModalityState.NON_MODAL); - } + toUpdate.add(Pair.create(editor, project)); } } + + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + for (Pair each : toUpdate) { + final CodeFoldingManager foldingManager = CodeFoldingManager.getInstance(each.second); + if (foldingManager != null) { + foldingManager.buildInitialFoldings(each.first); + } + } + EditorOptionsPanel.reinitAllEditors(); + } + }, ModalityState.NON_MODAL); } public void reset() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java index 183425fdfed2..4ad566e6502a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java @@ -87,7 +87,7 @@ public class UpdateHighlightersUtil { List infosToRemove = new ArrayList(); for (HighlightInfo info : infos) { if (info.group == group) { - manager.removeEditorAnnotation(fileEditor, info.fileLevelComponent); + manager.removeTopComponent(fileEditor, info.fileLevelComponent); infosToRemove.add(info); } } @@ -340,7 +340,7 @@ public class UpdateHighlightersUtil { if (fileEditor instanceof TextEditor) { FileLevelIntentionComponent component = new FileLevelIntentionComponent(info.description, info.severity, info.quickFixActionRanges, project, psiFile, ((TextEditor)fileEditor).getEditor()); - manager.showEditorAnnotation(fileEditor, component); + manager.addTopComponent(fileEditor, component); List fileLevelInfos = fileEditor.getUserData(FILE_LEVEL_HIGHLIGHTS); if (fileLevelInfos == null) { fileLevelInfos = new ArrayList(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java index 6b836f9d2166..38813695f507 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/FileLevelIntentionComponent.java @@ -49,7 +49,6 @@ public class FileLevelIntentionComponent extends EditorNotificationPanel { final HighlightSeverity severity, final List> intentions, final Project project, final PsiFile psiFile, final Editor editor) { - super(); myProject = project; final ShowIntentionsPass.IntentionsInfo info = new ShowIntentionsPass.IntentionsInfo(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java index 9a1148fdbe8c..40a6b22d5053 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java @@ -155,4 +155,8 @@ public class CustomTemplateCallback { } return element; } + + public boolean isInInjectedFragment() { + return myInInjectedFragment; + } } diff --git a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java index 2afdc436b3b7..174de671f389 100644 --- a/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java +++ b/platform/lang-impl/src/com/intellij/execution/ExecutionHelper.java @@ -150,7 +150,7 @@ public class ExecutionHelper { public static class RailsErrorViewPanel extends NewErrorTreeViewPanel { public RailsErrorViewPanel(final Project project) { - super(project, null); + super(project, "reference.toolWindows.messages"); } protected boolean canHideWarnings() { @@ -270,54 +270,27 @@ public class ExecutionHelper { final int timeout) { return new Runnable() { private final Semaphore mySemaphore = new Semaphore(); - private final Object LOCK = new Object(); - private Boolean processedFinished = Boolean.FALSE; private final Runnable myProcessThread = new Runnable() { public void run() { try { - processHandler.waitFor(); - synchronized (LOCK) { - processedFinished = Boolean.TRUE; + final boolean finished = processHandler.waitFor(1000 * timeout); + if (!finished) { + LOG.error("Timeout (" + timeout + " sec) on executing: " + processHandler.getCommandLine()); + processHandler.destroyProcess(); } - } - finally { + } finally { mySemaphore.up(); } } }; - private final Runnable myTimeoutListener = new Runnable() { - public void run() { - try { - synchronized (this) { - try { - wait(1000 * timeout); - synchronized (LOCK) { - if (!processedFinished) { - LOG.error("Timeout (" + timeout + " sec) on executing: " + processHandler.getCommandLine()); - processHandler.destroyProcess(); - } - } - } - finally { - mySemaphore.up(); - } - } - } - catch (InterruptedException e) { - //Do nothing - } - } - }; - public void run() { mySemaphore.down(); ApplicationManager.getApplication().executeOnPooledThread(myProcessThread); - ApplicationManager.getApplication().executeOnPooledThread(myTimeoutListener); mySemaphore.waitFor(); } }; } -} \ No newline at end of file +} diff --git a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java index b58f110bca68..20f17a5a7df7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java +++ b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java @@ -100,7 +100,8 @@ public class GeneralColorsPage implements ColorSettingsPage, InspectionColorSett private static final ColorDescriptor[] COLOR_DESCRIPTORS = { new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.background.in.readonly.files"), EditorColors.READONLY_BACKGROUND_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.deneral.color.descriptor.readonly.fragment.background"), EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, ColorDescriptor.Kind.BACKGROUND), - new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.gutter.background"), EditorColors.LEFT_GUTTER_BACKGROUND, ColorDescriptor.Kind.BACKGROUND), + new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.gutter.background"), EditorColors.GUTTER_BACKGROUND, ColorDescriptor.Kind.BACKGROUND), + new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.notification.background"), EditorColors.NOTIFICATION_BACKGROUND, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.selection.background"), EditorColors.SELECTION_BACKGROUND_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.selection.foreground"), EditorColors.SELECTION_FOREGROUND_COLOR, ColorDescriptor.Kind.FOREGROUND), @@ -113,8 +114,8 @@ public class GeneralColorsPage implements ColorSettingsPage, InspectionColorSett new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.line.number"), EditorColors.LINE_NUMBERS_COLOR, ColorDescriptor.Kind.FOREGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.vcs.annotations"), EditorColors.ANNOTATIONS_COLOR, ColorDescriptor.Kind.FOREGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.vcs.annotations.merged"), EditorColors.ANNOTATIONS_MERGED_COLOR, ColorDescriptor.Kind.FOREGROUND), - new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.folding.outline"), EditorColors.FOLDING_TREE_COLOR, ColorDescriptor.Kind.FOREGROUND), - new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.selected.folding.outline"), EditorColors.SELECTED_FOLDING_TREE_COLOR, ColorDescriptor.Kind.FOREGROUND), + new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.tearline"), EditorColors.TEARLINE_COLOR, ColorDescriptor.Kind.FOREGROUND), + new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.tearline.selected"), EditorColors.SELECTED_TEARLINE_COLOR, ColorDescriptor.Kind.FOREGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.added.lines"), EditorColors.ADDED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.general.color.descriptor.modified.lines"), EditorColors.MODIFIED_LINES_COLOR, ColorDescriptor.Kind.BACKGROUND), new ColorDescriptor(OptionsBundle.message("options.java.color.descriptor.method.separator.color"), CodeInsightColors.METHOD_SEPARATORS_COLOR, ColorDescriptor.Kind.FOREGROUND), diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java index 75d415fe5c97..aa9655238917 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java @@ -32,12 +32,13 @@ import com.intellij.refactoring.rename.PsiElementRenameHandler; import com.intellij.refactoring.rename.RenameHandler; import com.intellij.refactoring.rename.RenameHandlerRegistry; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public final class VariableInplaceRenameHandler implements RenameHandler { +public class VariableInplaceRenameHandler implements RenameHandler { private static final ThreadLocal ourPreventInlineRenameFlag = new ThreadLocal(); private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler"); - public boolean isAvailableOnDataContext(final DataContext dataContext) { + public final boolean isAvailableOnDataContext(final DataContext dataContext) { final PsiElement element = PsiElementRenameHandler.getElement(dataContext); final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext); @@ -46,15 +47,20 @@ public final class VariableInplaceRenameHandler implements RenameHandler { if (ourPreventInlineRenameFlag.get() != null) { return false; } + return isAvailable(element, editor, file); + } + + protected boolean isAvailable(PsiElement element, Editor editor, PsiFile file) { final PsiElement nameSuggestionContext = file.findElementAt(editor.getCaretModel().getOffset()); - final RefactoringSupportProvider supportProvider = element != null ? LanguageRefactoringSupport.INSTANCE.forLanguage(element.getLanguage()):null; + final RefactoringSupportProvider + supportProvider = element != null ? LanguageRefactoringSupport.INSTANCE.forLanguage(element.getLanguage()):null; return supportProvider != null && editor.getSettings().isVariableInplaceRenameEnabled() && supportProvider.doInplaceRenameFor(element, nameSuggestionContext); } - public boolean isRenaming(final DataContext dataContext) { + public final boolean isRenaming(final DataContext dataContext) { return isAvailableOnDataContext(dataContext); } @@ -83,7 +89,8 @@ public final class VariableInplaceRenameHandler implements RenameHandler { return; } - final boolean startedRename = new VariableInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor).performInplaceRename(); + VariableInplaceRenamer renamer = createRenamer(elementToRename, editor); + boolean startedRename = renamer == null ? false : renamer.performInplaceRename(); if (!startedRename) { try { @@ -101,4 +108,9 @@ public final class VariableInplaceRenameHandler implements RenameHandler { } } } + + @Nullable + protected VariableInplaceRenamer createRenamer(PsiElement elementToRename, Editor editor) { + return new VariableInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor); + } } diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfiguration.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfiguration.java index 5b6df5e5102b..d79c015e4315 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfiguration.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfiguration.java @@ -16,6 +16,8 @@ package com.intellij.ui.tabs; +import com.intellij.openapi.project.Project; +import com.intellij.psi.search.scope.packageSet.NamedScopeManager; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,7 +56,7 @@ class FileColorConfiguration implements Cloneable { myColorName = colorName; } - public boolean isValid() { + public boolean isValid(Project project) { if (myScopeName == null || myScopeName.length() == 0) { return false; } @@ -63,11 +65,15 @@ class FileColorConfiguration implements Cloneable { return false; } - return true; + if (project != null) { + return NamedScopeManager.getScope(project, myScopeName) != null; + } else { + return true; + } } public void save(@NotNull final Element e) { - if (!isValid()) { + if (!isValid(null)) { return; } diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorManagerImpl.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorManagerImpl.java index a926ed2170a9..40ea7834ed48 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorManagerImpl.java @@ -53,11 +53,14 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent private final Project myProject; private boolean myEnabledForTabs = true; + private boolean myHighlightNonProjectFiles = true; private static final Map ourDefaultColors; + private static final Map ourHiddenColors; static { ourDefaultColors = new LinkedHashMap(); + ourHiddenColors = new LinkedHashMap(); ourDefaultColors.put("Blue", new Color(215, 237, 243)); //ourDefaultColors.put("Blue 2", new Color(218, 224, 244)); ourDefaultColors.put("Green", new Color(228, 241, 209)); @@ -66,6 +69,8 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent ourDefaultColors.put("Rose", new Color(242, 206, 202)); ourDefaultColors.put("Violet", new Color(222, 213, 241)); ourDefaultColors.put("Yellow", new Color(247, 241, 203)); + + ourHiddenColors.put(OUT_OF_PROJECT_SCOPE_COLOR, new Color(255, 255, 228)); } public FileColorManagerImpl(@NotNull final Project project) { @@ -95,11 +100,20 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent return myEnabledForTabs; } + public boolean isHighlightNonProjectFiles() { + return myHighlightNonProjectFiles; + } + + public void setHighlightNonProjectFiles(boolean highlight) { + myHighlightNonProjectFiles = highlight; + } + public Element getState(final boolean shared) { Element element = new Element("state"); if (!shared) { element.setAttribute("enabled", Boolean.toString(myEnabled)); element.setAttribute("enabledForTabs", Boolean.toString(myEnabledForTabs)); + element.setAttribute("highlightNonProjectFiles", Boolean.toString(myHighlightNonProjectFiles)); } myModel.save(element, shared); @@ -110,7 +124,8 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent @SuppressWarnings({"MethodMayBeStatic"}) @Nullable public Color getColor(@NotNull final String name) { - return ourDefaultColors.get(name); + final Color color = ourDefaultColors.get(name); + return color == null ? ourHiddenColors.get(name) : color; } public static String toString(final Color color) { @@ -133,7 +148,10 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent myEnabled = enabled == null ? true : Boolean.valueOf(enabled); final String enabledForTabs = state.getAttributeValue("enabledForTabs"); - myEnabledForTabs = enabledForTabs == null ? false : Boolean.valueOf(enabledForTabs); + myEnabledForTabs = enabledForTabs == null ? true : Boolean.valueOf(enabledForTabs); + + final String highlightNonProjectFiles = state.getAttributeValue("highlightNonProjectFiles"); + myHighlightNonProjectFiles = highlightNonProjectFiles == null ? true : Boolean.valueOf(highlightNonProjectFiles); } myModel.load(state, shared); @@ -183,7 +201,7 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent @Nullable public Color getFileColor(@NotNull final PsiFile file) { final String colorName = myModel.getColor(file); - return colorName == null ? null : ourDefaultColors.get(colorName); + return colorName == null ? null : getColor(colorName); } public boolean isShared(@NotNull final String scopeName) { diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsConfigurablePanel.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsConfigurablePanel.java index aa15cd6347c4..5693b316a581 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsConfigurablePanel.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsConfigurablePanel.java @@ -37,6 +37,7 @@ public class FileColorsConfigurablePanel extends JPanel implements Disposable { private FileColorManagerImpl myManager; private final JCheckBox myEnabledCheckBox; private final JCheckBox myTabsEnabledCheckBox; + private final JCheckBox myHighlightNonProjectFilesCheckBox; private final FileColorSettingsTable myLocalTable; private final FileColorSettingsTable mySharedTable; @@ -56,6 +57,10 @@ public class FileColorsConfigurablePanel extends JPanel implements Disposable { myTabsEnabledCheckBox = new JCheckBox("Use colors in Editor Tabs"); myTabsEnabledCheckBox.setMnemonic('T'); topPanel.add(myTabsEnabledCheckBox); + + myHighlightNonProjectFilesCheckBox = new JCheckBox("Highlight Non-Project Files"); + myHighlightNonProjectFilesCheckBox.setMnemonic('N'); + topPanel.add(myHighlightNonProjectFilesCheckBox); topPanel.add(Box.createHorizontalGlue()); add(topPanel, BorderLayout.NORTH); @@ -229,6 +234,7 @@ public class FileColorsConfigurablePanel extends JPanel implements Disposable { modified = myEnabledCheckBox.isSelected() != myManager.isEnabled(); modified |= myTabsEnabledCheckBox.isSelected() != myManager.isEnabledForTabs(); + modified |= myHighlightNonProjectFilesCheckBox.isSelected() != myManager.isHighlightNonProjectFiles(); modified |= myLocalTable.isModified() || mySharedTable.isModified(); return modified; @@ -237,6 +243,7 @@ public class FileColorsConfigurablePanel extends JPanel implements Disposable { public void apply() { myManager.setEnabled(myEnabledCheckBox.isSelected()); myManager.setEnabledForTabs(myTabsEnabledCheckBox.isSelected()); + myManager.setHighlightNonProjectFiles(myHighlightNonProjectFilesCheckBox.isSelected()); myLocalTable.apply(); mySharedTable.apply(); @@ -247,6 +254,7 @@ public class FileColorsConfigurablePanel extends JPanel implements Disposable { public void reset() { myEnabledCheckBox.setSelected(myManager.isEnabled()); myTabsEnabledCheckBox.setSelected(myManager.isEnabledForTabs()); + myHighlightNonProjectFilesCheckBox.setSelected(myManager.isHighlightNonProjectFiles()); if(myLocalTable.isModified()) myLocalTable.reset(); if(mySharedTable.isModified()) mySharedTable.reset(); diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java index 51da4e225235..41cde5d978e4 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorsModel.java @@ -17,10 +17,14 @@ package com.intellij.ui.tabs; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopeManager; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; +import com.intellij.ui.FileColorManager; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -136,13 +140,23 @@ public class FileColorsModel implements Cloneable { } final FileColorConfiguration configuration = findConfiguration(psiFile); - if (configuration != null && configuration.isValid()) { + if (configuration != null && configuration.isValid(psiFile.getProject())) { return configuration.getColorName(); } + if (FileColorManager.getInstance(myProject).isHighlightNonProjectFiles() + && !isFileUnderProject(psiFile.getVirtualFile())) { + return FileColorManager.OUT_OF_PROJECT_SCOPE_COLOR; + } return null; } + private boolean isFileUnderProject(@Nullable VirtualFile file) { + if (file == null) return false; + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); + return myProject.isInitialized() && !fileIndex.isIgnored(file) && fileIndex.getContentRootForFile(file) != null; + } + @Nullable private FileColorConfiguration findConfiguration(@NotNull final PsiFile colored) { for (final FileColorConfiguration configuration : myConfigurations) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java b/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java index 09d8b21080b2..a271dc9dc083 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java @@ -33,15 +33,22 @@ public interface EditorColors { TextAttributesKey SEARCH_RESULT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("SEARCH_RESULT_ATTRIBUTES"); TextAttributesKey WRITE_SEARCH_RESULT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("WRITE_SEARCH_RESULT_ATTRIBUTES"); TextAttributesKey IDENTIFIER_UNDER_CARET_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("IDENTIFIER_UNDER_CARET_ATTRIBUTES"); - TextAttributesKey WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES"); + TextAttributesKey WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES = + TextAttributesKey.createTextAttributesKey("WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES"); TextAttributesKey TEXT_SEARCH_RESULT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("TEXT_SEARCH_RESULT_ATTRIBUTES"); TextAttributesKey FOLDED_TEXT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("FOLDED_TEXT_ATTRIBUTES"); - ColorKey FOLDING_TREE_COLOR = ColorKey.createColorKey("FOLDING_TREE_COLOR"); - ColorKey SELECTED_FOLDING_TREE_COLOR = ColorKey.createColorKey("SELECTED_FOLDING_TREE_COLOR"); + + ColorKey GUTTER_BACKGROUND = ColorKey.createColorKey("GUTTER_BACKGROUND"); + @Deprecated ColorKey LEFT_GUTTER_BACKGROUND = GUTTER_BACKGROUND; + ColorKey NOTIFICATION_BACKGROUND = ColorKey.createColorKey("NOTIFICATION_BACKGROUND"); + + ColorKey TEARLINE_COLOR = ColorKey.createColorKey("TEARLINE_COLOR"); + ColorKey SELECTED_TEARLINE_COLOR = ColorKey.createColorKey("SELECTED_TEARLINE_COLOR"); + @Deprecated ColorKey FOLDING_TREE_COLOR = TEARLINE_COLOR; + @Deprecated ColorKey SELECTED_FOLDING_TREE_COLOR = SELECTED_TEARLINE_COLOR; ColorKey ADDED_LINES_COLOR = ColorKey.createColorKey("ADDED_LINES_COLOR"); ColorKey MODIFIED_LINES_COLOR = ColorKey.createColorKey("MODIFIED_LINES_COLOR"); - ColorKey LEFT_GUTTER_BACKGROUND = ColorKey.createColorKey("LEFT_GUTTER_BACKGROUND"); TextAttributesKey INJECTED_LANGUAGE_FRAGMENT = TextAttributesKey.createTextAttributesKey("INJECTED_LANGUAGE_FRAGMENT"); } diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java index 32f4af9e4bfe..0a91e3cff630 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java @@ -108,7 +108,13 @@ public abstract class FileEditorManager { */ @NotNull public abstract FileEditor[] getAllEditors(); + /** + * @deprecated use addTopComponent + */ public abstract void showEditorAnnotation(@NotNull FileEditor editor, @NotNull JComponent annotationComoponent); + /** + * @deprecated use removeTopComponent + */ public abstract void removeEditorAnnotation(@NotNull FileEditor editor, @NotNull JComponent annotationComoponent); public abstract void addTopComponent(@NotNull final FileEditor editor, @NotNull final JComponent component); diff --git a/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java b/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java index 782257e0b6f1..e195664cf9c6 100644 --- a/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java +++ b/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java @@ -20,6 +20,9 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; import org.jetbrains.annotations.NonNls; import javax.swing.*; @@ -31,19 +34,16 @@ import java.awt.*; * @author Dmitry Avdeev */ public class EditorNotificationPanel extends JPanel { - protected final JLabel myLabel = new JLabel(); protected final JPanel myLinksPanel; public EditorNotificationPanel() { super(new BorderLayout()); - - setBackground(LightColors.YELLOW); - setBorder(new SideBorder(Color.gray, SideBorder.BOTTOM, true)); + setBorder(BorderFactory.createEmptyBorder(1, 15, 1, 15)); setPreferredSize(new Dimension(-1, 24)); + add(myLabel, BorderLayout.CENTER); - myLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); myLinksPanel = new JPanel(new FlowLayout()); myLinksPanel.setBackground(LightColors.YELLOW); @@ -54,6 +54,12 @@ public class EditorNotificationPanel extends JPanel { myLabel.setText(text); } + @Override + public Color getBackground() { + Color color = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.NOTIFICATION_BACKGROUND); + return color == null ? new Color(0xffffcc) : color; + } + public HyperlinkLabel createActionLabel(final String text, @NonNls final String actionId) { return createActionLabel(text, new Runnable() { public void run() { @@ -63,7 +69,7 @@ public class EditorNotificationPanel extends JPanel { } public HyperlinkLabel createActionLabel(final String text, final Runnable action) { - HyperlinkLabel label = new HyperlinkLabel(text, Color.BLUE, LightColors.YELLOW, Color.BLUE); + HyperlinkLabel label = new HyperlinkLabel(text, Color.BLUE, getBackground(), Color.BLUE); label.addHyperlinkListener(new HyperlinkListener() { public void hyperlinkUpdate(final HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { diff --git a/platform/platform-api/src/com/intellij/ui/ExcludingTraversalPolicy.java b/platform/platform-api/src/com/intellij/ui/ExcludingTraversalPolicy.java index e2acc21b3d25..e6fedf213f80 100644 --- a/platform/platform-api/src/com/intellij/ui/ExcludingTraversalPolicy.java +++ b/platform/platform-api/src/com/intellij/ui/ExcludingTraversalPolicy.java @@ -85,6 +85,6 @@ public class ExcludingTraversalPolicy extends FocusTraversalPolicy { @Override public Component getDefaultComponent(Container aContainer) { - return myWrappee.getDefaultComponent(aContainer); + return getFirstComponent(aContainer); } } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java index 2da522b899e7..de68140d7ec2 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java @@ -114,7 +114,7 @@ public class EditorFragmentComponent extends JPanel { setLayout(new BorderLayout()); add(component); - final Color borderColor = editor.getColorsScheme().getColor(EditorColors.SELECTED_FOLDING_TREE_COLOR); + final Color borderColor = editor.getColorsScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR); Border outsideBorder = BorderFactory.createLineBorder(borderColor, 1); Border insideBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java index 7c25b2080040..6308f59d545e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java @@ -31,7 +31,14 @@ public abstract class EditorGutterComponentEx extends JComponent implements Edit public abstract int getWhitespaceSeparatorOffset(); - public abstract Color getFoldingColor(boolean isActive); + public abstract Color getOutlineColor(boolean isActive); + + /** + * @deprecated use getOutlineColor + */ + public Color getFoldingColor(boolean isActive) { + return getOutlineColor(isActive); + } public abstract void revalidateMarkup(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapChangeListener.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapChangeListener.java new file mode 100644 index 000000000000..8a4d17f3e6a2 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapChangeListener.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.ex; + +/** + * Defines a contract for the callbacks for soft wraps management notifications (addition/removal). + * + * @author Denis Zhdanov + * @since Jul 8, 2010 6:50:17 PM + */ +public interface SoftWrapChangeListener { + + /** + * This method is assumed to be called every time number of soft wraps registered for the target logical line(s) + * is changed (soft wraps are added or remove). + * + * @param changedLogicalLine logical line for which number of registered soft wraps is changed + */ + void softWrapsStateChanged(int changedLogicalLine); +} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java index cb723ffc1405..88d897c9d3e7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType; import org.jetbrains.annotations.NotNull; import java.awt.*; +import java.util.Collections; import java.util.List; /** @@ -72,6 +73,18 @@ public interface SoftWrapModelEx extends SoftWrapModel { */ List getRegisteredSoftWraps(); + /** + * Tries to find index of the target soft wrap at {@link #getRegisteredSoftWraps() soft wraps collection}. + * 'Target' soft wrap is the one that starts at the given offset. + * + * @param offset target offset + * @return index that conforms to {@link Collections#binarySearch(List, Object)} contract, i.e. non-negative returned + * index points to soft wrap that starts at the given offset; '-(negative value) - 1' points + * to position at {@link #getRegisteredSoftWraps() soft wraps collection} where soft wrap for the given index + * should be inserted + */ + int getSoftWrapIndex(int offset); + /** * Asks to paint drawing of target type at the given graphics buffer at the given position. * @@ -91,4 +104,12 @@ public interface SoftWrapModelEx extends SoftWrapModel { * @return width in pixels required for the painting of the given type */ int getMinDrawingWidth(@NotNull SoftWrapDrawingType drawingType); + + /** + * Registers given listener within the current model + * + * @param listener listener to register + * @return true if given listener was not registered before; false otherwise + */ + boolean addSoftWrapChangeListener(@NotNull SoftWrapChangeListener listener); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 36b90cb9dc3d..bb5ade1b546a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -27,7 +27,6 @@ package com.intellij.openapi.editor.impl; import com.intellij.codeInsight.hint.TooltipController; import com.intellij.codeInsight.hint.TooltipGroup; import com.intellij.ide.IdeEventQueue; -import com.intellij.ide.ui.LafManager; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; @@ -119,6 +118,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse public void reinitSettings() { myBackgroundColor = null; + revalidateMarkup(); repaint(); } @@ -191,9 +191,12 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private void paintAnnotations(Graphics g, Rectangle clip) { - paintBackground(g, clip, getAnnotationsAreaOffset(), getAnnotationsAreaWidth()); - int x = getAnnotationsAreaOffset(); + int w = getAnnotationsAreaWidth(); + + if (w == 0) return; + + paintBackground(g, clip, getAnnotationsAreaOffset(), w); Color color = myEditor.getColorsScheme().getColor(EditorColors.ANNOTATIONS_COLOR); g.setColor(color != null ? color : Color.blue); @@ -201,6 +204,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse for (int i = 0; i < myTextAnnotationGutters.size(); i++) { TextAnnotationGutterProvider gutterProvider = myTextAnnotationGutters.get(i); + int lineHeight = myEditor.getLineHeight(); int startLineNumber = clip.y / lineHeight; int endLineNumber = (clip.y + clip.height) / lineHeight + 1; @@ -209,7 +213,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse .line; endLineNumber = Math.min(endLineNumber, lastLine + 1); if (startLineNumber >= endLineNumber) { - return; + break; } for (int j = startLineNumber; j < endLineNumber; j++) { @@ -219,7 +223,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse final Color bg = gutterProvider.getBgColor(logLine, myEditor); if (bg != null) { g.setColor(bg); - g.fillRect(x, j * lineHeight, getAnnotationsAreaWidth(), lineHeight); + g.fillRect(x, j * lineHeight, w, lineHeight); } g.setColor(myEditor.getColorsScheme().getColor(gutterProvider.getColor(logLine, myEditor))); g.setFont(myEditor.getColorsScheme().getFont(style)); @@ -230,6 +234,8 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse x += myTextAnnotationGutterSizes.get(i); } + + UIUtil.drawVDottedLine((Graphics2D)g, getAnnotationsAreaOffset() + w - 1, clip.y, clip.y + clip.height, null, getOutlineColor(false)); } private void paintFoldingTree(Graphics g, Rectangle clip) { @@ -237,9 +243,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse paintFoldingTree((Graphics2D)g); } else { - g.setColor(Color.white); - int x = getWhitespaceSeparatorOffset() - 1; - UIUtil.drawVDottedLine((Graphics2D)g, x, clip.y, clip.y + clip.height, myEditor.getBackgroundColor(), getFoldingColor(false)); + UIUtil.drawVDottedLine((Graphics2D)g, clip.x + clip.width -1, clip.y, clip.y + clip.height, null, getOutlineColor(false)); } } @@ -270,28 +274,16 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private void paintLineNumbers(Graphics g, Rectangle clip) { if (isLineNumbersShown()) { paintBackground(g, clip, getLineNumberAreaOffset(), getLineNumberAreaWidth()); - g.setColor(Color.white); int x = getLineNumberAreaOffset() + getLineNumberAreaWidth() - 2; - UIUtil.drawLine(g, x, clip.y, x, clip.y + clip.height); + UIUtil.drawVDottedLine((Graphics2D)g, x, clip.y, clip.y + clip.height, null, getOutlineColor(false)); paintLineNumbers(g); } } public Color getBackground() { if (myBackgroundColor == null) { - final Color userDefinedColor = myEditor.getColorsScheme().getColor(EditorColors.LEFT_GUTTER_BACKGROUND); - if (userDefinedColor != null) { - myBackgroundColor = userDefinedColor; - } - else { - LafManager lafManager = LafManager.getInstance(); - if (lafManager != null && lafManager.isUnderAquaLookAndFeel()) { - myBackgroundColor = new Color(0xF0F0F0); - } - else { - myBackgroundColor = super.getBackground(); - } - } + Color color = myEditor.getColorsScheme().getColor(EditorColors.GUTTER_BACKGROUND); + myBackgroundColor = color == null ? new Color(0xF0F0F0) : color; } return myBackgroundColor; } @@ -639,8 +631,8 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return (myEditor.getLineHeight() - icon.getIconHeight()) /2; } - public Color getFoldingColor(boolean isActive) { - ColorKey key = isActive ? EditorColors.SELECTED_FOLDING_TREE_COLOR : EditorColors.FOLDING_TREE_COLOR; + public Color getOutlineColor(boolean isActive) { + ColorKey key = isActive ? EditorColors.SELECTED_TEARLINE_COLOR : EditorColors.TEARLINE_COLOR; Color color = myEditor.getColorsScheme().getColor(key); return color != null ? color : Color.black; } @@ -706,7 +698,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse if (!isFoldingOutlineShown()) return; Rectangle clip = g.getClipBounds(); - UIUtil.drawVDottedLine(g, getWhitespaceSeparatorOffset(), clip.y, clip.y + clip.height, myEditor.getBackgroundColor(), getFoldingColor(false)); + UIUtil.drawVDottedLine(g, getWhitespaceSeparatorOffset(), clip.y, clip.y + clip.height, null, getOutlineColor(false)); int anchorX = getFoldingAreaOffset(); int width = getFoldingAnchorWidth(); @@ -820,7 +812,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse g.fillPolygon(xPoints, yPoints, 5); } else { - g.setColor(getFoldingColor(active)); + g.setColor(getOutlineColor(active)); g.drawPolygon(xPoints, yPoints, 5); //Minus @@ -855,11 +847,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse g.fillRect(anchorX, y, width, width); } else { - g.setColor(getFoldingColor(active)); + g.setColor(getOutlineColor(active)); g.drawRect(anchorX, y, width, width); // Draw plus - if (!active) g.setColor(getFoldingColor(true)); + if (!active) g.setColor(getOutlineColor(true)); UIUtil.drawLine(g, anchorX + 2, y + width / 2, anchorX + width - 2, y + width / 2); } } @@ -876,7 +868,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse int lineX = anchorX + width / 2; - g.setColor(getFoldingColor(true)); + g.setColor(getOutlineColor(true)); UIUtil.drawLine(g, lineX, startY, lineX, endY); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 4cd94276b027..b935c71b4c0d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -176,7 +176,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private static final int MOUSE_SELECTION_STATE_LINE_SELECTED = 2; private final MarkupModelListener myMarkupModelListener; - private final List mySoftWrapsOnLastRepaint = new ArrayList(); private EditorHighlighter myHighlighter; private final TextDrawingCallback myTextDrawingCallback = new MyTextDrawingCallback(); @@ -216,6 +215,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private boolean myEmbeddedIntoDialogWrapper; private CachedFontContent myLastCache; private boolean mySpacesHaveSameWidth; + private boolean mySoftWrapsChanged; private Point myLastBackgroundPosition = null; private Color myLastBackgroundColor = null; @@ -327,6 +327,14 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myFoldingModel.flushCaretShift(); myScrollBarOrientation = VERTICAL_SCROLLBAR_RIGHT; + mySoftWrapModel.addSoftWrapChangeListener(new SoftWrapChangeListener() { + @Override + public void softWrapsStateChanged(int changedLogicalLine) { + mySoftWrapsChanged = true; + mySizeContainer.update(changedLogicalLine, changedLogicalLine, changedLogicalLine); + } + }); + EditorHighlighter highlighter = new EmptyEditorHighlighter(myScheme.getAttributes(HighlighterColors.TEXT)); setHighlighter(highlighter); @@ -1692,8 +1700,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi // Perform additional activity if soft wrap is added or removed during repainting. // Note: this code lives in this method in assumption that background repainting is the very first activity performed // during whole editor component repaint. - List softWrapsAfterRepaint = mySoftWrapModel.getRegisteredSoftWraps(); - if (!mySoftWrapsOnLastRepaint.equals(softWrapsAfterRepaint)) { + if (mySoftWrapsChanged) { + mySoftWrapsChanged = false; + validateSize(); + // Repaint editor to the bottom in order to ensure that its content is shown correctly after new soft wrap introduction. repaintToScreenBottom(xyToLogicalPosition(position).line); @@ -1704,8 +1714,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi // Ask caret model to update visual caret position. getCaretModel().moveToOffset(getCaretModel().getOffset()); } - mySoftWrapsOnLastRepaint.clear(); - mySoftWrapsOnLastRepaint.addAll(softWrapsAfterRepaint); } private void paintRectangularSelection(Graphics g) { @@ -2482,11 +2490,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public Dimension getContentSize() { Dimension size = mySizeContainer.getContentSize(); - //TODO den move soft wrap-related logic to editor size container - return new Dimension( - size.width, - size.height + (mySettings.getAdditionalLinesCount() + mySoftWrapModel.getSoftWrapsIntroducedLinesNumber()) * getLineHeight() - ); + return new Dimension(size.width, size.height + mySettings.getAdditionalLinesCount() * getLineHeight()); } public JScrollPane getScrollPane() { @@ -2524,10 +2528,20 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return myLastColumnNumber; } + /** + * @return information about total number of lines that can be viewed by user. I.e. this is a number of all document + * lines (considering that single logical document line may be represented on multiple visual lines because of + * soft wraps appliance) minus number of folded lines + */ int getVisibleLineCount() { - int line = getDocument().getLineCount() + getSoftWrapModel().getSoftWrapsIntroducedLinesNumber(); - line -= myFoldingModel.getFoldedLinesCountBefore(getDocument().getTextLength() + 1); - return line; + return getVisibleLogicalLinesCount() + getSoftWrapModel().getSoftWrapsIntroducedLinesNumber(); + } + + /** + * @return number of visible logical lines. Generally, that is a total logical lines number minus number of folded lines + */ + private int getVisibleLogicalLinesCount() { + return getDocument().getLineCount() - myFoldingModel.getFoldedLinesCountBefore(getDocument().getTextLength() + 1); } @NotNull @@ -4595,15 +4609,25 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } + @SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private class EditorSizeContainer { + + /** Holds logical line widths in pixels. */ private TIntArrayList myLineWidths; + + /** Holds value that indicates if line widths recalculation should be performed. */ private volatile boolean myIsDirty; + + /** Holds number of the last logical line affected by the last document change. */ private int myOldEndLine; + private Dimension mySize; - private int myMaxWidth = -1; + + private final Object lock = new Object(); + private int myMaxWidth = -1; public synchronized void reset() { - int visLinesCount = getVisibleLineCount(); + int visLinesCount = getDocument().getLineCount(); myLineWidths = new TIntArrayList(visLinesCount + 300); int[] values = new int[visLinesCount]; Arrays.fill(values, -1); @@ -4611,6 +4635,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myIsDirty = true; } + @SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext"}) public synchronized void beforeChange(DocumentEvent e) { if (myDocument.isInBulkUpdate()) { myMaxWidth = mySize != null ? mySize.width : -1; @@ -4626,11 +4651,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return offsetToVisualPosition(startLineOffset).line; } - public synchronized void changedUpdate(DocumentEvent e) { - int startLine = e.getOldLength() == 0 ? myOldEndLine : getVisualPositionLine(e.getOffset()); - int newEndLine = e.getNewLength() == 0 ? startLine : getVisualPositionLine(e.getOffset() + e.getNewLength()); - int oldEndLine = myOldEndLine; - + public synchronized void update(int startLine, int newEndLine, int oldEndLine) { final int lineWidthSize = myLineWidths.size(); if (lineWidthSize == 0) { reset(); @@ -4657,12 +4678,21 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } + public synchronized void changedUpdate(DocumentEvent e) { + int startLine = e.getOldLength() == 0 ? myOldEndLine : getVisualPositionLine(e.getOffset()); + int newEndLine = e.getNewLength() == 0 ? startLine : getVisualPositionLine(e.getOffset() + e.getNewLength()); + int oldEndLine = myOldEndLine; + + update(startLine, newEndLine, oldEndLine); + } + + @SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext", "AssignmentToForLoopParameter"}) private void validateSizes() { if (!myIsDirty) return; - synchronized (this) { + synchronized (lock) { if (!myIsDirty) return; - int lineCount = myLineWidths.size(); + int lineCount = Math.min(myLineWidths.size(), myDocument.getLineCount()); if (myMaxWidth != -1 && myDocument.isInBulkUpdate()) { mySize = new Dimension(myMaxWidth, getLineHeight() * lineCount); @@ -4676,19 +4706,31 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi final int fontSize = myScheme.getEditorFontSize(); final String fontName = myScheme.getEditorFontName(); + List softWraps = getSoftWrapModel().getRegisteredSoftWraps(); + int softWrapsIndex = -1; + for (int line = 0; line < lineCount; line++) { if (myLineWidths.getQuick(line) != -1) continue; x = 0; - int offset = logicalPositionToOffset(visualToLogicalPosition(new VisualPosition(line, 0))); + int offset = myDocument.getLineStartOffset(line); if (offset >= myDocument.getTextLength()) { myLineWidths.set(line, 0); break; } + if (softWrapsIndex < 0) { + softWrapsIndex = getSoftWrapModel().getSoftWrapIndex(offset); + if (softWrapsIndex < 0) { + softWrapsIndex = -softWrapsIndex - 1; + } + } + IterationState state = new IterationState(EditorImpl.this, offset, false); int fontType = state.getMergedAttributes().getFontType(); + int maxPreviousSoftWrappedWidth = -1; + while (offset < end && line < lineCount) { char c = text.charAt(offset); if (offset >= state.getEndOffset()) { @@ -4696,6 +4738,22 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi fontType = state.getMergedAttributes().getFontType(); } + while (softWrapsIndex < softWraps.size()) { + TextChange softWrap = softWraps.get(softWrapsIndex); + if (softWrap.getStart() > offset) { + break; + } + softWrapsIndex++; + if (softWrap.getStart() == offset) { + maxPreviousSoftWrappedWidth = Math.max(maxPreviousSoftWrappedWidth, x); + x = getSoftWrapModel().getSoftWrapIndentWidthInPixels(softWrap); + } + } + if (line + 1 >= lineCount) { + myLineWidths.set(line, Math.max(x, maxPreviousSoftWrappedWidth)); + break; + } + FoldRegion collapsed = state.getCurrentFold(); if (collapsed != null) { String placeholder = collapsed.getPlaceholderText(); @@ -4703,6 +4761,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi x += EditorUtil.charWidth(placeholder.charAt(i), fontType, EditorImpl.this); } offset = collapsed.getEndOffset(); + line = myDocument.getLineNumber(offset); } else { if (c == '\t') { @@ -4711,7 +4770,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } else { if (c == '\n') { - myLineWidths.set(line, x); + myLineWidths.set(line, Math.max(x, maxPreviousSoftWrappedWidth)); if (line + 1 >= lineCount || myLineWidths.getQuick(line + 1) != -1) break; offset++; x = 0; @@ -4732,12 +4791,28 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi x); // Last line can be non-zero length and won't be caught by in-loop procedure since latter only react on \n's } + // There is a following possible situation: + // 1. Big document is opened at editor; + // 2. Soft wraps are calculated for the current visible area; + // 2. The user scrolled down; + // 3. The user significantly reduced visible area width (say, reduced it twice); + // 4. Soft wraps are calculated for the current visible area; + // We need to consider only the widths for the logical lines that are completely shown at the current visible area then. + // I.e. we shouldn't use widths of the lines that are not shown for max width calculation because previous widths are calculated + // for another visible area width. + int startToUse = 0; + int endToUse = lineCount; + if (getSoftWrapModel().isSoftWrappingEnabled()) { + Rectangle visibleArea = getScrollingModel().getVisibleArea(); + startToUse = xyToLogicalPosition(visibleArea.getLocation()).line + 1; + endToUse = xyToLogicalPosition(new Point(0, visibleArea.y + visibleArea.height)).line; + } int maxWidth = 0; - for (int i = 0; i < lineCount; i++) { + for (int i = startToUse; i < endToUse; i++) { maxWidth = Math.max(maxWidth, myLineWidths.getQuick(i)); } - mySize = new Dimension(maxWidth, getLineHeight() * lineCount); + mySize = new Dimension(maxWidth, getLineHeight() * getVisibleLineCount()); myIsDirty = false; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java index 175681baf26a..de8cbb67c426 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java @@ -15,11 +15,9 @@ */ package com.intellij.openapi.editor.impl; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.LogicalPosition; -import com.intellij.openapi.editor.TextChange; -import com.intellij.openapi.editor.VisualPosition; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.ex.SoftWrapChangeListener; import com.intellij.openapi.editor.ex.SoftWrapModelEx; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.softwrap.*; @@ -56,7 +54,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx { private int myActive; public SoftWrapModelImpl(@NotNull EditorEx editor) { - this(editor, new SoftWrapsStorage(), new CompositeSoftWrapPainter(editor)); + this(editor, new SoftWrapsStorage(editor.getDocument()), new CompositeSoftWrapPainter(editor)); } public SoftWrapModelImpl(@NotNull final EditorEx editor, @NotNull SoftWrapsStorage storage, @NotNull SoftWrapPainter painter) { @@ -77,7 +75,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx { } public boolean isSoftWrappingEnabled() { - return myEditor.getSettings().isUseSoftWraps(); + return myEditor.getSettings().isUseSoftWraps() && !myEditor.isOneLineMode(); } @Nullable @@ -88,6 +86,11 @@ public class SoftWrapModelImpl implements SoftWrapModelEx { return myStorage.getSoftWrap(offset); } + @Override + public int getSoftWrapIndex(int offset) { + return myStorage.getSoftWrapIndex(offset); + } + @NotNull @Override public List getSoftWrapsForRange(int start, int end) { @@ -138,8 +141,11 @@ public class SoftWrapModelImpl implements SoftWrapModelEx { return 0; } int result = 0; - for (TextChange myWrap : myStorage.getSoftWraps()) { - result += StringUtil.countNewLines(myWrap.getText()); + FoldingModel foldingModel = myEditor.getFoldingModel(); + for (TextChange softWrap : myStorage.getSoftWraps()) { + if (!foldingModel.isOffsetCollapsed(softWrap.getStart())) { + result += StringUtil.countNewLines(softWrap.getText()); + } } return result; } @@ -309,4 +315,9 @@ public class SoftWrapModelImpl implements SoftWrapModelEx { // Restore caret position. myEditor.getCaretModel().moveToVisualPosition(visualCaretPosition); } + + @Override + public boolean addSoftWrapChangeListener(@NotNull SoftWrapChangeListener listener) { + return myStorage.addSoftWrapChangeListener(listener); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java index 345ae83973ee..5c325f5a7285 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java @@ -15,12 +15,16 @@ */ package com.intellij.openapi.editor.impl.softwrap; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.ex.SoftWrapChangeListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; /** * Holds registered soft wraps and provides monitoring and management facilities for them. @@ -32,8 +36,15 @@ import java.util.List; */ public class SoftWrapsStorage { - private final List myWraps = new ArrayList(); - private final List myWrapsView = Collections.unmodifiableList(myWraps); + private final List myWraps = new ArrayList(); + private final List myWrapsView = Collections.unmodifiableList(myWraps); + private final Set myListeners = new CopyOnWriteArraySet(); + + private final Document myDocument; + + public SoftWrapsStorage(Document document) { + myDocument = document; + } /** * @return true if there is at least one soft wrap registered at the current storage; false otherwise @@ -103,6 +114,10 @@ public class SoftWrapsStorage { i = -i - 1; myWraps.add(i, softWrap); + int changedLogicalLine = myDocument.getLineNumber(softWrap.getStart()); + for (SoftWrapChangeListener listener : myListeners) { + listener.softWrapsStateChanged(changedLogicalLine); + } return null; } @@ -127,4 +142,14 @@ public class SoftWrapsStorage { public void removeAll() { myWraps.clear(); } + + /** + * Registers given listener within the current model + * + * @param listener listener to register + * @return true if given listener was not registered before; false otherwise + */ + public boolean addSoftWrapChangeListener(@NotNull SoftWrapChangeListener listener) { + return myListeners.add(listener); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java index 16a857560f58..dcd7e45aeda7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java @@ -20,6 +20,8 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.project.DumbService; @@ -29,6 +31,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.FocusWatcher; import com.intellij.ui.PrevNextActionsDescriptor; +import com.intellij.ui.SideBorder; import com.intellij.ui.TabbedPaneWrapper; import com.intellij.ui.tabs.UiDecorator; import org.jetbrains.annotations.NotNull; @@ -77,7 +80,6 @@ public abstract class EditorComposite implements Disposable { private FileEditor mySelectedEditor; private final FileEditorManagerEx myFileEditorManager; private final long myInitialFileModificationStamp; - private final Map myInfoPanes = new HashMap(); private final Map myTopComponents = new HashMap(); private final Map myBottomComponents = new HashMap(); @@ -198,20 +200,14 @@ public abstract class EditorComposite implements Disposable { component.add(comp, BorderLayout.CENTER); - final JPanel topPanel = new JPanel(); - topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS)); + JPanel topPanel = new TopBottomPanel(); myTopComponents.put(editor, topPanel); component.add(topPanel, BorderLayout.NORTH); - final JPanel bottomPanel = new JPanel(); - bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); + final JPanel bottomPanel = new TopBottomPanel(); myBottomComponents.put(editor, bottomPanel); component.add(bottomPanel, BorderLayout.SOUTH); - FileEditorInfoPane infoPane = new FileEditorInfoPane(); - myInfoPanes.put(editor, infoPane); - addTopComponent(editor, infoPane); - return component; } @@ -307,17 +303,13 @@ public abstract class EditorComposite implements Disposable { assert container != null; if (remove) { - container.remove(component); + container.remove(component.getParent()); } else { - container.add(component); + container.add(new TopBottomComponentWrapper(component, top)); } container.revalidate(); } - public FileEditorInfoPane getPane(FileEditor editor) { - return myInfoPanes.get(editor); - } - /** * @return currently selected myEditor. The method never returns null. */ @@ -409,4 +401,33 @@ public abstract class EditorComposite implements Disposable { public void dispose() { } + + private class TopBottomPanel extends JPanel { + private TopBottomPanel() { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + } + + @Override + public Color getBackground() { + Color color = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.GUTTER_BACKGROUND); + return color == null ? Color.gray : color; + } + } + + private class TopBottomComponentWrapper extends JPanel { + public TopBottomComponentWrapper(JComponent component, boolean top) { + super(new BorderLayout()); + setOpaque(false); + + setBorder(new SideBorder(null, top ? SideBorder.BOTTOM : SideBorder.TOP, true) { + @Override + public Color getLineColor() { + Color result = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.TEARLINE_COLOR); + return result == null ? Color.black : result; + } + }); + + add(component); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorInfoPane.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorInfoPane.java deleted file mode 100644 index 759ad4fa40b0..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorInfoPane.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.openapi.fileEditor.impl; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; - -/** - * @author max - */ -public class FileEditorInfoPane extends JPanel { - private int myCounter = 0; - private final JPanel myCards; - private final JButton myPrevButton; - private final JButton myNextButton; - private final java.util.List myComponents; - private final JPanel myButtonsPanel; - - public FileEditorInfoPane() { - super(new BorderLayout()); - final CardLayout layout = new CardLayout(); - myCards = new JPanel(layout); - myComponents = new ArrayList(); - add(myCards, BorderLayout.CENTER); - myPrevButton = new JButton("<"); - myNextButton = new JButton(">"); - - myButtonsPanel = new JPanel(new GridLayout(1, 2)); - myButtonsPanel.add(myPrevButton); - myButtonsPanel.add(myNextButton); - - myPrevButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - layout.previous(myCards); - updateButtons(); - } - }); - - myNextButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - layout.next(myCards); - updateButtons(); - } - }); - - add(myButtonsPanel, BorderLayout.EAST); - myButtonsPanel.setVisible(false); - setVisible(false); - } - - public void addInfo(JComponent component) { - myComponents.add(component); - myCards.add(component, String.valueOf(myCounter++)); - updateButtons(); - validate(); - } - - public void removeInfo(JComponent component) { - myComponents.remove(component); - myCards.remove(component); - updateButtons(); - validate(); - } - - private int getCurrentCard() { - for (int i = 0; i < myComponents.size(); i++) { - if (myComponents.get(i).isVisible()) return i; - } - return -1; - } - - private void updateButtons() { - int count = myComponents.size(); - if (count > 0) { - setVisible(true); - if (count == 1) { - myButtonsPanel.setVisible(false); - } - else { - myButtonsPanel.setVisible(true); - int currentCard = getCurrentCard(); - myNextButton.setEnabled(currentCard + 1 < count); - myPrevButton.setEnabled(currentCard - 1 >= 0); - } - } - else { - setVisible(false); - } - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index 06493cbc0f5d..89cb3dfd4c09 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -915,17 +915,11 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec } public void showEditorAnnotation(@NotNull FileEditor editor, @NotNull JComponent annotationComponent) { - final EditorComposite composite = getEditorComposite(editor); - if (composite != null) { - composite.getPane(editor).addInfo(annotationComponent); - } + addTopComponent(editor, annotationComponent); } public void removeEditorAnnotation(@NotNull FileEditor editor, @NotNull JComponent annotationComponent) { - final EditorComposite composite = getEditorComposite(editor); - if (composite != null) { - composite.getPane(editor).removeInfo(annotationComponent); - } + removeTopComponent(editor, annotationComponent); } public void addTopComponent(@NotNull final FileEditor editor, @NotNull final JComponent component) { diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java index 78f4584e3c81..705f55786f1f 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java @@ -1,5 +1,6 @@ package com.intellij.openapi.editor.impl.softwrap; +import com.intellij.idea.Bombed; import com.intellij.mock.MockFoldRegion; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.ex.EditorEx; @@ -17,10 +18,7 @@ import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.Mockery; import org.jmock.lib.legacy.ClassImposteriser; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; /** * @author Denis Zhdanov @@ -85,9 +83,10 @@ public class SoftWrapDataMapperTest { myMockery = new JUnit4Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; - myStorage = new SoftWrapsStorage(); + myEditor = myMockery.mock(EditorEx.class); myDocument = myMockery.mock(Document.class); + myStorage = new SoftWrapsStorage(myDocument); myFoldingModel = myMockery.mock(FoldingModel.class); final EditorSettings settings = myMockery.mock(EditorSettings.class); final Project project = myMockery.mock(Project.class); @@ -177,6 +176,7 @@ public class SoftWrapDataMapperTest { myMockery.assertIsSatisfied(); } + @Bombed(day = 12, month = Calendar.JULY) @Test public void softWrapHasSymbolBeforeFirstLineFeed() { String document = @@ -192,6 +192,7 @@ public class SoftWrapDataMapperTest { test(document); } + @Bombed(day = 12, month = Calendar.JULY) @Test public void multipleSoftWrappedLogicalLines() { String document = @@ -211,6 +212,7 @@ public class SoftWrapDataMapperTest { test(document); } + @Bombed(day = 12, month = Calendar.JULY) @Test public void softWrapAndFoldedLines() { String document = diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index c207d61fd61a..1caf6b46de68 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -107,8 +107,9 @@ options.xml.attribute.descriptor.descriptor.entity,reference=Entity reference options.general.color.descriptor.background.in.readonly.files=Background in readonly files options.deneral.color.descriptor.readonly.fragment.background=Readonly fragment background options.general.color.descriptor.gutter.background=Gutter background -options.general.color.descriptor.selection.background=Selection Background -options.general.color.descriptor.selection.foreground=Selection Foreground +options.general.color.descriptor.notification.background=Notification background +options.general.color.descriptor.selection.background=Selection background +options.general.color.descriptor.selection.foreground=Selection foreground options.general.color.descriptor.caret=Caret options.general.color.descriptor.caret.row=Caret row options.general.color.descriptor.right.margin=Right margin @@ -118,8 +119,8 @@ options.general.color.descriptor.indent.guide.selected=Selected vertical indent options.general.color.descriptor.line.number=Line number options.general.color.descriptor.vcs.annotations=VCS annotations options.general.color.descriptor.vcs.annotations.merged=VCS annotations (merged from) -options.general.color.descriptor.folding.outline=Folding outline -options.general.color.descriptor.selected.folding.outline=Selected folding outline +options.general.color.descriptor.tearline=Tear line +options.general.color.descriptor.tearline.selected=Selected tear line options.general.color.descriptor.added.lines=Added lines options.general.color.descriptor.modified.lines=Modified lines options.general.color.descriptor.console.background=Console background diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml index 73e39badc00b..50532f06a4f2 100644 --- a/platform/platform-resources/src/DefaultColorSchemesManager.xml +++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml @@ -11,6 +11,8 @@