diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 238a794759f4..1edb4b3d8954 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -50,7 +50,8 @@ import com.intellij.execution.configurations.CommandLineState; import com.intellij.execution.configurations.RemoteConnection; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfileState; -import com.intellij.execution.filters.ExceptionFilter; +import com.intellij.execution.filters.ExceptionFilters; +import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; @@ -1669,7 +1670,10 @@ public abstract class DebugProcessImpl implements DebugProcess { if (state instanceof CommandLineState) { final TextConsoleBuilder consoleBuilder = ((CommandLineState)state).getConsoleBuilder(); if (consoleBuilder != null) { - consoleBuilder.addFilter(new ExceptionFilter(session.getSearchScope())); + List filters = ExceptionFilters.getFilters(session.getSearchScope()); + for (Filter filter : filters) { + consoleBuilder.addFilter(filter); + } } } myExecutionResult = state.execute(executor, runner); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java index a024d125154f..fba455e7a9db 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java @@ -33,7 +33,8 @@ import com.intellij.debugger.ui.impl.watch.*; import com.intellij.execution.*; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.executors.DefaultDebugExecutor; -import com.intellij.execution.filters.ExceptionFilter; +import com.intellij.execution.filters.ExceptionFilters; +import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.runners.ExecutionEnvironment; @@ -498,7 +499,10 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos public void addThreadDump(List threads) { final Project project = getProject(); final TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project); - consoleBuilder.addFilter(new ExceptionFilter(myDebuggerSession.getSearchScope())); + List filters = ExceptionFilters.getFilters(myDebuggerSession.getSearchScope()); + for (Filter filter : filters) { + consoleBuilder.addFilter(filter); + } final ConsoleView consoleView = consoleBuilder.getConsole(); final DefaultActionGroup toolbarActions = new DefaultActionGroup(); final ThreadDumpPanel panel = new ThreadDumpPanel(project, consoleView, toolbarActions, threads); diff --git a/java/execution/impl/src/com/intellij/execution/filters/DefaultConsoleFiltersProvider.java b/java/execution/impl/src/com/intellij/execution/filters/DefaultConsoleFiltersProvider.java index 1f85d105a237..38041d3fc7b8 100644 --- a/java/execution/impl/src/com/intellij/execution/filters/DefaultConsoleFiltersProvider.java +++ b/java/execution/impl/src/com/intellij/execution/filters/DefaultConsoleFiltersProvider.java @@ -24,12 +24,16 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; +import java.util.List; + public class DefaultConsoleFiltersProvider implements ConsoleFilterProviderEx { public Filter[] getDefaultFilters(@NotNull Project project) { - return new Filter[]{new ExceptionFilter(project), new YourkitFilter(project)}; + return getDefaultFilters(project, GlobalSearchScope.allScope(project)); } public Filter[] getDefaultFilters(@NotNull Project project, @NotNull GlobalSearchScope scope) { - return new Filter[]{new ExceptionFilter(scope), new YourkitFilter(project)}; + List filters = ExceptionFilters.getFilters(scope); + filters.add(new YourkitFilter(project)); + return filters.toArray(new Filter[filters.size()]); } } \ No newline at end of file diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionBaseFilterFactory.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionBaseFilterFactory.java new file mode 100644 index 000000000000..ce12a88468d2 --- /dev/null +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionBaseFilterFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.psi.search.GlobalSearchScope; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/8/11 + * Time: 12:11 PM + */ +public class ExceptionBaseFilterFactory implements ExceptionFilterFactory { + @Override + public Filter create(GlobalSearchScope searchScope) { + return new ExceptionFilter(searchScope); + } +} diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java index 0d965a038ed1..38a8a0180084 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java @@ -15,135 +15,20 @@ */ package com.intellij.execution.filters; -import com.intellij.openapi.editor.colors.CodeInsightColors; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.Trinity; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; public class ExceptionFilter implements Filter, DumbAware { - private final Project myProject; - @NonNls private static final String AT = "at"; - private static final String AT_PREFIX = AT + " "; - private static final String STANDALONE_AT = " " + AT + " "; - private static final TextAttributes HYPERLINK_ATTRIBUTES = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES); - private final GlobalSearchScope mySearchScope; - - public ExceptionFilter(@NotNull final Project project) { - myProject = project; - mySearchScope = GlobalSearchScope.allScope(myProject); - } + private final GlobalSearchScope myScope; public ExceptionFilter(@NotNull final GlobalSearchScope scope) { - myProject = scope.getProject(); - mySearchScope = scope; - } - - @Nullable - static Trinity parseExceptionLine(final String line) { - int atIndex; - if (line.startsWith(AT_PREFIX)){ - atIndex = 0; - } - else{ - atIndex = line.indexOf(STANDALONE_AT); - if (atIndex < 0) { - atIndex = line.indexOf(AT_PREFIX); - } - if (atIndex < 0) return null; - } - - final int lparenthIndex = line.indexOf('(', atIndex); - if (lparenthIndex < 0) return null; - final int lastDotIndex = line.lastIndexOf('.', lparenthIndex); - if (lastDotIndex < 0 || lastDotIndex < atIndex) return null; - String className = line.substring(atIndex + AT.length() + 1, lastDotIndex).trim(); - - String methodName = line.substring(lastDotIndex + 1, lparenthIndex).trim(); - - final int rparenthIndex = line.indexOf(')', lparenthIndex); - if (rparenthIndex < 0) return null; - - return Trinity.create(className, methodName, new TextRange(lparenthIndex, rparenthIndex)); + myScope = scope; } public Result applyFilter(final String line, final int textEndOffset) { - final Trinity info = parseExceptionLine(line); - if (info == null) { - return null; - } - - String className = info.first; - final int dollarIndex = className.indexOf('$'); - if (dollarIndex >= 0){ - className = className.substring(0, dollarIndex); - } - - final int lparenthIndex = info.third.getStartOffset(); - final int rparenthIndex = info.third.getEndOffset(); - final String fileAndLine = line.substring(lparenthIndex + 1, rparenthIndex).trim(); - - final int colonIndex = fileAndLine.lastIndexOf(':'); - if (colonIndex < 0) return null; - - final String lineString = fileAndLine.substring(colonIndex + 1); - try{ - final int lineNumber = Integer.parseInt(lineString); - final PsiManager manager = PsiManager.getInstance(myProject); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(manager.getProject()); - PsiClass aClass = psiFacade.findClass(className, mySearchScope); - if (aClass == null) { - aClass = psiFacade.findClass(className, GlobalSearchScope.allScope(myProject)); - if (aClass == null) {//try to find class according to all dollars in package name - aClass = psiFacade.findClass(info.first, GlobalSearchScope.allScope(myProject)); - } - if (aClass == null) return null; - } - final PsiFile file = (PsiFile) aClass.getContainingFile().getNavigationElement(); - if (file == null) return null; - - /* - IDEADEV-4976: Some scramblers put something like SourceFile mock instead of real class name. - final String filePath = fileAndLine.substring(0, colonIndex).replace('/', File.separatorChar); - final int slashIndex = filePath.lastIndexOf(File.separatorChar); - final String shortFileName = slashIndex < 0 ? filePath : filePath.substring(slashIndex + 1); - if (!file.getName().equalsIgnoreCase(shortFileName)) return null; - */ - - final int textStartOffset = textEndOffset - line.length(); - - final int highlightStartOffset = textStartOffset + lparenthIndex + 1; - final int highlightEndOffset = textStartOffset + rparenthIndex; - VirtualFile virtualFile = file.getVirtualFile(); - final OpenFileHyperlinkInfo linkInfo = new OpenFileHyperlinkInfo(myProject, virtualFile, lineNumber - 1); - TextAttributes attributes = HYPERLINK_ATTRIBUTES.clone(); - if (!ProjectRootManager.getInstance(myProject).getFileIndex().isInContent(virtualFile)) { - Color color = UIUtil.getInactiveTextColor(); - attributes.setForegroundColor(color); - attributes.setEffectColor(color); - } - return new Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes); - } - catch(NumberFormatException e){ - return null; - } + ExceptionWorker worker = new ExceptionWorker(myScope.getProject(), myScope); + worker.execute(line, textEndOffset); + return worker.getResult(); } - -} \ No newline at end of file +} diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilterFactory.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilterFactory.java new file mode 100644 index 000000000000..fd57dfe7cf89 --- /dev/null +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilterFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.search.GlobalSearchScope; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/5/11 + * Time: 7:46 PM + */ +public interface ExceptionFilterFactory { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.exceptionFilter"); + + Filter create(final GlobalSearchScope searchScope); +} diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilters.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilters.java new file mode 100644 index 000000000000..2c79ed095130 --- /dev/null +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilters.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.psi.search.GlobalSearchScope; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/5/11 + * Time: 7:54 PM + */ +public class ExceptionFilters { + private ExceptionFilters() { + } + + public static List getFilters(final GlobalSearchScope searchScope) { + List filters = new ArrayList(); + ExceptionFilterFactory[] extensions = ExceptionFilterFactory.EP_NAME.getExtensions(); + for (ExceptionFilterFactory extension : extensions) { + filters.add(extension.create(searchScope)); + } + return filters; + } +} diff --git a/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java b/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java new file mode 100644 index 000000000000..b3b653dea8c1 --- /dev/null +++ b/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java @@ -0,0 +1,278 @@ +/* + * Copyright 2000-2011 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.vcs.contentAnnotation; + +import com.intellij.execution.filters.ExceptionWorker; +import com.intellij.execution.filters.Filter; +import com.intellij.execution.filters.FilterMixin; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.diff.DiffColors; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.localVcs.UpToDateLineNumberProvider; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.impl.UpToDateLineNumberProviderImpl; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.Consumer; +import com.intellij.util.SmartList; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/5/11 + * Time: 8:39 PM + */ +public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin { + private final Project myProject; + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationExceptionFilter"); + private final GlobalSearchScope myScope; + + public VcsContentAnnotationExceptionFilter(GlobalSearchScope scope) { + myScope = scope; + myProject = scope.getProject(); + } + + private static class MyAdditionalHighlight extends AdditionalHighlight { + private MyAdditionalHighlight(int start, int end) { + super(start, end); + } + + @Override + public TextAttributes getTextAttributes(@Nullable TextAttributes source) { + EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); + final TextAttributes changedColor = globalScheme.getAttributes(DiffColors.DIFF_MODIFIED); + if (source == null) { + TextAttributes atts = + globalScheme.getAttributes(CodeInsightColors.CLASS_NAME_ATTRIBUTES).clone(); + atts.setBackgroundColor(changedColor.getBackgroundColor()); + return atts; + } + TextAttributes clone = source.clone(); + clone.setBackgroundColor(changedColor.getBackgroundColor()); + return clone; + } + } + + @Override + public void applyHeavyFilter(final Document copiedFragment, + int startOffset, + int startLineNumber, + Consumer consumer) { + VcsContentAnnotation vcsContentAnnotation = VcsContentAnnotationImpl.getInstance(myProject); + final LocalChangesCorrector localChangesCorrector = new LocalChangesCorrector(myProject); + Trinity previousLineResult = null; + + for (int i = 0; i < copiedFragment.getLineCount(); i++) { + final int lineStartOffset = copiedFragment.getLineStartOffset(i); + final int lineEndOffset = copiedFragment.getLineEndOffset(i); + final ExceptionWorker worker = new ExceptionWorker(myProject, myScope); + final String[] lineText = new String[1]; + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + lineText[0] = copiedFragment.getText(new TextRange(lineStartOffset, lineEndOffset)); + worker.execute(lineText[0], lineEndOffset); + } + }); + if (worker.getResult() != null) { + VirtualFile vf = worker.getFile().getVirtualFile(); + if (localChangesCorrector.isFileAlreadyIdentifiedAsChanged(vf) || ChangeListManager.isFileChanged(myProject, vf) || + vcsContentAnnotation.fileRecentlyChanged(vf)) { + final Document document = getDocumentForFile(worker); + if (document == null) return; + + int startFileOffset = worker.getInfo().getThird().getStartOffset(); + int idx = lineText[0].indexOf(':', startFileOffset); + int endIdx = idx == -1 ? worker.getInfo().getThird().getEndOffset() : idx; + consumer.consume(new MyAdditionalHighlight(startOffset + lineStartOffset + startFileOffset + 1, startOffset + lineStartOffset + endIdx)); + + // also check method + final List ranges = findMethodRange(worker, document, previousLineResult); + if (ranges != null) { + boolean methodChanged = false; + for (TextRange range : ranges) { + if (localChangesCorrector.isRangeChangedLocally(vf, document, range)) { + methodChanged = true; + break; + } + final TextRange correctedRange = localChangesCorrector.getCorrectedRange(vf, document, range); + if (vcsContentAnnotation.intervalRecentlyChanged(vf, correctedRange)) { + methodChanged = true; + break; + } + } + if (methodChanged) { + consumer.consume(new MyAdditionalHighlight(startOffset + lineStartOffset + worker.getInfo().getSecond().getStartOffset(), + startOffset + lineStartOffset + worker.getInfo().getSecond().getEndOffset())); + } + } + } + } + previousLineResult = worker.getResult() == null ? null : + new Trinity(worker.getPsiClass(), worker.getFile(), worker.getMethod()); + } + } + + private static class LocalChangesCorrector { + private final Map myRecentlyChanged; + private final Project myProject; + + private LocalChangesCorrector(final Project project) { + myProject = project; + myRecentlyChanged = new HashMap(); + } + + public boolean isFileAlreadyIdentifiedAsChanged(final VirtualFile vf) { + return myRecentlyChanged.containsKey(vf); + } + + public boolean isRangeChangedLocally(final VirtualFile vf, final Document document, final TextRange range) { + final UpToDateLineNumberProvider provider = getProvider(vf, document); + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return provider.isRangeChanged(range.getStartOffset(), range.getEndOffset()); + } + }); + } + + public TextRange getCorrectedRange(final VirtualFile vf, final Document document, final TextRange range) { + final UpToDateLineNumberProvider provider = getProvider(vf, document); + if (provider == null) return range; + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public TextRange compute() { + return new TextRange(provider.getLineNumber(range.getStartOffset()), provider.getLineNumber(range.getEndOffset())); + } + }); + } + + private UpToDateLineNumberProvider getProvider(VirtualFile vf, Document document) { + UpToDateLineNumberProvider provider = myRecentlyChanged.get(vf); + if (provider == null) { + provider = new UpToDateLineNumberProviderImpl(document, myProject); + myRecentlyChanged.put(vf, provider); + } + return provider; + } + } + + private Document getDocumentForFile(final ExceptionWorker worker) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Document compute() { + final Document document = FileDocumentManager.getInstance().getDocument(worker.getFile().getVirtualFile()); + if (document == null) { + LOG.info("can not get document for file: " + worker.getFile().getVirtualFile()); + return null; + } + return document; + } + }); + } + + /* final UpToDateLineNumberProvider getUpToDateLineNumber = new UpToDateLineNumberProviderImpl(editor.getDocument(), project, upToDateContent); + /**/ + + // line numbers + private List findMethodRange(final ExceptionWorker worker, final Document document, final Trinity previousLineResult) { + return ApplicationManager.getApplication().runReadAction(new Computable>() { + @Override + public List compute() { + List ranges = getTextRangeForMethod(worker, previousLineResult); + if (ranges == null) return null; + final List result = new ArrayList(); + for (TextRange range : ranges) { + result.add(new TextRange(document.getLineNumber(range.getStartOffset()), + document.getLineNumber(range.getEndOffset()))); + } + return result; + } + }); + } + + // null - check all + @Nullable + private List selectMethod(final PsiMethod[] methods, final Trinity previousLineResult) { + if (previousLineResult == null || previousLineResult.getThird() == null) return null; + + final List result = new SmartList(); + for (final PsiMethod method : methods) { + method.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitCallExpression(PsiCallExpression callExpression) { + final PsiMethod resolved = callExpression.resolveMethod(); + if (resolved != null) { + if (resolved.getName().equals(previousLineResult.getThird())) { + result.add(method); + } + } + } + }); + } + + return result; + } + + private List getTextRangeForMethod(final ExceptionWorker worker, Trinity previousLineResult) { + String method = worker.getMethod(); + PsiClass psiClass = worker.getPsiClass(); + PsiMethod[] methods; + if (method.contains("")) { + // constructor + methods = psiClass.getConstructors(); + } else if (method.contains("$")) { + // access$100 + return null; + } else { + methods = psiClass.findMethodsByName(method, false); + } + if (methods.length > 0) { + if (methods.length == 1) { + final TextRange range = methods[0].getTextRange(); + return Collections.singletonList(range); + } else { + List selectedMethods = selectMethod(methods, previousLineResult); + final List toIterate = selectedMethods == null ? Arrays.asList(methods) : selectedMethods; + final List result = new ArrayList(); + for (PsiMethod psiMethod : toIterate) { + result.add(psiMethod.getTextRange()); + } + return result; + } + } + return null; + } + + @Override + public Result applyFilter(String line, int entireLength) { + return null; + } +} diff --git a/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilterFactory.java b/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilterFactory.java new file mode 100644 index 000000000000..fc000c8b57f3 --- /dev/null +++ b/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilterFactory.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2011 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.vcs.contentAnnotation; + +import com.intellij.execution.filters.ExceptionFilterFactory; +import com.intellij.execution.filters.Filter; +import com.intellij.psi.search.GlobalSearchScope; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/5/11 + * Time: 8:03 PM + */ +public class VcsContentAnnotationExceptionFilterFactory implements ExceptionFilterFactory { + @Override + public Filter create(GlobalSearchScope searchScope) { + return new VcsContentAnnotationExceptionFilter(searchScope); + } +} diff --git a/java/java-impl/src/com/intellij/unscramble/ThreadDumpPanel.java b/java/java-impl/src/com/intellij/unscramble/ThreadDumpPanel.java index 90921e32e1fb..0a87d9541f09 100644 --- a/java/java-impl/src/com/intellij/unscramble/ThreadDumpPanel.java +++ b/java/java-impl/src/com/intellij/unscramble/ThreadDumpPanel.java @@ -89,7 +89,8 @@ public class ThreadDumpPanel extends JPanel { }); toolbarActions.add(new CopyToClipboardAction(threadDump, project)); toolbarActions.add(new SortThreadsAction()); - add(ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarActions,false).getComponent(), BorderLayout.WEST); + //toolbarActions.add(new ShowRecentlyChanged()); + add(ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarActions, false).getComponent(), BorderLayout.WEST); final Splitter splitter = new Splitter(false, 0.3f); splitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myThreadList)); diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java new file mode 100644 index 000000000000..e3a57cd722bc --- /dev/null +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java @@ -0,0 +1,198 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +/** +* Created by IntelliJ IDEA. +* User: Irina.Chernushina +* Date: 8/5/11 +* Time: 8:36 PM +* To change this template use File | Settings | File Templates. +*/ +public class ExceptionWorker { + @NonNls private static final String AT = "at"; + private static final String AT_PREFIX = AT + " "; + private static final String STANDALONE_AT = " " + AT + " "; + + private static final TextAttributes HYPERLINK_ATTRIBUTES = EditorColorsManager + .getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES); + + private final Project myProject; + private final GlobalSearchScope mySearchScope; + private Filter.Result myResult; + private PsiClass myClass; + private PsiFile myFile; + private String myMethod; + private Trinity myInfo; + + public ExceptionWorker(Project project, final GlobalSearchScope searchScope) { + myProject = project; + mySearchScope = searchScope; + } + + public void execute(final String line, final int textEndOffset) { + myInfo = parseExceptionLine(line); + if (myInfo == null) { + return; + } + + myMethod = myInfo.getSecond().substring(line); + String className = myInfo.first.substring(line).trim(); + final int dollarIndex = className.indexOf('$'); + if (dollarIndex >= 0){ + className = className.substring(0, dollarIndex); + } + + final int lparenthIndex = myInfo.third.getStartOffset(); + final int rparenthIndex = myInfo.third.getEndOffset(); + final String fileAndLine = line.substring(lparenthIndex + 1, rparenthIndex).trim(); + + final int colonIndex = fileAndLine.lastIndexOf(':'); + if (colonIndex < 0) return; + + final String lineString = fileAndLine.substring(colonIndex + 1); + try{ + final int lineNumber = Integer.parseInt(lineString); + final PsiManager manager = PsiManager.getInstance(myProject); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(manager.getProject()); + myClass = psiFacade.findClass(className, mySearchScope); + if (myClass == null) { + myClass = psiFacade.findClass(className, GlobalSearchScope.allScope(myProject)); + if (myClass == null) {//try to find class according to all dollars in package name + myClass = psiFacade.findClass(className, GlobalSearchScope.allScope(myProject)); + } + if (myClass == null) return; + } + myFile = (PsiFile) myClass.getContainingFile().getNavigationElement(); + if (myFile == null) return; + + /* + IDEADEV-4976: Some scramblers put something like SourceFile mock instead of real class name. + final String filePath = fileAndLine.substring(0, colonIndex).replace('/', File.separatorChar); + final int slashIndex = filePath.lastIndexOf(File.separatorChar); + final String shortFileName = slashIndex < 0 ? filePath : filePath.substring(slashIndex + 1); + if (!file.getName().equalsIgnoreCase(shortFileName)) return null; + */ + + final int textStartOffset = textEndOffset - line.length(); + + final int highlightStartOffset = textStartOffset + lparenthIndex + 1; + final int highlightEndOffset = textStartOffset + rparenthIndex; + VirtualFile virtualFile = myFile.getVirtualFile(); + final OpenFileHyperlinkInfo linkInfo = new OpenFileHyperlinkInfo(myProject, virtualFile, lineNumber - 1); + TextAttributes attributes = HYPERLINK_ATTRIBUTES.clone(); + if (!ProjectRootManager.getInstance(myProject).getFileIndex().isInContent(virtualFile)) { + Color color = UIUtil.getInactiveTextColor(); + attributes.setForegroundColor(color); + attributes.setEffectColor(color); + } + myResult = new Filter.Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes); + } + catch(NumberFormatException e){ + // + } + } + + public Filter.Result getResult() { + return myResult; + } + + public PsiClass getPsiClass() { + return myClass; + } + + public String getMethod() { + return myMethod; + } + + public PsiFile getFile() { + return myFile; + } + + public Trinity getInfo() { + return myInfo; + } + + @Nullable + static Trinity parseExceptionLine(final String line) { + int atIndex; + if (line.startsWith(AT_PREFIX)){ + atIndex = 0; + } + else{ + atIndex = line.indexOf(STANDALONE_AT); + if (atIndex < 0) { + atIndex = line.indexOf(AT_PREFIX); + } + if (atIndex < 0) return null; + } + + final int lparenthIndex = line.indexOf('(', atIndex); + if (lparenthIndex < 0) return null; + final int lastDotIndex = line.lastIndexOf('.', lparenthIndex); + if (lastDotIndex < 0 || lastDotIndex < atIndex) return null; + + final int rparenthIndex = line.indexOf(')', lparenthIndex); + if (rparenthIndex < 0) return null; + + // class, method, link + return Trinity.create(adjustedRange(line, atIndex + AT.length() + 1, lastDotIndex), + adjustedRange(line, lastDotIndex + 1, lparenthIndex), new TextRange(lparenthIndex, rparenthIndex)); + } + + private static TextRange adjustedRange(final String line, final int start, final int end) { + String sub = line.substring(start, end); + return new TextRange(start, end - spacesEnd(sub)); + } + + private static int spacesStart(final String s) { + int cnt = 0; + for (int i = 0; i < s.length(); i++) { + final char c = s.charAt(i); + if (! Character.isSpaceChar(c)) return cnt; + ++ cnt; + } + return 0; + } + private static int spacesEnd(final String s) { + int cnt = 0; + for (int i = s.length() - 1; i >= 0; i--) { + final char c = s.charAt(i); + if (! Character.isSpaceChar(c)) return cnt; + ++ cnt; + } + return 0; + } +} diff --git a/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java b/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java index 67bfb51c47ed..01ca873f687a 100644 --- a/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java +++ b/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java @@ -15,15 +15,18 @@ */ package com.intellij.execution.filters; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; +import com.intellij.util.Consumer; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -public class CompositeFilter implements Filter { +public class CompositeFilter implements Filter, FilterMixin { private final List myFilters = new ArrayList(); + private boolean myIsAnyHeavy; private final DumbService myDumbService; public CompositeFilter(Project project) { @@ -48,11 +51,34 @@ public class CompositeFilter implements Filter { return null; } + @Override + public void applyHeavyFilter(Document copiedFragment, + int startOffset, + int startLineNumber, + Consumer consumer) { + final boolean dumb = myDumbService.isDumb(); + List filters = myFilters; + int count = filters.size(); + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < count; i++) { + Filter filter = filters.get(i); + if (! (filter instanceof FilterMixin)) continue; + if (!dumb || DumbService.isDumbAware(filter)) { + ((FilterMixin) filter).applyHeavyFilter(copiedFragment, startOffset, startLineNumber, consumer); + } + } + } + public boolean isEmpty() { return myFilters.isEmpty(); } + public boolean isAnyHeavy() { + return myIsAnyHeavy; + } + public void addFilter(final Filter filter) { myFilters.add(filter); + myIsAnyHeavy |= filter instanceof FilterMixin; } -} \ No newline at end of file +} diff --git a/platform/lang-api/src/com/intellij/execution/filters/Filter.java b/platform/lang-api/src/com/intellij/execution/filters/Filter.java index 264792ec8723..83ef58fd741f 100644 --- a/platform/lang-api/src/com/intellij/execution/filters/Filter.java +++ b/platform/lang-api/src/com/intellij/execution/filters/Filter.java @@ -44,6 +44,7 @@ public interface Filter { /** * Filters line by creating an instance of {@link Result}. * + * * @param line * The line to be filtered. Note that the line must contain a line * separator at the end. diff --git a/platform/lang-api/src/com/intellij/execution/filters/FilterMixin.java b/platform/lang-api/src/com/intellij/execution/filters/FilterMixin.java new file mode 100644 index 000000000000..c4b4f61b5e5d --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/filters/FilterMixin.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.Nullable; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/3/11 + * Time: 4:50 PM + */ +public interface FilterMixin { + @Nullable + void applyHeavyFilter(Document copiedFragment, int startOffset, int startLineNumber, Consumer consumer); + + abstract class AdditionalHighlight { + private final int myStart; + private final int myEnd; + + public AdditionalHighlight(int start, int end) { + myStart = start; + myEnd = end; + } + + public int getStart() { + return myStart; + } + + public int getEnd() { + return myEnd; + } + + public abstract TextAttributes getTextAttributes(@Nullable final TextAttributes source); + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index c98211693584..adcd00f0678e 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -41,11 +41,11 @@ import com.intellij.openapi.editor.actions.ToggleUseSoftWrapsToolbarAction; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.event.*; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.editor.ex.FoldingModelEx; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.HighlighterClient; import com.intellij.openapi.editor.highlighter.HighlighterIterator; +import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; @@ -60,10 +60,7 @@ import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; @@ -91,7 +88,7 @@ import java.util.*; import java.util.List; import java.util.concurrent.CopyOnWriteArraySet; -public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableConsoleView, DataProvider, OccurenceNavigator { +public class ConsoleViewImpl implements ConsoleView, ObservableConsoleView, DataProvider, OccurenceNavigator { @NonNls private static final String CONSOLE_VIEW_POPUP_MENU = "ConsoleView.PopupMenu"; private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.ConsoleViewImpl"); @@ -115,12 +112,17 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo private Computable myStateForUpdate; private final Alarm mySpareTimeAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, this); + @Nullable + private final Alarm myHeavyAlarm; private final CopyOnWriteArraySet myListeners = new CopyOnWriteArraySet(); private final ArrayList customActions = new ArrayList(); private final ConsoleBuffer myBuffer = new ConsoleBuffer(); private boolean myUpdateFoldingsEnabled = true; private EditorHyperlinkSupport myHyperlinks; + private MyDiffContainer myJLayeredPane; + private JPanel myMainPanel; + private final Runnable myFinishProgress; @TestOnly public Editor getEditor() { @@ -272,7 +274,6 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo protected ConsoleViewImpl(final Project project, GlobalSearchScope searchScope, boolean viewer, FileType fileType, @NotNull final ConsoleState initialState) { - super(new BorderLayout()); isViewer = viewer; myState = initialState; myPsiDisposedCheck = new DisposedPsiManagerCheck(project); @@ -289,8 +290,19 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo myPredefinedMessageFilter.addFilter(filter); } } + if (myPredefinedMessageFilter.isAnyHeavy()) { + myHeavyAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, this); + } else { + myHeavyAlarm = null; + } Disposer.register(project, this); + myFinishProgress = new Runnable() { + @Override + public void run() { + myJLayeredPane.finishUpdating(); + } + }; } public void attachToProcess(final ProcessHandler processHandler) { @@ -368,17 +380,27 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } }, 100, - ModalityState.stateForComponent(this) + ModalityState.stateForComponent(myJLayeredPane) ); } } + public void addToolbar(JComponent component, String constraint) { + myMainPanel.add(component, constraint); + } + public JComponent getComponent() { + if (myMainPanel == null) { + myMainPanel = new JPanel(new BorderLayout()); + myJLayeredPane = new MyDiffContainer(myMainPanel, "Checking recent changes..."); + } + if (myEditor == null) { myEditor = createEditor(); myHyperlinks = new EditorHyperlinkSupport(myEditor, myProject); requestFlushImmediately(); - add(createCenterComponent(), BorderLayout.CENTER); + myMainPanel.add(createCenterComponent(), BorderLayout.CENTER); + myEditor.getDocument().addDocumentListener(new DocumentAdapter() { public void documentChanged(DocumentEvent e) { @@ -412,7 +434,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } }); } - return this; + return myJLayeredPane; } protected JComponent createCenterComponent() { @@ -436,6 +458,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo myEditor = null; myHyperlinks = null; } + myJLayeredPane.dispose(); } protected void disposeEditor() { @@ -476,7 +499,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } private ModalityState getStateForUpdate() { - return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(this); + return myStateForUpdate != null ? myStateForUpdate.compute() : ModalityState.stateForComponent(myJLayeredPane); } private void requestFlushImmediately() { @@ -789,6 +812,43 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo if (canHighlightHyperlinks) { myHyperlinks.highlightHyperlinks(myCustomFilter, myPredefinedMessageFilter, line1, endLine); } + + if (myPredefinedMessageFilter.isAnyHeavy()) { + final int startLine = Math.max(0, line1); + + final Document document = getEditor().getDocument(); + final Document documentCopy = new DocumentImpl(true); + final int startOffset = document.getLineStartOffset(startLine); + documentCopy.setText(new String(document.getText(new TextRange(startOffset, document.getLineEndOffset(endLine))))); + documentCopy.setReadOnly(true); + + myJLayeredPane.startUpdating(); + myHeavyAlarm.addRequest(new Runnable() { + @Override + public void run() { + myPredefinedMessageFilter.applyHeavyFilter(documentCopy, startOffset, startLine, new Consumer() { + @Override + public void consume(final FilterMixin.AdditionalHighlight additionalHighlight) { + SwingUtilities.invokeLater( + new Runnable() { + @Override + public void run() { + myFlushAlarm.addRequest(new Runnable() { + @Override + public void run() { + myHyperlinks.adjustHighlighters(Collections.singletonList(additionalHighlight)); + } + }, 0); + } + }); + } + }); + if (myHeavyAlarm.getActiveRequestCount() == 0) { + SwingUtilities.invokeLater(myFinishProgress); + } + } + }, 0); + } if (myUpdateFoldingsEnabled) { updateFoldings(line1, endLine, true); } @@ -1066,7 +1126,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo s = (String)content.getTransferData(DataFlavor.stringFlavor); } catch (Exception e) { - consoleView.getToolkit().beep(); + consoleView.getComponent().getToolkit().beep(); } if (s == null) return; Editor editor = consoleView.myEditor; @@ -1279,6 +1339,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo consoleActions[1] = nextAction; consoleActions[2] = switchSoftWrapsAction; consoleActions[3] = autoScrollToTheEndAction; + //consoleActions[4] = new ShowRecentlyChanged(); for (int i = 0; i < customActions.size(); ++i) { consoleActions[i + 4] = customActions.get(i); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/MyDiffContainer.java b/platform/lang-impl/src/com/intellij/execution/impl/MyDiffContainer.java new file mode 100644 index 000000000000..7724d6803bbb --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/impl/MyDiffContainer.java @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.impl; + +import com.intellij.openapi.Disposable; +import com.intellij.util.ui.AbstractLayoutManager; +import com.intellij.util.ui.AnimatedIcon; +import com.intellij.util.ui.AsyncProcessIcon; +import com.intellij.util.ui.UIUtil; + +import javax.swing.*; +import java.awt.*; + +/** +* Created by IntelliJ IDEA. +* @author amakeev +* @author Irina.Chernushina +* Date: 8/8/11 +* Time: 3:13 PM +*/ +public class MyDiffContainer extends JLayeredPane implements Disposable { + private AnimatedIcon myIcon = new AsyncProcessIcon(this.getClass().getName()); + + private JComponent myContent; + private JComponent myLoadingPanel; + private final JLabel myJLabel; + + public MyDiffContainer(JComponent content, final String text) { + setLayout(new MyOverlayLayout()); + myContent = content; + myLoadingPanel = new JPanel(new MyPanelLayout()); + myLoadingPanel.setOpaque(false); + myLoadingPanel.add(myIcon); + myJLabel = new JLabel(text); + myJLabel.setForeground(UIUtil.getInactiveTextColor()); + myLoadingPanel.add(myJLabel); + + add(myContent); + add(myLoadingPanel, JLayeredPane.POPUP_LAYER); + + finishUpdating(); + } + + public void dispose() { + myIcon.dispose(); + } + + public void startUpdating() { + myLoadingPanel.setVisible(true); + myIcon.resume(); + } + + public void finishUpdating() { + myIcon.suspend(); + myLoadingPanel.setVisible(false); + } + + private class MyOverlayLayout extends AbstractLayoutManager { + public void layoutContainer(Container parent) { + myContent.setBounds(0, 0, getWidth(), getHeight()); + myLoadingPanel.setBounds(0, 0, getWidth(), getHeight()); + } + + public Dimension preferredLayoutSize(Container parent) { + return myContent.getPreferredSize(); + } + } + + private class MyPanelLayout extends AbstractLayoutManager { + public void layoutContainer(Container parent) { + Dimension size = myIcon.getPreferredSize(); + Dimension preferredSize = myJLabel.getPreferredSize(); + int width = getWidth(); + int offset = width - size.width - 15 - preferredSize.width; + myIcon.setBounds(offset, 0, size.width, size.height); + myJLabel.setBounds(offset + size.width + 3, 0, preferredSize.width, size.height); + } + + public Dimension preferredLayoutSize(Container parent) { + return myContent.getPreferredSize(); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/unscramble/ShowRecentlyChanged.java b/platform/lang-impl/src/com/intellij/unscramble/ShowRecentlyChanged.java new file mode 100644 index 000000000000..678f8b44f9a0 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/unscramble/ShowRecentlyChanged.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2011 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.unscramble; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.configurable.VcsContentAnnotationConfigurable; + +/** +* Created by IntelliJ IDEA. +* User: Irina.Chernushina +* Date: 8/4/11 +* Time: 2:29 PM +* To change this template use File | Settings | File Templates. +*/ +public class ShowRecentlyChanged extends DumbAwareAction { + public ShowRecentlyChanged() { + super("Show recently changed", "Show recently changed", IconLoader.getIcon("/general/copy.png")); + } + + @Override + public void actionPerformed(AnActionEvent e) { + if (! enabled(e)) return; + Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); + VcsContentAnnotationConfigurable configurable = new VcsContentAnnotationConfigurable(project); + ShowSettingsUtil.getInstance().editConfigurable(project, configurable); + // todo recalculate highlight + } + + private boolean enabled(AnActionEvent e) { + Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); + if (project == null) return false; + ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project); + if (! vcsManager.hasActiveVcss()) return false; + return true; + } + + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setEnabled(enabled(e)); + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java index 6e1fd9ca0f2c..22ae559d18ed 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java @@ -258,16 +258,4 @@ public class LoadingDecorator { frame.setBounds(300, 300, 300, 300); frame.show(); } - - - private static class MyLayeredPane extends JLayeredPane { - @Override - public void doLayout() { - super.doLayout(); - for (int i = 0; i < getComponentCount(); i++) { - final Component each = getComponent(i); - each.setBounds(0, 0, getWidth(), getHeight()); - } - } - } } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MyLayeredPane.java b/platform/platform-api/src/com/intellij/openapi/ui/MyLayeredPane.java new file mode 100644 index 000000000000..f0dce003be41 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/MyLayeredPane.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2011 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.ui; + +import javax.swing.*; +import java.awt.*; + +/** +* Created by IntelliJ IDEA. +* User: Irina.Chernushina +* Date: 8/4/11 +* Time: 3:59 PM +* To change this template use File | Settings | File Templates. +*/ +public class MyLayeredPane extends JLayeredPane { + @Override + public void doLayout() { + super.doLayout(); + for (int i = 0; i < getComponentCount(); i++) { + final Component each = getComponent(i); + if (each instanceof Icon) { + each.setBounds(0, 0, each.getWidth(), each.getHeight()); + } else { + each.setBounds(0, 0, getWidth(), getHeight()); + } + } + } +} diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index 9b8725ea98b7..49d7a30a7cf7 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -45,6 +45,7 @@ import java.util.Map; */ public class SimpleColoredComponent extends JComponent implements Accessible { private static final Logger LOG = Logger.getInstance("#com.intellij.ui.SimpleColoredComponent"); + public static final Color STYLE_SEARCH_MATCH_BACKGROUND = new Color(250, 250, 250, 140); private final ArrayList myFragments; private final ArrayList myAttributes; @@ -439,7 +440,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { if (!attributes.isSearchMatch()) { if (shouldDrawMacShadow()) { - g.setColor(new Color(250, 250, 250, 140)); + g.setColor(STYLE_SEARCH_MATCH_BACKGROUND); g.drawString(fragment, xOffset, textBaseline + 1); } diff --git a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java index 85832860109c..1b4645a66f3b 100644 --- a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java +++ b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java @@ -16,6 +16,7 @@ package com.intellij.execution.impl; import com.intellij.execution.filters.Filter; +import com.intellij.execution.filters.FilterMixin; import com.intellij.execution.filters.HyperlinkInfo; import com.intellij.ide.OccurenceNavigator; import com.intellij.openapi.editor.Document; @@ -33,7 +34,9 @@ import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.pom.Navigatable; +import com.intellij.util.BeforeAfter; import com.intellij.util.Consumer; +import com.intellij.util.SmartList; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,14 +53,18 @@ import java.util.List; public class EditorHyperlinkSupport { public static final Key OLD_HYPERLINK_TEXT_ATTRIBUTES = Key.create("OLD_HYPERLINK_TEXT_ATTRIBUTES"); private static final int HYPERLINK_LAYER = HighlighterLayer.SELECTION - 123; + private static final int HIGHLIGHT_LAYER = HighlighterLayer.SELECTION - 111; private static final int NO_INDEX = Integer.MIN_VALUE; private final Editor myEditor; private final Map myHighlighterToMessageInfoMap = new HashMap(); private int myLastIndex = NO_INDEX; + private final Consumer> myRefresher; + private final List myHighlighters; public EditorHyperlinkSupport(@NotNull final Editor editor, @NotNull final Project project) { myEditor = editor; + myHighlighters = new SmartList(); editor.addEditorMouseListener(new EditorMouseAdapter() { public void mouseReleased(final EditorMouseEvent e) { @@ -86,10 +93,78 @@ public class EditorHyperlinkSupport { } } ); + + myRefresher = new Consumer>() { + @Override + public void consume(BeforeAfter resultBeforeAfter) { + if (resultBeforeAfter.getBefore() == null) return; + final RangeHighlighter hyperlinkRange = findHyperlinkRange(resultBeforeAfter.getBefore().hyperlinkInfo); + if (hyperlinkRange != null) { + myHighlighterToMessageInfoMap.remove(hyperlinkRange); + } else { + final Iterator iterator = myHighlighters.iterator(); + while (iterator.hasNext()) { + final RangeHighlighter highlighter = iterator.next(); + if (highlighter.isValid() && containsOffset(resultBeforeAfter.getBefore().highlightStartOffset, highlighter)) { + iterator.remove(); + break; + } + } + } + + if (resultBeforeAfter.getAfter() != null) { + if (resultBeforeAfter.getAfter().hyperlinkInfo != null) { + addHyperlink(resultBeforeAfter.getAfter().highlightStartOffset, resultBeforeAfter.getAfter().highlightEndOffset, + resultBeforeAfter.getAfter().highlightAttributes, resultBeforeAfter.getAfter().hyperlinkInfo); + } else if (resultBeforeAfter.getAfter().highlightAttributes != null) { + addHighlighter(resultBeforeAfter.getAfter().highlightStartOffset, resultBeforeAfter.getAfter().highlightEndOffset, + resultBeforeAfter.getAfter().highlightAttributes); + } + } + } + }; + } + + public void adjustHighlighters(final List highlights) { + for (FilterMixin.AdditionalHighlight highlight : highlights) { + RangeHighlighter found = null; + for (RangeHighlighter rangeHighlighter : myHighlighterToMessageInfoMap.keySet()) { + if (rangeHighlighter.getStartOffset() <= highlight.getStart() && rangeHighlighter.getEndOffset() >= highlight.getEnd()) { + found = rangeHighlighter; + break; + } + } + if (found != null) { + TextAttributes textAttributes = highlight.getTextAttributes(found.getTextAttributes()); + final HyperlinkInfo hyperlinkInfo = myHighlighterToMessageInfoMap.remove(found); + if (found.getStartOffset() != highlight.getStart()) { + addHyperlink(found.getStartOffset(), highlight.getEnd(), found.getTextAttributes(), hyperlinkInfo); + } + if (found.getEndOffset() != highlight.getEnd()) { + addHyperlink(highlight.getEnd(), found.getEndOffset(), found.getTextAttributes(), hyperlinkInfo); + } + addHyperlink(highlight.getStart(), highlight.getEnd(), textAttributes, hyperlinkInfo); + myEditor.getMarkupModel().removeHighlighter(found); + return; + } + final Iterator iterator = myHighlighters.iterator(); + while (iterator.hasNext()) { + final RangeHighlighter highlighter = iterator.next(); + if (highlighter.getStartOffset() == highlight.getStart() && highlighter.getEndOffset() == highlight.getEnd()) { + iterator.remove(); + final TextAttributes textAttributes = highlight.getTextAttributes(highlighter.getTextAttributes()); + addHighlighter(highlight.getStart(), highlight.getEnd(), textAttributes); + return; + } + } + final TextAttributes textAttributes = highlight.getTextAttributes(null); + addHighlighter(highlight.getStart(), highlight.getEnd(), textAttributes); + } } public void clearHyperlinks() { myHighlighterToMessageInfoMap.clear(); + myHighlighters.clear(); myLastIndex = NO_INDEX; } @@ -171,12 +246,25 @@ public class EditorHyperlinkSupport { if (result == null) { result = predefinedMessageFilter.applyFilter(text, endOffset); } - if (result != null && result.hyperlinkInfo != null) { - addHyperlink(result.highlightStartOffset, result.highlightEndOffset, result.highlightAttributes, result.hyperlinkInfo); + if (result != null) { + if (result.hyperlinkInfo != null) { + addHyperlink(result.highlightStartOffset, result.highlightEndOffset, result.highlightAttributes, result.hyperlinkInfo); + } else if (result.highlightAttributes != null) { + addHighlighter(result.highlightStartOffset, result.highlightEndOffset, result.highlightAttributes); + } } } } + private void addHighlighter(int highlightStartOffset, int highlightEndOffset, TextAttributes highlightAttributes) { + final RangeHighlighter highlighter = myEditor.getMarkupModel().addRangeHighlighter(highlightStartOffset, + highlightEndOffset, + HIGHLIGHT_LAYER, + highlightAttributes, + HighlighterTargetArea.EXACT_RANGE); + myHighlighters.add(highlighter); + } + private static TextAttributes getHyperlinkAttributes() { return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES); } @@ -220,6 +308,7 @@ public class EditorHyperlinkSupport { }, i, ranges.size()); } + // todo fix link followed here! private static void linkFollowed(Editor editor, Collection ranges, final RangeHighlighter link) { MarkupModelEx markupModel = (MarkupModelEx)editor.getMarkupModel(); for (RangeHighlighter range : ranges) { @@ -237,6 +326,7 @@ public class EditorHyperlinkSupport { attributes.setEffectType(oldAttributes.getEffectType()); attributes.setEffectColor(oldAttributes.getEffectColor()); attributes.setForegroundColor(oldAttributes.getForegroundColor()); + attributes.setBackgroundColor(oldAttributes.getBackgroundColor()); markupModel.setRangeHighlighterAttributes(range, attributes); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index fd4aabc7bdc6..2c86e314ecfb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -384,19 +384,20 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark if (clip.height == 0) return; final Rectangle componentBounds = c.getBounds(); + final TextRange docRange = TextRange.create(0, getEditor().getDocument().getTextLength()); if (myCachedTrack == null || myCachedTrack.getHeight() != componentBounds.getHeight()) { myCachedTrack = new BufferedImage(componentBounds.width, componentBounds.height, BufferedImage.TYPE_INT_ARGB); - myDirtyRange = TextRange.create(0, getEditor().getDocument().getTextLength()); + myDirtyRange = docRange; paintTrackBasement(myCachedTrack.getGraphics(), new Rectangle(0, 0, componentBounds.width, componentBounds.height)); } if (myDirtyRange != null) { final Graphics2D imageGraphics = myCachedTrack.createGraphics(); - ((ApplicationImpl)ApplicationManager.getApplication()).editorPaintStart(); try { + myDirtyRange = myDirtyRange.intersection(docRange); repaint(imageGraphics, componentBounds.width, ERROR_ICON_WIDTH - 1, myDirtyRange.getStartOffset(), myDirtyRange.getEndOffset()); myDirtyRange = null; } diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 5b7c408c25be..b44e2be72b46 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -119,5 +119,6 @@ - + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 26aeee11a962..46314fd97894 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -226,4 +226,7 @@ + + + diff --git a/platform/platform-resources/src/componentSets/VCS.xml b/platform/platform-resources/src/componentSets/VCS.xml index 2f0f306727ef..4b06ef8b184e 100644 --- a/platform/platform-resources/src/componentSets/VCS.xml +++ b/platform/platform-resources/src/componentSets/VCS.xml @@ -106,5 +106,10 @@ com.intellij.openapi.vcs.impl.VcsBaseContentProvider com.intellij.openapi.vcs.impl.VcsFileStatusProvider + com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationSettings + com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationSettings + + com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotation + com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationImpl diff --git a/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java b/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java index a927e1ed9acc..bacb8ba9e42e 100644 --- a/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java +++ b/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java @@ -19,4 +19,6 @@ public interface UpToDateLineNumberProvider { int ABSENT_LINE_NUMBER = -1; int getLineNumber(int currentNumber); + boolean isLineChanged(int currentNumber); + boolean isRangeChanged(final int start, final int end); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/RichTextItem.java b/platform/vcs-api/src/com/intellij/openapi/vcs/RichTextItem.java new file mode 100644 index 000000000000..573558853e34 --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/RichTextItem.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2011 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.vcs; + +import com.intellij.ui.SimpleTextAttributes; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/3/11 + * Time: 12:56 PM + * To change this template use File | Settings | File Templates. + */ +public class RichTextItem { + private final String myText; + private final SimpleTextAttributes myTextAttributes; + + public RichTextItem(String text, SimpleTextAttributes textAttributes) { + myText = text; + myTextAttributes = textAttributes; + } + + public String getText() { + return myText; + } + + public SimpleTextAttributes getTextAttributes() { + return myTextAttributes; + } +} diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/FileAnnotation.java b/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/FileAnnotation.java index 43c890723391..e6acc734770e 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/FileAnnotation.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/FileAnnotation.java @@ -19,6 +19,7 @@ import com.intellij.openapi.vcs.history.VcsFileRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import org.jetbrains.annotations.Nullable; +import java.util.Date; import java.util.List; /** @@ -81,6 +82,9 @@ public interface FileAnnotation { @Nullable VcsRevisionNumber getLineRevisionNumber(int lineNumber); + @Nullable + Date getLineDate(int lineNumber); + /** * Get revision number for the line. */ diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListManager.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListManager.java index c19ae587f2e5..8147780363e9 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListManager.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeListManager.java @@ -150,4 +150,12 @@ public abstract class ChangeListManager implements ChangeListModification { public abstract void letGo(); public abstract String isFreezed(); public abstract boolean isFreezedWithNotification(@Nullable String modalTitle); + + public static boolean isFileChanged(final Project project, final VirtualFile vf) { + FileStatus status = getInstance(project).getStatus(vf); + if (status == null || FileStatus.NOT_CHANGED.equals(status) || FileStatus.UNKNOWN.equals(status) || FileStatus.IGNORED.equals(status)) { + return false; + } + return true; + } } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotation.java b/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotation.java new file mode 100644 index 000000000000..b39340ba32da --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotation.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2011 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.vcs.contentAnnotation; + +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.RichTextItem; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/3/11 + * Time: 12:50 PM + */ +public interface VcsContentAnnotation { + boolean fileRecentlyChanged(final VirtualFile vf); + + boolean intervalRecentlyChanged(VirtualFile file, final TextRange lineInterval); + + @Nullable + Details annotateLine(final VirtualFile vf, final Getter enclosingRange, final int lineNumber); + + class Details { + private final boolean myLineChanged; + // meaningful enclosing structure + private final boolean myMethodChanged; + private final boolean myFileChanged; + @Nullable + private final List myDetails; + + public Details(boolean lineChanged, boolean methodChanged, boolean fileChanged, List details) { + myLineChanged = lineChanged; + myMethodChanged = methodChanged; + myFileChanged = fileChanged; + myDetails = details; + } + + public boolean isLineChanged() { + return myLineChanged; + } + + public boolean isMethodChanged() { + return myMethodChanged; + } + + public boolean isFileChanged() { + return myFileChanged; + } + } +} diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationImpl.java b/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationImpl.java new file mode 100644 index 000000000000..f8394311bc54 --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationImpl.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2011 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.vcs.contentAnnotation; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.annotate.FileAnnotation; +import com.intellij.openapi.vcs.diff.DiffMixin; +import com.intellij.openapi.vcs.history.VcsRevisionDescription; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nullable; + +import java.util.Date; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/3/11 + * Time: 1:04 PM + */ +public class VcsContentAnnotationImpl implements VcsContentAnnotation { + private final Project myProject; + private final VcsContentAnnotationSettings mySettings; + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationImpl"); + + public static VcsContentAnnotation getInstance(final Project project) { + return ServiceManager.getService(project, VcsContentAnnotation.class); + } + + public VcsContentAnnotationImpl(Project project, VcsContentAnnotationSettings settings) { + myProject = project; + mySettings = settings; + } + + @Override + public boolean fileRecentlyChanged(VirtualFile vf) { + final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); + final AbstractVcs vcs = vcsManager.getVcsFor(vf); + if (vcs == null) return false; + if (vcs.getDiffProvider() instanceof DiffMixin) { + final VcsRevisionDescription description = ((DiffMixin)vcs.getDiffProvider()).getCurrentRevisionDescription(vf); + final Date date = description.getRevisionDate(); + return isRecent(date); + } + return false; + } + + private boolean isRecent(Date date) { + return date.getTime() > (System.currentTimeMillis() - mySettings.getLimit()); + } + + @Override + public boolean intervalRecentlyChanged(VirtualFile file, TextRange lineInterval) { + final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); + final AbstractVcs vcs = vcsManager.getVcsFor(file); + if (vcs == null) return false; + final FileAnnotation fileAnnotation; + try { + fileAnnotation = vcs.getCachingAnnotationProvider().annotate(file); + } + catch (VcsException e) { + LOG.info(e); + return false; + } + for (int i = lineInterval.getStartOffset(); i <= lineInterval.getEndOffset(); i++) { + Date lineDate = fileAnnotation.getLineDate(i); + if (lineDate != null && isRecent(lineDate)) return true; + } + return false; + } + + @Nullable + @Override + public Details annotateLine(final VirtualFile vf, final Getter enclosingRange, final int lineNumber) { + final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); + final AbstractVcs vcs = vcsManager.getVcsFor(vf); + if (vcs == null) return null; + if (vcs.getDiffProvider() instanceof DiffMixin) { + boolean fileRecent = false; + final VcsRevisionDescription description = ((DiffMixin)vcs.getDiffProvider()).getCurrentRevisionDescription(vf); + final Date date = description.getRevisionDate(); + if (isRecent(date)) { + fileRecent = true; + enclosingRange.get(); + } + return new Details(false, false, fileRecent, null); + } + return null; + } +} diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationSettings.java b/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationSettings.java new file mode 100644 index 000000000000..87228feb1dbf --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationSettings.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2011 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.vcs.contentAnnotation; + +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/3/11 + * Time: 1:13 PM + */ +@State( + name = "VcsContentAnnotationSettings", + storages = {@Storage( file = "$WORKSPACE_FILE$")}) +public class VcsContentAnnotationSettings implements PersistentStateComponent { + // approx + public static final int ourMaxDays = 31; + public final static long ourAbsoluteLimit = ourMaxDays * 24 * 60 * 60 * 1000L; + private State myState = new State(); + + { + myState.myLimit = ourAbsoluteLimit; + } + + public static VcsContentAnnotationSettings getInstance(final Project project) { + return ServiceManager.getService(project, VcsContentAnnotationSettings.class); + } + + public static class State { + public boolean myShow = true; + public long myLimit; + } + + @Override + public State getState() { + return myState; + } + + @Override + public void loadState(State state) { + myState = state; + } + + public long getLimit() { + return myState.myLimit; + } + + public long getLimitDays() { + return myState.myLimit / (24 * 60 * 60 * 1000L); + } + + public void setLimit(long limit) { + myState.myLimit = limit * 24 * 60 * 60 * 1000L; + } + + public boolean isShow() { + return myState.myShow; + } + + public void setShow(final boolean value) { + myState.myShow = value; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java index abb32edb3356..7f609421585a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java @@ -188,7 +188,7 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware, Ann final AbstractVcs vcs) { final String upToDateContent = fileAnnotation.getAnnotatedContent(); - final UpToDateLineNumberProvider getUpToDateLineNumber = new UpToDateLineNumberProviderImpl(editor.getDocument(), project, upToDateContent); + final UpToDateLineNumberProvider getUpToDateLineNumber = new UpToDateLineNumberProviderImpl(editor.getDocument(), project); editor.getGutter().closeAllAnnotations(); // be careful, not proxies but original items are put there (since only their presence not behaviour is important) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsContentAnnotationConfigurable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsContentAnnotationConfigurable.java new file mode 100644 index 000000000000..f2d9f4f4b5f4 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsContentAnnotationConfigurable.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2011 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.vcs.configurable; + +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationSettings; +import org.jetbrains.annotations.Nls; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Created by IntelliJ IDEA. + * User: Irina.Chernushina + * Date: 8/4/11 + * Time: 2:05 PM + */ +public class VcsContentAnnotationConfigurable implements Configurable { + private final Project myProject; + private JCheckBox myHighlightRecentlyChanged; + private JSpinner myHighlightInterval; + + public VcsContentAnnotationConfigurable(Project project) { + myProject = project; + } + + @Nls + @Override + public String getDisplayName() { + return "Show recently changed"; + } + + @Override + public Icon getIcon() { + return null; + } + + @Override + public String getHelpTopic() { + return null; + } + + @Override + public JComponent createComponent() { + JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT)); + myHighlightRecentlyChanged = new JCheckBox("Show changed in last"); + myHighlightRecentlyChanged.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + myHighlightInterval = new JSpinner(new SpinnerNumberModel(1, 1, VcsContentAnnotationSettings.ourMaxDays, 1)); + wrapper.add(myHighlightRecentlyChanged); + wrapper.add(myHighlightInterval); + wrapper.add(new JLabel("days")); + + myHighlightRecentlyChanged.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + myHighlightInterval.setEnabled(myHighlightRecentlyChanged.isSelected()); + } + }); + return wrapper; + } + + @Override + public boolean isModified() { + VcsContentAnnotationSettings settings = VcsContentAnnotationSettings.getInstance(myProject); + if (myHighlightRecentlyChanged.isSelected() != settings.isShow()) return true; + if (! Comparing.equal(myHighlightInterval.getValue(), settings.getLimitDays())) return true; + return false; + } + + @Override + public void apply() throws ConfigurationException { + VcsContentAnnotationSettings settings = VcsContentAnnotationSettings.getInstance(myProject); + settings.setShow(myHighlightRecentlyChanged.isSelected()); + settings.setLimit(((Number) myHighlightInterval.getValue()).intValue()); + } + + @Override + public void reset() { + VcsContentAnnotationSettings settings = VcsContentAnnotationSettings.getInstance(myProject); + myHighlightRecentlyChanged.setSelected(settings.isShow()); + myHighlightInterval.setValue(settings.getLimitDays()); + myHighlightInterval.setEnabled(myHighlightRecentlyChanged.isSelected()); + } + + @Override + public void disposeUIResources() { + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsDirectoryConfigurationPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsDirectoryConfigurationPanel.java index f2b0f790866f..4e5e87c13f45 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsDirectoryConfigurationPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsDirectoryConfigurationPanel.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.configurable; import com.intellij.CommonBundle; import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.AbstractVcs; @@ -134,6 +135,7 @@ public class VcsDirectoryConfigurationPanel extends PanelWithButtons implements private JButton myEditButton; private JButton myRemoveButton; private final Map myAllVcss; + private VcsContentAnnotationConfigurable myRecentlyChangedConfigurable; private final boolean myIsDisabled; public VcsDirectoryConfigurationPanel(final Project project) { @@ -147,6 +149,7 @@ public class VcsDirectoryConfigurationPanel extends PanelWithButtons implements } myDirectoryMappingTable = new TableView(); + initPanel(); initializeModel(); final JComboBox comboBox = myVcsComboBox.getComboBox(); @@ -172,7 +175,6 @@ public class VcsDirectoryConfigurationPanel extends PanelWithButtons implements updateButtons(); } }); - initPanel(); updateButtons(); if (myIsDisabled) { myDirectoryMappingTable.setEnabled(false); @@ -187,6 +189,8 @@ public class VcsDirectoryConfigurationPanel extends PanelWithButtons implements } myModel = new ListTableModel(new ColumnInfo[]{DIRECTORY, VCS_SETTING}, mappings, 0); myDirectoryMappingTable.setModel(myModel); + + myRecentlyChangedConfigurable.reset(); } private void updateButtons() { @@ -273,19 +277,26 @@ public class VcsDirectoryConfigurationPanel extends PanelWithButtons implements } protected JComponent createMainComponent() { - return ScrollPaneFactory.createScrollPane(myDirectoryMappingTable); + JPanel panel = new JPanel(new BorderLayout()); + final JScrollPane scroll = ScrollPaneFactory.createScrollPane(myDirectoryMappingTable); + panel.add(scroll, BorderLayout.CENTER); + myRecentlyChangedConfigurable = new VcsContentAnnotationConfigurable(myProject); + panel.add(myRecentlyChangedConfigurable.createComponent(), BorderLayout.SOUTH); + return panel; } public void reset() { initializeModel(); } - public void apply() { + public void apply() throws ConfigurationException { myVcsManager.setDirectoryMappings(myModel.getItems()); + myRecentlyChangedConfigurable.apply(); initializeModel(); } public boolean isModified() { + if (myRecentlyChangedConfigurable.isModified()) return true; return !myModel.getItems().equals(myVcsManager.getDirectoryMappings()); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java index 857437149d69..795652f0b773 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java @@ -29,21 +29,55 @@ import java.util.List; public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvider { private final Document myDocument; private final Project myProject; - private final String myUpToDateContent; + private final LineStatusTrackerManagerI myLineStatusTrackerManagerI; - public UpToDateLineNumberProviderImpl(Document document, Project project, String upToDateContent) { + public UpToDateLineNumberProviderImpl(Document document, Project project) { myDocument = document; myProject = project; - myUpToDateContent = upToDateContent; + myLineStatusTrackerManagerI = LineStatusTrackerManager.getInstance(myProject); } public int getLineNumber(int currentNumber) { - LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument); + LineStatusTracker tracker = myLineStatusTrackerManagerI.getLineStatusTracker(myDocument); if (tracker == null) { return currentNumber; } return calcLineNumber(tracker, currentNumber); } + + public boolean isRangeChanged(final int start, final int end) { + LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument); + if (tracker == null) { + return false; + } + for (Range range : tracker.getRanges()) { + if (lineInRange(range, start) || lineInRange(range, end)) { + return true; + } + if (range.getOffset1() > start) { + return range.getOffset1() < end; + } + } + return false; + } + + private static boolean lineInRange(final Range range, final int currentNumber) { + return range.getOffset1() <= currentNumber && range.getOffset2() >= currentNumber; + } + + @Override + public boolean isLineChanged(int currentNumber) { + LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument); + if (tracker == null) { + return false; + } + for (Range range : tracker.getRanges()) { + if (range.getOffset1() <= currentNumber && range.getOffset2() >= currentNumber) { + return true; + } + } + return false; + } private boolean endsWithSeparator(final CharSequence string) { if ((string == null) || (string.length() == 0)) { diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/annotate/CvsFileAnnotation.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/annotate/CvsFileAnnotation.java index 4a699b857442..aa6d449df696 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/annotate/CvsFileAnnotation.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/annotate/CvsFileAnnotation.java @@ -155,6 +155,14 @@ public class CvsFileAnnotation implements FileAnnotation{ return null; } + @Override + public Date getLineDate(int lineNumber) { + if (lineNumber < 0 || lineNumber >= myAnnotations.length) { + return null; + } + return myAnnotations[lineNumber].getDate(); + } + public VcsRevisionNumber originalRevision(int lineNumber) { return getLineRevisionNumber(lineNumber); } diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index a69c0cbd97d0..32679c59b42f 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -118,7 +118,6 @@ serviceImplementation="git4idea.DialogManager"/> - diff --git a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java b/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java index b5335be80f33..da98e8703b24 100644 --- a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java +++ b/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java @@ -237,13 +237,26 @@ public class GitFileAnnotation implements FileAnnotation { * {@inheritDoc} */ public VcsRevisionNumber getLineRevisionNumber(final int lineNumber) { - if (myLines.size() <= lineNumber || lineNumber < 0 || myLines.get(lineNumber) == null) { + if (lineNumberCheck(lineNumber)) { return null; } final LineInfo lineInfo = myLines.get(lineNumber); return lineInfo == null ? null : lineInfo.getRevision(); } + private boolean lineNumberCheck(int lineNumber) { + return myLines.size() <= lineNumber || lineNumber < 0 || myLines.get(lineNumber) == null; + } + + @Override + public Date getLineDate(int lineNumber) { + if (lineNumberCheck(lineNumber)) { + return null; + } + final LineInfo lineInfo = myLines.get(lineNumber); + return lineInfo == null ? null : lineInfo.getDate(); + } + /** * Get revision number for the line. */ @@ -287,7 +300,7 @@ public class GitFileAnnotation implements FileAnnotation { } public String getValue(int lineNumber) { - if (myLines.size() <= lineNumber || lineNumber < 0 || myLines.get(lineNumber) == null) { + if (lineNumberCheck(lineNumber)) { return ""; } else { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotation.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotation.java index 02addf7afa86..0d6075ecfe45 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotation.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotation.java @@ -22,6 +22,7 @@ import org.apache.commons.lang.StringUtils; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; +import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -99,6 +100,16 @@ public class HgAnnotation implements FileAnnotation { return annotationLine.getVcsRevisionNumber(); } + @Override + public Date getLineDate(int lineNumber) { + if (lineNumber >= lines.size() || lineNumber < 0) { + return null; + } + //lines.get(lineNumber).get(HgAnnotation.FIELD.DATE) + // todo : parse date + return null; + } + public List getRevisions() { List result = new LinkedList(); result.addAll(vcsFileRevisions); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenConsoleImpl.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenConsoleImpl.java index ef641814e4d7..5a7c50d9bd92 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenConsoleImpl.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenConsoleImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.MessageView; @@ -34,6 +35,7 @@ import org.jetbrains.idea.maven.execution.MavenRunnerParameters; import org.jetbrains.idea.maven.execution.MavenRunnerSettings; import org.jetbrains.idea.maven.utils.MavenUtil; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; public class MavenConsoleImpl extends MavenConsole { @@ -73,10 +75,11 @@ public class MavenConsoleImpl extends MavenConsole { public static TextConsoleBuilder createConsoleBuilder(Project project) { TextConsoleBuilder builder = TextConsoleBuilderFactory.getInstance().createBuilder(project); - Filter[] filters = {new ExceptionFilter(project), new RegexpFilter(project, CONSOLE_FILTER_REGEXP)}; + List filters = ExceptionFilters.getFilters(GlobalSearchScope.allScope(project)); for (Filter filter : filters) { builder.addFilter(filter); } + builder.addFilter(new RegexpFilter(project, CONSOLE_FILTER_REGEXP)); return builder; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnFileAnnotation.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnFileAnnotation.java index d2f89e47af21..4e211f432c79 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnFileAnnotation.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnFileAnnotation.java @@ -246,6 +246,16 @@ public class SvnFileAnnotation implements FileAnnotation { return null; } + @Override + public Date getLineDate(int lineNumber) { + if (myInfos.size() <= lineNumber || lineNumber < 0) { + return null; + } + final LineInfo info = myInfos.get(lineNumber); + if (info == null) return null; + return info.getDate(); + } + public List getRevisions() { final List result = new ArrayList(myRevisionMap.values()); Collections.sort(result, new Comparator() {