From 9f5cd7f4f2ab2f753c938a6687f5e062902e3b48 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 25 Aug 2015 21:10:40 +0300 Subject: [PATCH 001/172] PY-14560 Regexp changed to state machine that works in parallel Since regexp backtraces are unacceptible due to performance reasons, machine is created to check several branches in parallel instead of backtracking --- .../python/run/PyTracebackParser.java | 4 +- .../testing/pytest/PyFilesStateMachine.java | 179 ++++++++++++++++++ .../pytest/PyFilesStateMachineResult.java | 36 ++++ .../testing/pytest/PyTestTracebackParser.java | 63 ++++-- .../traceBackParsers/TraceBackParser.java | 54 +----- .../TraceBackParserAdapter.java | 70 +++++++ .../python/traceBackParsers/package-info.java | 2 +- .../pytest/PyTestTracebackParserTest.java | 65 +++++-- .../python/testing/pytest/linksDataTest.txt | 26 +++ 9 files changed, 424 insertions(+), 75 deletions(-) create mode 100644 python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java create mode 100644 python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java create mode 100644 python/src/com/jetbrains/python/traceBackParsers/TraceBackParserAdapter.java create mode 100644 python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt diff --git a/python/src/com/jetbrains/python/run/PyTracebackParser.java b/python/src/com/jetbrains/python/run/PyTracebackParser.java index 276de8ed2be3..546daef338dc 100644 --- a/python/src/com/jetbrains/python/run/PyTracebackParser.java +++ b/python/src/com/jetbrains/python/run/PyTracebackParser.java @@ -16,7 +16,7 @@ package com.jetbrains.python.run; import com.jetbrains.python.traceBackParsers.LinkInTrace; -import com.jetbrains.python.traceBackParsers.TraceBackParser; +import com.jetbrains.python.traceBackParsers.TraceBackParserAdapter; import org.jetbrains.annotations.NotNull; import java.util.regex.Matcher; @@ -27,7 +27,7 @@ import java.util.regex.Pattern; * * @author Ilya.Kazakevich */ -public class PyTracebackParser extends TraceBackParser { +public class PyTracebackParser extends TraceBackParserAdapter { public PyTracebackParser() { diff --git a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java new file mode 100644 index 000000000000..cd603fc4a31d --- /dev/null +++ b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java @@ -0,0 +1,179 @@ +/* + * Copyright 2000-2015 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.jetbrains.python.testing.pytest; + +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Automata searches for file links and numbers. + * Create one with either {@link #createFromStart()} for initial or {@link #createFromChar(char, int)} + * or char inside of line. + *

+ * Call {@link #addChar(char)} or {@link #endLine()} when line ends and do the following: + *

    + *
  1. {@link PyFilesStateMachineResult#FINISHED}: machine found link, use {@link #getFileAndLine()} to get info
  2. + *
  3. {@link PyFilesStateMachineResult#FAILED}: machine failed, discard it
  4. + *
  5. {@link PyFilesStateMachineResult#IN_PROGRESS}: machine waits for next char
  6. + *
+ * + * @author Ilya.Kazakevich + */ +final class PyFilesStateMachine { + private final boolean myHasQuote; // In "quote" mode, spaces accepted + private boolean myLookingForFile = true; // Looking for file if true , for line number if not + private boolean myWaitingForCharAfterSemicolon; // Semicolon entered, looking for next char + private final int myStart; // start position + private final StringBuilder myFileName = new StringBuilder(); + private final StringBuilder myLineNumber = new StringBuilder(); + + private PyFilesStateMachine(final int start, final boolean quoteMode) { + myStart = start; + myHasQuote = quoteMode; + } + + /** + * @param firstChar current char + * @param start machine may store start position, acessable by {@link #getStart()} + * @return machine or null of this char does not allow new machine + */ + @Nullable + static PyFilesStateMachine createFromChar(final char firstChar, final int start) { + if (firstChar == '"') { + final PyFilesStateMachine machine = new PyFilesStateMachine(start, true); + return machine; + } + if (firstChar == ' ') { + return new PyFilesStateMachine(start, false); + } + return null; + } + + /** + * @return machine for the start of the line + */ + @NotNull + static PyFilesStateMachine createFromStart() { + return new PyFilesStateMachine(0, false); + } + + /** + * @param charToCheck char to add to machine + * @return see class doc for possible states + */ + @NotNull + PyFilesStateMachineResult addChar(final char charToCheck) { + if (myWaitingForCharAfterSemicolon) { + // Previous step was ":", what is next? + if (charToCheck == '/' || charToCheck == '\\') { + // Slash? That is part of file + myFileName.append(':'); + myFileName.append(charToCheck); + myWaitingForCharAfterSemicolon = false; + return PyFilesStateMachineResult.IN_PROGRESS; + } + if (Character.isDigit(charToCheck)) { + // Number? Line numbers started, file name found + myLookingForFile = false; + myLineNumber.append(charToCheck); + myWaitingForCharAfterSemicolon = false; + return PyFilesStateMachineResult.IN_PROGRESS; + } + return PyFilesStateMachineResult.FAILED; + } + + if (charToCheck == '"') { + // If machine in quote mode, and file and line are already found, machine is finished! + if (myHasQuote && myFileName.length() > 0 && myLineNumber.length() > 0) { + return PyFilesStateMachineResult.FINISHED; + } + return PyFilesStateMachineResult.FAILED; // Can't handle quote in other modes + } + if (charToCheck == ' ') { + if (myHasQuote && myLookingForFile) { // Spaces in quote mode is legal file names + myFileName.append(' '); + return PyFilesStateMachineResult.IN_PROGRESS; + } + if ( !myHasQuote && myFileName.length() > 0 && myLineNumber.length() > 0) { //In other modes in may indicate end + return PyFilesStateMachineResult.FINISHED; + } + return PyFilesStateMachineResult.FAILED; + } + if (Character.isLetter(charToCheck) || charToCheck == '/' || charToCheck == '\\' || charToCheck == '.' || charToCheck == '_') { + // Alpha symbols are or for file name + if (myLookingForFile) { + myFileName.append(charToCheck); + return PyFilesStateMachineResult.IN_PROGRESS; + } + } + if (charToCheck == ':') { + // Semicolon is ok as file name + if (myLookingForFile) { + myWaitingForCharAfterSemicolon = true; + return PyFilesStateMachineResult.IN_PROGRESS; + } + } + if (Character.isDigit(charToCheck)) { + if (!myLookingForFile) { + myLineNumber.append(charToCheck); + return PyFilesStateMachineResult.IN_PROGRESS; + } + if (myFileName.length() == 0) { + // Can't start with digit + return PyFilesStateMachineResult.FAILED; + } + myFileName.append(charToCheck); + return PyFilesStateMachineResult.IN_PROGRESS; + } + // Any unknown char is success end if we already have file name and line number + if (myFileName.length() > 0 && myLineNumber.length() > 0) { + return PyFilesStateMachineResult.FINISHED; + } + return PyFilesStateMachineResult.FAILED; + } + + /** + * @return when machine is in {@link PyFilesStateMachineResult#FINISHED} use this method to get file and line number + */ + @NotNull + Pair getFileAndLine() { + return Pair.create(myFileName.toString(), myLineNumber.toString()); + } + + /** + * @return position when this machine started + */ + int getStart() { + return myStart; + } + + /** + * To be called when line ends + * + * @return see class doc + */ + @NotNull + PyFilesStateMachineResult endLine() { + if (myHasQuote) { + return PyFilesStateMachineResult.FAILED; + } + if (myFileName.length() > 0 && myLineNumber.length() > 0) { + return PyFilesStateMachineResult.FINISHED; + } + return PyFilesStateMachineResult.FAILED; + } +} diff --git a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java new file mode 100644 index 000000000000..c2ad57e1ac5f --- /dev/null +++ b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2015 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.jetbrains.python.testing.pytest; + +/** + * Results for {@link PyFilesStateMachine} + * + * @author Ilya.Kazakevich + */ +enum PyFilesStateMachineResult { + /** + * Discard this machine + */ + FAILED, + /** + * Provide next char + */ + IN_PROGRESS, + /** + * File found, you may get it + */ + FINISHED +} diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java b/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java index a4aa1ef566b5..a76132af5568 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java @@ -15,30 +15,67 @@ */ package com.jetbrains.python.testing.pytest; +import com.intellij.openapi.util.Pair; import com.jetbrains.python.traceBackParsers.LinkInTrace; import com.jetbrains.python.traceBackParsers.TraceBackParser; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; /** * User : catherine */ -public final class PyTestTracebackParser extends TraceBackParser { +public final class PyTestTracebackParser implements TraceBackParser { - public PyTestTracebackParser() { - // File name can't start with number, can't be more then 200 chars long (its insane) and line number is also limited to int maxvalue - super(Pattern.compile("([^0-9][^\"]{0,200}?):(\\d{1,8})")); + + @Nullable + @Override + public LinkInTrace findLinkInTrace(@NotNull final String line) { + final Collection machines = new ArrayList(); + machines.add(PyFilesStateMachine.createFromStart()); + final char[] chars = line.toCharArray(); + for (int i = 0; i < chars.length; i++) { + final char nextChar = chars[i]; + final Iterator iterator = machines.iterator(); + while (iterator.hasNext()) { + final PyFilesStateMachine machine = iterator.next(); + switch (machine.addChar(nextChar)) { + case FAILED: + iterator.remove(); // Machine failed, discard + break; + case FINISHED: + return createLinkInTrace(machine); // Link found + case IN_PROGRESS: + break; + } + } + + final PyFilesStateMachine newMachine = PyFilesStateMachine.createFromChar(nextChar, i); + if (newMachine != null) { + machines.add(newMachine); + } + } + + // Tell all machines file is ended + for (final PyFilesStateMachine machine : machines) { + if (machine.endLine() == PyFilesStateMachineResult.FINISHED) { + return createLinkInTrace(machine); + } + } + + return null; } @NotNull - @Override - protected LinkInTrace findLinkInTrace(@NotNull final String line, @NotNull final Matcher matchedMatcher) { - final String fileName = matchedMatcher.group(1).replace('\\', '/'); - final int lineNumber = Integer.parseInt(matchedMatcher.group(2)); - final int startPos = matchedMatcher.start(1); - final int endPos = matchedMatcher.end(2); - return new LinkInTrace(fileName, lineNumber, startPos, endPos); + private static LinkInTrace createLinkInTrace(@NotNull final PyFilesStateMachine machine) { + final Pair fileAndLine = machine.getFileAndLine(); + final int start = machine.getStart(); + final String lineNumber = fileAndLine.second; + // Cut too long lines that can't be presented as integer anyway + final int number = Integer.parseInt((lineNumber.length() > 5 ? lineNumber.substring(0, 5) : lineNumber)); + return new LinkInTrace(fileAndLine.first, number, start, start + fileAndLine.first.length() + lineNumber.length() + 1); } } diff --git a/python/src/com/jetbrains/python/traceBackParsers/TraceBackParser.java b/python/src/com/jetbrains/python/traceBackParsers/TraceBackParser.java index 276dbd120f18..e187640f6afb 100644 --- a/python/src/com/jetbrains/python/traceBackParsers/TraceBackParser.java +++ b/python/src/com/jetbrains/python/traceBackParsers/TraceBackParser.java @@ -20,36 +20,12 @@ import com.jetbrains.python.testing.pytest.PyTestTracebackParser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** - * Parent of all traceback filters. Extend it and your impl. to {@link #PARSERS}. - * When implement, provide {@link Pattern pattern}, and your code will be called only if line matches this pattern + * Searches for line in stacktrace * * @author Ilya.Kazakevich */ -public abstract class TraceBackParser { - /** - * We do not search anything in line longer than this, because it makes no sense to search something in so long lines - */ - private static final int MAX_LINE_TO_PARSE = 5000; - @NotNull - private final Pattern myPattern; - - /** - * @param pattern pattern to be used to match line. - */ - protected TraceBackParser(@NotNull final Pattern pattern) { - myPattern = pattern; - } - - - @NotNull // TODO: use EP instead? - @SuppressWarnings("PublicStaticArrayField") // Noone will change it, anyway. - public static final TraceBackParser[] PARSERS = {new PyTestTracebackParser(), new PyTracebackParser()}; - - +public interface TraceBackParser { /** * Searches for link in line * @@ -57,27 +33,9 @@ public abstract class TraceBackParser { * @return line info (if found) */ @Nullable - public final LinkInTrace findLinkInTrace(@NotNull String line) { - if (line.length() > MAX_LINE_TO_PARSE) { - // Cut down line is too long to parse (to prevent freeze) - //noinspection AssignmentToMethodParameter - line = line.substring(0, MAX_LINE_TO_PARSE); - } - final Matcher matcher = myPattern.matcher(line); - if (!matcher.find()) { - return null; - } - return findLinkInTrace(line, matcher); - } + LinkInTrace findLinkInTrace(@NotNull String line); - - /** - * Fetches link from line - * - * @param line line to search link in - * @param matchedMatcher regex matcher that found link - * @return line info - */ - @NotNull - protected abstract LinkInTrace findLinkInTrace(@NotNull String line, @NotNull Matcher matchedMatcher); + @NotNull // TODO: use EP instead? + @SuppressWarnings("PublicStaticArrayField") // Noone will change it, anyway. + TraceBackParser[] PARSERS = {new PyTestTracebackParser(), new PyTracebackParser()}; } diff --git a/python/src/com/jetbrains/python/traceBackParsers/TraceBackParserAdapter.java b/python/src/com/jetbrains/python/traceBackParsers/TraceBackParserAdapter.java new file mode 100644 index 000000000000..db1be45d81b2 --- /dev/null +++ b/python/src/com/jetbrains/python/traceBackParsers/TraceBackParserAdapter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2015 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.jetbrains.python.traceBackParsers; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Adapter that uses regexps + * + * @author Ilya.Kazakevich + */ +public abstract class TraceBackParserAdapter implements TraceBackParser { + /** + * We do not search anything in line longer than this, because it makes no sense to search something in so long lines + */ + private static final int MAX_LINE_TO_PARSE = 5000; + @NotNull + private final Pattern myPattern; + + /** + * @param pattern pattern to be used to match line. + */ + protected TraceBackParserAdapter(@NotNull final Pattern pattern) { + myPattern = pattern; + } + + + @Nullable + @Override + public final LinkInTrace findLinkInTrace(@NotNull String line) { + if (line.length() > MAX_LINE_TO_PARSE) { + // Cut down line is too long to parse (to prevent freeze) + //noinspection AssignmentToMethodParameter + line = line.substring(0, MAX_LINE_TO_PARSE); + } + final Matcher matcher = myPattern.matcher(line); + if (!matcher.find()) { + return null; + } + return findLinkInTrace(line, matcher); + } + + + /** + * Fetches link from line + * + * @param line line to search link in + * @param matchedMatcher regex matcher that found link + * @return line info + */ + @NotNull + protected abstract LinkInTrace findLinkInTrace(@NotNull String line, @NotNull Matcher matchedMatcher); +} diff --git a/python/src/com/jetbrains/python/traceBackParsers/package-info.java b/python/src/com/jetbrains/python/traceBackParsers/package-info.java index 5b2f8f35a157..71a5d73f858d 100644 --- a/python/src/com/jetbrains/python/traceBackParsers/package-info.java +++ b/python/src/com/jetbrains/python/traceBackParsers/package-info.java @@ -19,7 +19,7 @@ *

* Each parser knows how to parse test output to fetch file links from stack traces. * All parsers should extend {@link com.jetbrains.python.traceBackParsers.TraceBackParser} and be installed to - * {@link com.jetbrains.python.traceBackParsers.TraceBackParser#PARSERS} while this functionality has no EP. + * {@link com.jetbrains.python.traceBackParsers.TraceBackParserAdapter#PARSERS} while this functionality has no EP. *

*/ package com.jetbrains.python.traceBackParsers; \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java b/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java index 653ee032c0a3..a40b1cf55a76 100644 --- a/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java +++ b/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java @@ -15,13 +15,19 @@ */ package com.jetbrains.python.testing.pytest; +import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Base64; import com.jetbrains.python.traceBackParsers.LinkInTrace; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.nio.charset.Charset; +import java.util.HashSet; +import java.util.Set; + /** * Ensures we can parse pytest traces for links. * This test is JUnit4-based (hence it uses annotations) to support timeout @@ -30,12 +36,14 @@ import org.junit.Test; */ public final class PyTestTracebackParserTest { private String myStringJunk; + private String myStringJunkWithSpaces; + private String myStringJunkWithSpacesAndLine; private String myBase64Junk; @Before public void setUp() throws Exception { // Generate junk to text regexp speed - final int junkSize = 10000; + final int junkSize = 50000; final byte[] junk = new byte[junkSize]; for (int i = 0; i < junkSize; i++) { // We do not care about precision nor security, that junk for tests @@ -45,6 +53,8 @@ public final class PyTestTracebackParserTest { final String longString = StringUtil.repeat("1", junkSize); myStringJunk = String.format("%s:%s", longString, longString); myBase64Junk = Base64.encode(junk); + myStringJunkWithSpaces = StringUtil.repeat("dd ddddddddd", junkSize); + myStringJunkWithSpacesAndLine = myStringJunkWithSpaces + " c:/file:12"; } /** @@ -69,14 +79,47 @@ public final class PyTestTracebackParserTest { Assert.assertNull("No file name provided, but link found", new PyTestTracebackParser().findLinkInTrace(":12 file ")); } - /** - * Ensures - * Regexp worst cases are limited to prevent freezing on very long lines - */ - @Test(timeout = 5000) - public void testExponential() throws Exception { - Assert - .assertNull("No link should be found in numbers list", new PyTestTracebackParser().findLinkInTrace(myStringJunk)); - Assert.assertNull("No link should be found in base64 list", new PyTestTracebackParser().findLinkInTrace(myBase64Junk)); + @Test + public void testLinks() throws java.io.IOException { + final String s = + StreamUtil.readText(PyTestTracebackParserTest.class.getResource("linksDataTest.txt").openStream(), Charset.defaultCharset()); + + final Set requiredStrings = new HashSet(); + requiredStrings.add("file:///c:/windows/system32/file.txt - 42"); + requiredStrings.add("file:///c:/windows/system32/file_spam.txt - 42"); + requiredStrings.add("c:\\documents and settings\\foo.txt - 43"); + requiredStrings.add("file:///c:/windows/system32/file.txt - 42"); + requiredStrings.add("/file.py - 42"); + requiredStrings.add("c:\\folder55\\file.py - 12"); + requiredStrings.add("C:\\temp\\untitled55\\test_sample.py - 5"); + requiredStrings.add("C:\\temp\\untitled55\\test_sample.py - 6"); + requiredStrings.add("C:\\temp\\untitled55\\test_sample.py - 7"); + requiredStrings.add("C:\\temp\\untitled55\\test_sample.py - 89999"); + requiredStrings.add("C:\\temp\\untitled55\\test_sample.py - 99999"); + requiredStrings.add("../../../files/files.py - 100"); + requiredStrings.add("/Users/Mac Hipster/Applications/PyCharm 4.0 .app/helpers/lala.py - 12"); + for (final String line : s.split("\n")) { + final LinkInTrace trace = new PyTestTracebackParser().findLinkInTrace(line); + if (trace != null) { + final boolean removeResult = requiredStrings.remove(trace.getFileName() + " - " + trace.getLineNumber()); + Assert.assertTrue(String.format("Unexpected file found %s", trace.getFileName()), + removeResult); + } + } + Assert.assertThat("Some lines were notfound", requiredStrings, Matchers.empty()); + } + + /** + * Ensures + * Regexp worst cases are limited to prevent freezing on very long lines + */ + @Test(timeout = 5000) + public void testLongLines ()throws Exception { + Assert + .assertNull("No link should be found in numbers list", new PyTestTracebackParser().findLinkInTrace(myStringJunk)); + Assert.assertNull("No link should be found in base64 list", new PyTestTracebackParser().findLinkInTrace(myBase64Junk)); + Assert.assertNull("No link should be found in junk", new PyTestTracebackParser().findLinkInTrace(myStringJunkWithSpaces)); + final LinkInTrace trace = new PyTestTracebackParser().findLinkInTrace(myStringJunkWithSpacesAndLine); + Assert.assertNotNull("No link found in long line", trace); + } } -} diff --git a/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt b/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt new file mode 100644 index 000000000000..242bfb3779d3 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt @@ -0,0 +1,26 @@ +ddddddddddddddddddddddddddasdasdasdasd +d d d d +ddddddd +/asdasdasd:asdasdasd/asd +dddddddddddddddddd/ddddddddddddd +:asdasdasdasd:asdasd/asaaaaaaaaaaaaaa +file:///c:/windows/system32/file.txt:42 +Here is "c:\documents and settings\foo.txt:43" +And now I will show you the file file:///c:/windows/system32/file_spam.txt:42 +/file.py:42 +../../../files/files.py:100 + +c:\folder55\file.py:12 + +Please check the following file for errors: "/Users/Mac Hipster/Applications/PyCharm 4.0 .app/helpers/lala.py:12" + +"c:\windows\BUHAHA_ERROR:12 +"c:\windows\BUHAHA_ERROR:12 +C:\temp\untitled55\test_sample.py:5: AssertionError +C:\temp\untitled55\test_sample.py:6A AssertionError +C:\temp\untitled55\test_sample.py:7 +C:\temp\untitled55\test_sample.py:8999999999999999 + +Here is some file C:\temp\untitled55\test_sample.py:999999999999999 +c:/2files.py +a:b:c:d:E:d:s:asd:34:234 \ No newline at end of file From 9fb6a34e2919020f2b47c1fa4149fea311034511 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 26 Aug 2015 17:23:17 +0300 Subject: [PATCH 002/172] PY-14560 State machine is stateful now to prevent heap pollution with short-living objects --- .../testing/pytest/PyFilesStateMachine.java | 134 +++++++++--------- .../pytest/PyFilesStateMachineResult.java | 36 ----- .../testing/pytest/PyTestTracebackParser.java | 39 ++--- 3 files changed, 82 insertions(+), 127 deletions(-) delete mode 100644 python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java diff --git a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java index cd603fc4a31d..74ae4a9cde9e 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java @@ -21,62 +21,49 @@ import org.jetbrains.annotations.Nullable; /** * Automata searches for file links and numbers. - * Create one with either {@link #createFromStart()} for initial or {@link #createFromChar(char, int)} - * or char inside of line. + * Supports 2 modes: "quote-mode" (searches for strings in quotes) and "space mode" -- strings, separated by spaces (or start/end of line) + * Create one providing appropriate flag. *

- * Call {@link #addChar(char)} or {@link #endLine()} when line ends and do the following: - *

    - *
  1. {@link PyFilesStateMachineResult#FINISHED}: machine found link, use {@link #getFileAndLine()} to get info
  2. - *
  3. {@link PyFilesStateMachineResult#FAILED}: machine failed, discard it
  4. - *
  5. {@link PyFilesStateMachineResult#IN_PROGRESS}: machine waits for next char
  6. - *
+ * Call {@link #addChar(char, int)} or {@link #endLine()} when line ends and do the following: + * if result is true, then machine found something. Use {@link #getFileAndLine()} to get result. + * If false, provide next char * * @author Ilya.Kazakevich */ final class PyFilesStateMachine { - private final boolean myHasQuote; // In "quote" mode, spaces accepted + private final boolean myQuoteMode; // In "quote" mode, spaces accepted private boolean myLookingForFile = true; // Looking for file if true , for line number if not + private boolean myInProgress; // True if machine in progress, false if waits to start private boolean myWaitingForCharAfterSemicolon; // Semicolon entered, looking for next char - private final int myStart; // start position + private int myStart; // start position private final StringBuilder myFileName = new StringBuilder(); private final StringBuilder myLineNumber = new StringBuilder(); - private PyFilesStateMachine(final int start, final boolean quoteMode) { - myStart = start; - myHasQuote = quoteMode; - } - /** - * @param firstChar current char - * @param start machine may store start position, acessable by {@link #getStart()} - * @return machine or null of this char does not allow new machine + * @param quoteMode start machine in "quote mode" if true */ - @Nullable - static PyFilesStateMachine createFromChar(final char firstChar, final int start) { - if (firstChar == '"') { - final PyFilesStateMachine machine = new PyFilesStateMachine(start, true); - return machine; - } - if (firstChar == ' ') { - return new PyFilesStateMachine(start, false); - } - return null; - } + PyFilesStateMachine(final boolean quoteMode) { + myQuoteMode = quoteMode; - /** - * @return machine for the start of the line - */ - @NotNull - static PyFilesStateMachine createFromStart() { - return new PyFilesStateMachine(0, false); + if (!myQuoteMode) { + myInProgress = true; // We can start machine if we do not need to wait for quote + } } /** * @param charToCheck char to add to machine - * @return see class doc for possible states + * @param charNumber current position of char (to be checked by {@link #getStart()}) + * @return see class doc */ - @NotNull - PyFilesStateMachineResult addChar(final char charToCheck) { + boolean addChar(final char charToCheck, final int charNumber) { + if (!myInProgress) { + if ((charToCheck == '"' && myQuoteMode)) { + myInProgress = true; + myStart = charNumber; + } + return false; + } + if (myWaitingForCharAfterSemicolon) { // Previous step was ":", what is next? if (charToCheck == '/' || charToCheck == '\\') { @@ -84,70 +71,91 @@ final class PyFilesStateMachine { myFileName.append(':'); myFileName.append(charToCheck); myWaitingForCharAfterSemicolon = false; - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } if (Character.isDigit(charToCheck)) { // Number? Line numbers started, file name found myLookingForFile = false; myLineNumber.append(charToCheck); myWaitingForCharAfterSemicolon = false; - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } - return PyFilesStateMachineResult.FAILED; + resetState(); + return false; } if (charToCheck == '"') { // If machine in quote mode, and file and line are already found, machine is finished! - if (myHasQuote && myFileName.length() > 0 && myLineNumber.length() > 0) { - return PyFilesStateMachineResult.FINISHED; + if (myQuoteMode && myFileName.length() > 0 && myLineNumber.length() > 0) { + return true; } - return PyFilesStateMachineResult.FAILED; // Can't handle quote in other modes + resetState(); + if (myQuoteMode) { // Relaunch process + myInProgress = true; + myStart = charNumber; + } + return false; + // Can't handle quote in other modes } if (charToCheck == ' ') { - if (myHasQuote && myLookingForFile) { // Spaces in quote mode is legal file names + if (myQuoteMode && myLookingForFile) { // Spaces in quote mode is legal file names myFileName.append(' '); - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } - if ( !myHasQuote && myFileName.length() > 0 && myLineNumber.length() > 0) { //In other modes in may indicate end - return PyFilesStateMachineResult.FINISHED; + if (!myQuoteMode && myFileName.length() > 0 && myLineNumber.length() > 0) { //In other modes in may indicate end + return true; } - return PyFilesStateMachineResult.FAILED; + resetState(); + if (!myQuoteMode) { // Relaunch process if we do not need quote + myInProgress = true; + myStart = charNumber; + } + return false; } if (Character.isLetter(charToCheck) || charToCheck == '/' || charToCheck == '\\' || charToCheck == '.' || charToCheck == '_') { // Alpha symbols are or for file name if (myLookingForFile) { myFileName.append(charToCheck); - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } } if (charToCheck == ':') { // Semicolon is ok as file name if (myLookingForFile) { myWaitingForCharAfterSemicolon = true; - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } } if (Character.isDigit(charToCheck)) { if (!myLookingForFile) { myLineNumber.append(charToCheck); - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } if (myFileName.length() == 0) { // Can't start with digit - return PyFilesStateMachineResult.FAILED; + resetState(); + return false; } myFileName.append(charToCheck); - return PyFilesStateMachineResult.IN_PROGRESS; + return false; } // Any unknown char is success end if we already have file name and line number if (myFileName.length() > 0 && myLineNumber.length() > 0) { - return PyFilesStateMachineResult.FINISHED; + return true; } - return PyFilesStateMachineResult.FAILED; + resetState(); + return false; + } + + private void resetState() { + myInProgress = false; + myLookingForFile = true; + myLineNumber.setLength(0); + myFileName.setLength(0); } /** - * @return when machine is in {@link PyFilesStateMachineResult#FINISHED} use this method to get file and line number + * @return when machine is in {@link PyFilesStateMachineState#FINISHED} use this method to get file and line number */ @NotNull Pair getFileAndLine() { @@ -166,14 +174,10 @@ final class PyFilesStateMachine { * * @return see class doc */ - @NotNull - PyFilesStateMachineResult endLine() { - if (myHasQuote) { - return PyFilesStateMachineResult.FAILED; + boolean endLine() { + if (myQuoteMode) { + return false; } - if (myFileName.length() > 0 && myLineNumber.length() > 0) { - return PyFilesStateMachineResult.FINISHED; - } - return PyFilesStateMachineResult.FAILED; + return myFileName.length() > 0 && myLineNumber.length() > 0; } } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java deleted file mode 100644 index c2ad57e1ac5f..000000000000 --- a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachineResult.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2000-2015 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.jetbrains.python.testing.pytest; - -/** - * Results for {@link PyFilesStateMachine} - * - * @author Ilya.Kazakevich - */ -enum PyFilesStateMachineResult { - /** - * Discard this machine - */ - FAILED, - /** - * Provide next char - */ - IN_PROGRESS, - /** - * File found, you may get it - */ - FINISHED -} diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java b/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java index a76132af5568..3e69b5e45f33 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestTracebackParser.java @@ -21,10 +21,6 @@ import com.jetbrains.python.traceBackParsers.TraceBackParser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; - /** * User : catherine */ @@ -34,36 +30,27 @@ public final class PyTestTracebackParser implements TraceBackParser { @Nullable @Override public LinkInTrace findLinkInTrace(@NotNull final String line) { - final Collection machines = new ArrayList(); - machines.add(PyFilesStateMachine.createFromStart()); + final PyFilesStateMachine quoteMachine = new PyFilesStateMachine(true); + final PyFilesStateMachine spaceMachine = new PyFilesStateMachine(false); + + final char[] chars = line.toCharArray(); for (int i = 0; i < chars.length; i++) { final char nextChar = chars[i]; - final Iterator iterator = machines.iterator(); - while (iterator.hasNext()) { - final PyFilesStateMachine machine = iterator.next(); - switch (machine.addChar(nextChar)) { - case FAILED: - iterator.remove(); // Machine failed, discard - break; - case FINISHED: - return createLinkInTrace(machine); // Link found - case IN_PROGRESS: - break; - } + if (quoteMachine.addChar(nextChar, i)) { + return createLinkInTrace(quoteMachine); } - - final PyFilesStateMachine newMachine = PyFilesStateMachine.createFromChar(nextChar, i); - if (newMachine != null) { - machines.add(newMachine); + if (spaceMachine.addChar(nextChar, i)) { + return createLinkInTrace(spaceMachine); } } // Tell all machines file is ended - for (final PyFilesStateMachine machine : machines) { - if (machine.endLine() == PyFilesStateMachineResult.FINISHED) { - return createLinkInTrace(machine); - } + if (quoteMachine.endLine()) { + return createLinkInTrace(quoteMachine); + } + if (spaceMachine.endLine()) { + return createLinkInTrace(spaceMachine); } return null; From 1f7b686d897e350e0a6a34a64769d6626a1612b2 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 26 Aug 2015 21:51:10 +0300 Subject: [PATCH 003/172] PY-14560 dash char added --- .../jetbrains/python/testing/pytest/PyFilesStateMachine.java | 3 ++- .../python/testing/pytest/PyTestTracebackParserTest.java | 1 + .../com/jetbrains/python/testing/pytest/linksDataTest.txt | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java index 74ae4a9cde9e..775fed87e4ea 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyFilesStateMachine.java @@ -112,7 +112,8 @@ final class PyFilesStateMachine { } return false; } - if (Character.isLetter(charToCheck) || charToCheck == '/' || charToCheck == '\\' || charToCheck == '.' || charToCheck == '_') { + if (Character.isLetter(charToCheck) || charToCheck == '/' || charToCheck == '\\' || charToCheck == '.' || charToCheck == '_' || + charToCheck == '-') { // Alpha symbols are or for file name if (myLookingForFile) { myFileName.append(charToCheck); diff --git a/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java b/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java index a40b1cf55a76..4863083d1b45 100644 --- a/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java +++ b/python/testSrc/com/jetbrains/python/testing/pytest/PyTestTracebackParserTest.java @@ -98,6 +98,7 @@ public final class PyTestTracebackParserTest { requiredStrings.add("C:\\temp\\untitled55\\test_sample.py - 99999"); requiredStrings.add("../../../files/files.py - 100"); requiredStrings.add("/Users/Mac Hipster/Applications/PyCharm 4.0 .app/helpers/lala.py - 12"); + requiredStrings.add("C:\\Users\\ilya.kazakevich\\virtenvs\\spammy\\lib\\site-packages\\django_cron\\models.py - 4"); for (final String line : s.split("\n")) { final LinkInTrace trace = new PyTestTracebackParser().findLinkInTrace(line); if (trace != null) { diff --git a/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt b/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt index 242bfb3779d3..cddc66506b65 100644 --- a/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt +++ b/python/testSrc/com/jetbrains/python/testing/pytest/linksDataTest.txt @@ -20,6 +20,7 @@ C:\temp\untitled55\test_sample.py:5: AssertionError C:\temp\untitled55\test_sample.py:6A AssertionError C:\temp\untitled55\test_sample.py:7 C:\temp\untitled55\test_sample.py:8999999999999999 +C:\Users\ilya.kazakevich\virtenvs\spammy\lib\site-packages\django_cron\models.py:4: Here is some file C:\temp\untitled55\test_sample.py:999999999999999 c:/2files.py From 62f3014456237b77f37fdaa6a9e49448786e410f Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Thu, 27 Aug 2015 15:42:39 +0300 Subject: [PATCH 004/172] IDEA-143938 Emacs mode: `C-m` does `C-l`, and `C-l` is unbound --- .../src/idea/Keymap_Emacs.xml | 20 +++++++++++++++++++ .../openapi/keymap/KeymapsTestCase.java | 3 +++ 2 files changed, 23 insertions(+) diff --git a/platform/platform-resources/src/idea/Keymap_Emacs.xml b/platform/platform-resources/src/idea/Keymap_Emacs.xml index 280be2cfcd99..b9950f364d51 100644 --- a/platform/platform-resources/src/idea/Keymap_Emacs.xml +++ b/platform/platform-resources/src/idea/Keymap_Emacs.xml @@ -273,6 +273,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java index 70e655965133..7e82afffdbc2 100644 --- a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java @@ -170,6 +170,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "alt R", "Django.RunManageTaskAction", "org.jetbrains.plugins.ruby.tasks.rake.actions.RakeTasksPopupAction"}, }); put("Emacs", new String[][] { + { "ENTER", "EditorChooseLookupItem", "NextTemplateVariable", "EditorEnter", "Images.Thumbnails.EnterAction", + "PropertyInspectorActions.EditValue", "Console.Execute", "Console.TableResult.EditValue"}, { "F2", "GotoNextError", "GuiDesigner.EditComponent", "GuiDesigner.EditGroup", "Console.TableResult.EditValue"}, { "alt ENTER", "ShowIntentionActions", "Console.TableResult.EditValue", "DatabaseView.PropertiesAction"}, { "TAB", "EditorChooseLookupItemReplace", "NextTemplateVariable", "NextParameter", "EditorIndentSelection", @@ -181,6 +183,7 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "control 3", "GotoBookmark3", "FileChooser.GotoModule"}, { "control D", "$Delete", "Diff.ShowDiff", "CompareTwoFiles", "SendEOF", "FileChooser.GotoDesktop"}, { "control K", "EditorCutLineEnd", "CheckinProject"}, + { "control M", "EditorEnter", "EditorChooseLookupItem", "NextTemplateVariable", "Console.Execute"}, { "control N", "EditorDown", "FileChooser.NewFolder"}, { "control P", "EditorUp", "FileChooser.TogglePathShowing"}, { "control R", "Console.TableResult.Reload", "org.jetbrains.plugins.ruby.rails.console.ReloadSources", "FindPrevious"}, From 8dec0f5b837e4c61725f06275d741c025dd9e580 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 24 Aug 2015 17:21:24 +0300 Subject: [PATCH 005/172] don t diff injected tree when the text is not changed --- .../tree/injected/MultiHostRegistrarImpl.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java index d3e9e8ec904f..954d0532cbc9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/MultiHostRegistrarImpl.java @@ -443,20 +443,22 @@ public class MultiHostRegistrarImpl implements MultiHostRegistrar, ModificationT oldFile.putUserData(FileContextUtil.INJECTED_IN_ELEMENT, injectedPsi.getUserData(FileContextUtil.INJECTED_IN_ELEMENT)); assert shreds.isValid(); - oldViewProvider.performNonPhysically(new Runnable() { - @Override - public void run() { - DebugUtil.startPsiModification("injected tree diff"); - try { - final DiffLog diffLog = BlockSupportImpl.mergeTrees(oldFile, oldFileNode, injectedNode, new DaemonProgressIndicator(), - oldFileNode.getText()); - DocumentCommitProcessor.doActualPsiChange(oldFile, diffLog); + if (!oldFile.textMatches(injectedPsi)) { + oldViewProvider.performNonPhysically(new Runnable() { + @Override + public void run() { + DebugUtil.startPsiModification("injected tree diff"); + try { + final DiffLog diffLog = BlockSupportImpl.mergeTrees(oldFile, oldFileNode, injectedNode, new DaemonProgressIndicator(), + oldFileNode.getText()); + DocumentCommitProcessor.doActualPsiChange(oldFile, diffLog); + } + finally { + DebugUtil.finishPsiModification(); + } } - finally { - DebugUtil.finishPsiModification(); - } - } - }); + }); + } assert shreds.isValid(); return oldFile; From ed69ae7721b4036b9541270116ae850f352c93aa Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 25 Aug 2015 15:30:23 +0300 Subject: [PATCH 006/172] more logs --- .../fileTypes/impl/FileTypeManagerImpl.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index 83fa8dc423bf..5998c7e432a8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -206,7 +206,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent VirtualFile file = event instanceof VFileCreateEvent ? /* avoid expensive find child here */ null : event.getFile(); VirtualFile filtered = file != null && wasAutoDetectedBefore(file) && isDetectable(file) ? file : null; if (toLog()) { - log("F: handled " + event + "; filtered file: " + filtered + "(file: "+file+"; wasAutoDetectedBefore(file): "+(file == null ? null : wasAutoDetectedBefore(file))+"; isDetectable(file): "+(file == null ? null : isDetectable(file))+"; file.getLength(): "+(file == null ? null : file.getLength())+"; file.isValid(): "+(file == null ? null : file.isValid())+"; file.is(VFileProperty.SPECIAL): "+(file == null ? null : file.is(VFileProperty.SPECIAL))+"; packedFlags.get(id): "+(!(file instanceof VirtualFileWithId) ? null : packedFlags.get(((VirtualFileWithId)file).getId()))+"; file.getFileSystem():"+(file == null ? null : file.getFileSystem())+")"); + log("F: handled " + event + "; filtered file: " + filtered + " (file: "+file+"; wasAutoDetectedBefore(file): "+(file == null ? null : wasAutoDetectedBefore(file))+"; isDetectable(file): "+(file == null ? null : isDetectable(file))+"; file.getLength(): "+(file == null ? null : file.getLength())+"; file.isValid(): "+(file == null ? null : file.isValid())+"; file.is(VFileProperty.SPECIAL): "+(file == null ? null : file.is(VFileProperty.SPECIAL))+"; packedFlags.get(id): "+(!(file instanceof VirtualFileWithId) ? null : packedFlags.get(((VirtualFileWithId)file).getId()))+"; file.getFileSystem():"+(file == null ? null : file.getFileSystem())+")"); } return filtered; } @@ -349,7 +349,11 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent int id = file instanceof VirtualFileWithId ? ((VirtualFileWithId)file).getId() : -1; FileType before = getAutoDetectedType(file, id); - packedFlags.set(id, ATTRIBUTES_WERE_LOADED_MASK); + int flags = ATTRIBUTES_WERE_LOADED_MASK; + packedFlags.set(id, flags); + if (toLog()) { + log("F: reDetect("+file.getName()+") prepare to redetect. flags: "+flags); + } file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, null); FileType after = getFileTypeByFile(file); // may be back to standard file type @@ -481,13 +485,16 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent if (autoDetectWasRun) { FileType type = getAutoDetectedType(file, id); if (toLog()) { - log("F: autodetected getFileType("+file.getName()+") = "+type.getName()); + log("F: autodetected getFileType("+file.getName()+") = "+type.getName()+"; packedFlags.get(id):"+flags); } return type; } if ((flags & ATTRIBUTES_WERE_LOADED_MASK) == 0) { flags = readFlagsFromCache(file); packedFlags.set(id, flags); + if (toLog()) { + log("F: readFlagsFromCache("+file.getName()+") = "+flags); + } } boolean wasDetectedAsText = BitUtil.isSet(flags, AUTO_DETECTED_AS_TEXT_MASK); boolean wasDetectedAsBinary = BitUtil.isSet(flags, AUTO_DETECTED_AS_BINARY_MASK); @@ -553,6 +560,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent autoDetectedAttribute = autoDetectedAttribute.newVersion(count); PropertiesComponent.getInstance().setValue("fileTypeChangedCounter", Integer.toString(count)); packedFlags.clear(); + if (toLog()) { + log("F: clearCaches"); + } } @NotNull @@ -583,6 +593,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent flags = BitUtil.set(flags, AUTO_DETECTED_AS_TEXT_MASK, wasAutodetectedAsText); flags = BitUtil.set(flags, AUTO_DETECTED_AS_BINARY_MASK, wasAutodetectedAsBinary); packedFlags.set(id, flags); + if (toLog()) { + log("F: cacheAutoDetectedFileType("+file.getName()+") = "+flags); + } if (wasAutodetectedAsText || wasAutodetectedAsBinary) { file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, null); From ff085f0e702c0696e3b32d3d106e68c4316e06e7 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 26 Aug 2015 14:59:45 +0300 Subject: [PATCH 007/172] indicator mem leak --- .../impl/analysis/HighlightVisitorImpl.java | 2 +- .../impl/analysis/PostHighlightingVisitor.java | 13 +++++-------- .../daemon/impl/HighlightingSession.java | 3 +-- .../daemon/impl/HighlightingSessionImpl.java | 17 ++--------------- 4 files changed, 9 insertions(+), 26 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index af88115801c4..0f44a9171846 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -182,7 +182,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh highlight.run(); progress.checkCanceled(); HighlightingSession highlightingSession = HighlightingSessionImpl.getHighlightingSession(file, progress); - PostHighlightingVisitor highlightingVisitor = new PostHighlightingVisitor(file, document, refCountHolder, highlightingSession); + PostHighlightingVisitor highlightingVisitor = new PostHighlightingVisitor(file, document, refCountHolder); highlightingVisitor.collectHighlights(file, holder, progress); } }); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java index 3f89ae26ff55..1d1644d7dfd5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PostHighlightingVisitor.java @@ -73,7 +73,6 @@ class PostHighlightingVisitor { @NotNull private final Project myProject; private final PsiFile myFile; @NotNull private final Document myDocument; - @NotNull private final HighlightingSession myHighlightingSession; private boolean myHasRedundantImports; private int myCurrentEntryIndex; @@ -94,19 +93,19 @@ class PostHighlightingVisitor { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - if (myProject.isDisposed() || !myFile.isValid()) return; + if (myProject.isDisposed() || !myFile.isValid() || !myFile.isWritable()) return; IntentionAction optimizeImportsFix = QuickFixFactory.getInstance().createOptimizeImportsFix(true); - if (optimizeImportsFix.isAvailable(myProject, null, myFile) && myFile.isWritable()) { + if (optimizeImportsFix.isAvailable(myProject, null, myFile)) { optimizeImportsFix.invoke(myProject, null, myFile); } } }); } }; - Disposer.register(myHighlightingSession, invokeFixLater); + Disposer.register((DaemonProgressIndicator)progress, invokeFixLater); if (progress.isCanceled()) { Disposer.dispose(invokeFixLater); - Disposer.dispose(myHighlightingSession); + Disposer.dispose((DaemonProgressIndicator)progress); progress.checkCanceled(); } } @@ -114,9 +113,7 @@ class PostHighlightingVisitor { PostHighlightingVisitor(@NotNull PsiFile file, @NotNull Document document, - @NotNull RefCountHolder refCountHolder, - @NotNull HighlightingSession highlightingSession) throws ProcessCanceledException { - myHighlightingSession = highlightingSession; + @NotNull RefCountHolder refCountHolder) throws ProcessCanceledException { myProject = file.getProject(); myFile = file; myDocument = document; diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSession.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSession.java index c8e54875e6c9..017595c0e68a 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSession.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSession.java @@ -15,7 +15,6 @@ */ package com.intellij.codeInsight.daemon.impl; -import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColorsScheme; @@ -24,7 +23,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; -public interface HighlightingSession extends Disposable { +public interface HighlightingSession { @NotNull Project getProject(); @NotNull PsiFile getPsiFile(); Editor getEditor(); diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSessionImpl.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSessionImpl.java index 94640f84aeab..94d69dab0a5f 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSessionImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightingSessionImpl.java @@ -24,7 +24,6 @@ import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; @@ -48,7 +47,6 @@ public class HighlightingSessionImpl implements HighlightingSession { @NotNull private final Project myProject; private final Document myDocument; private final Map myRanges2markersCache = new THashMap(); - private volatile boolean myDisposed; private HighlightingSessionImpl(@NotNull PsiFile psiFile, @Nullable Editor editor, @@ -60,10 +58,6 @@ public class HighlightingSessionImpl implements HighlightingSession { myEditorColorsScheme = editorColorsScheme; myProject = psiFile.getProject(); myDocument = PsiDocumentManager.getInstance(myProject).getDocument(psiFile); - Disposer.register(progressIndicator, this); - if (progressIndicator.isCanceled()) { - Disposer.dispose(progressIndicator); //dispose both progress indicator and this session in case we managed to register after indicator dispose to avoid mem leaks - } } private static final Key> HIGHLIGHTING_SESSION = Key.create("HIGHLIGHTING_SESSION"); @@ -159,7 +153,7 @@ public class HighlightingSessionImpl implements HighlightingSession { @NotNull TextRange priorityRange, @NotNull TextRange restrictedRange, int groupId) { - myAddHighlighterInEDTQueue.offer(new Info(info, priorityRange, restrictedRange, groupId)); + myAddHighlighterInEDTQueue.offer(new Info(info, restrictedRange, groupId)); } void queueDisposeHighlighter(@Nullable RangeHighlighterEx highlighter) { @@ -167,20 +161,13 @@ public class HighlightingSessionImpl implements HighlightingSession { myDisposeHighlighterInEDTQueue.offer(highlighter); } - @Override - public void dispose() { - myDisposed = true; - } - private static class Info { @NotNull private final HighlightInfo myInfo; - @NotNull private final TextRange myPriorityRange; @NotNull private final TextRange myRestrictRange; private final int myGroupId; - public Info(@NotNull HighlightInfo info, @NotNull TextRange priorityRange, @NotNull TextRange restrictRange, int groupId) { + private Info(@NotNull HighlightInfo info, @NotNull TextRange restrictRange, int groupId) { myInfo = info; - myPriorityRange = priorityRange; myRestrictRange = restrictRange; myGroupId = groupId; } From 9603c36d8c94a27b35a2dd9ae3918e168209d38f Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 26 Aug 2015 15:10:08 +0300 Subject: [PATCH 008/172] made non-recursive --- .../com/intellij/util/ui/tree/TreeUtil.java | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java index d3e281010192..92348089686e 100644 --- a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java +++ b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java @@ -154,20 +154,12 @@ public final class TreeUtil { } @NotNull - public static TreePath getPath(final TreeNode aRootNode, @NotNull final TreeNode aNode) { - final List pathStack = new ArrayList(); - addEach(aRootNode, aNode, pathStack); - - final Object[] pathElements = new Object[pathStack.size()]; - - for (int i = pathStack.size() - 1; i >= 0; i--) { - pathElements[pathStack.size() - i - 1] = pathStack.get(i); - } - - return new TreePath(pathElements); + public static TreePath getPath(@NotNull TreeNode aRootNode, @NotNull TreeNode aNode) { + TreeNode[] nodes = getPathFromRootTo(aRootNode, aNode, true); + return new TreePath(nodes); } - public static boolean isAncestor(final TreeNode ancestor, final TreeNode node) { + public static boolean isAncestor(@NotNull TreeNode ancestor, @NotNull TreeNode node) { TreeNode parent = node; while (parent != null) { if (parent == ancestor) return true; @@ -192,21 +184,21 @@ public final class TreeUtil { @NotNull public static TreePath getPathFromRoot(@NotNull TreeNode node) { - TreeNode[] path = getPathFromRoot(node, 1); + TreeNode[] path = getPathFromRootTo(null, node, false); return new TreePath(path); } @NotNull - private static TreeNode[] getPathFromRoot(@NotNull TreeNode node, int depth) { - TreeNode[] path; - TreeNode parent = node.getParent(); - if (parent == null) { - path = new TreeNode[depth]; + private static TreeNode[] getPathFromRootTo(@Nullable TreeNode root, @NotNull TreeNode node, boolean includeRoot) { + int height = 0; + for (TreeNode n = node; n != root; n = n.getParent()) { + height++; } - else { - path = getPathFromRoot(parent, depth + 1); + TreeNode[] path = new TreeNode[includeRoot ? height+1 : height]; + int i = path.length-1; + for (TreeNode n = node; i>=0; n = n.getParent()) { + path[i--] = n; } - path[path.length - depth] = node; return path; } @@ -294,14 +286,6 @@ public final class TreeUtil { return selectionPath; } - private static void addEach(final TreeNode aRootNode, @NotNull final TreeNode aNode, @NotNull final List aPathStack) { - aPathStack.add(aNode); - - if (aNode != aRootNode) { - addEach(aRootNode, aNode.getParent(), aPathStack); - } - } - @NotNull private static IndexTreePathState removeLastPathComponent(@NotNull final DefaultTreeModel model, @NotNull final TreePath pathToBeRemoved) { final IndexTreePathState selectionState = new IndexTreePathState(pathToBeRemoved); @@ -343,11 +327,11 @@ public final class TreeUtil { return result.toArray(new TreePath[result.size()]); } - public static void sort(@NotNull final DefaultTreeModel model, final Comparator comparator) { + public static void sort(@NotNull final DefaultTreeModel model, @Nullable Comparator comparator) { sort((DefaultMutableTreeNode) model.getRoot(), comparator); } - public static void sort(@NotNull final DefaultMutableTreeNode node, final Comparator comparator) { + public static void sort(@NotNull final DefaultMutableTreeNode node, @Nullable Comparator comparator) { final List children = childrenToArray(node); Collections.sort(children, comparator); node.removeAllChildren(); From 1b1cf922491b50e1001911662d401b912d1283f8 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 26 Aug 2015 19:15:47 +0300 Subject: [PATCH 009/172] cleanup --- .../custom/CustomFileTypeLexerTest.groovy | 7 ++-- .../openapi/util/text/StringUtil.java | 33 ++++++++----------- .../containers/ConcurrentPackedBitsArray.java | 2 ++ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy index 7f13b49765c9..c92e592d4ce0 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy @@ -1,8 +1,7 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * - * Licensed under the Apache License, Version 2.0 (the "License") - + * 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 * @@ -27,6 +26,7 @@ import com.intellij.util.Processor import com.intellij.util.ThrowableRunnable import junit.framework.TestCase import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable /** * @author peter @@ -422,6 +422,7 @@ class SlowCharSequence extends StringUtil.BombedCharSequence { super(sequence) } + @NotNull @Override CharSequence subSequence(int i, int i1) { return new SlowCharSequence(super.subSequence(i, i1)) diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 7748c3e26404..a5c4a185b557 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -58,6 +58,7 @@ public class StringUtil extends StringUtilRt { new ParserDelegator().parse(in, this, Boolean.TRUE); } + @Override public void handleText(char[] text, int pos) { if (myBuffer.length() > 0) myBuffer.append(SystemProperties.getLineSeparator()); @@ -67,9 +68,9 @@ public class StringUtil extends StringUtilRt { public String getText() { return myBuffer.toString(); } - }; + } - private static MyHtml2Text html2TextParser = new MyHtml2Text(); + private static final MyHtml2Text html2TextParser = new MyHtml2Text(); public static final NotNullFunction QUOTER = new NotNullFunction() { @Override @@ -499,12 +500,7 @@ public class StringUtil extends StringUtilRt { } } } - if (buffer == null) { - return s; - } - else { - return buffer.toString(); - } + return buffer == null ? s : buffer.toString(); } @NonNls private static final String[] ourPrepositions = { @@ -524,7 +520,7 @@ public class StringUtil extends StringUtilRt { if (lastChar - firstChar + 1 == preposition.length()) { found = true; for (int j = 0; j < preposition.length(); j++) { - if (!(toLowerCase(s.charAt(firstChar + j)) == preposition.charAt(j))) { + if (toLowerCase(s.charAt(firstChar + j)) != preposition.charAt(j)) { found = false; } } @@ -786,7 +782,7 @@ public class StringUtil extends StringUtilRt { if (escaped) buffer.append('\\'); } - @SuppressWarnings({"HardCodedStringLiteral"}) + @SuppressWarnings("HardCodedStringLiteral") @NotNull @Contract(pure = true) public static String pluralize(@NotNull String suggestion) { @@ -1140,7 +1136,7 @@ public class StringUtil extends StringUtilRt { @Contract(value = "null -> true",pure = true) // we need to keep this method to preserve backward compatibility public static boolean isEmptyOrSpaces(@Nullable String s) { - return isEmptyOrSpaces(((CharSequence)s)); + return isEmptyOrSpaces((CharSequence)s); } @Contract(value = "null -> true", pure = true) @@ -1601,7 +1597,7 @@ public class StringUtil extends StringUtilRt { * @param name english word in plural form * @return name in singular form or null if failed to find one. */ - @SuppressWarnings({"HardCodedStringLiteral"}) + @SuppressWarnings("HardCodedStringLiteral") @Nullable @Contract(pure = true) public static String unpluralize(@NotNull final String name) { @@ -2324,15 +2320,13 @@ public class StringUtil extends StringUtilRt { if (methodName.startsWith("get")) { return Introspector.decapitalize(methodName.substring(3)); } - else if (methodName.startsWith("is")) { + if (methodName.startsWith("is")) { return Introspector.decapitalize(methodName.substring(2)); } - else if (methodName.startsWith("set")) { + if (methodName.startsWith("set")) { return Introspector.decapitalize(methodName.substring(3)); } - else { - return null; - } + return null; } @Contract(pure = true) @@ -2739,7 +2733,7 @@ public class StringUtil extends StringUtilRt { if (i < string1Length) { return 1; } - else if (j < string2Length) { + if (j < string2Length) { return -1; } if (!caseSensitive && string1Length == string2Length) { @@ -3249,7 +3243,7 @@ public class StringUtil extends StringUtilRt { */ public abstract static class BombedCharSequence implements CharSequence { private final CharSequence delegate; - private int i = 0; + private int i; public BombedCharSequence(@NotNull CharSequence sequence) { delegate = sequence; @@ -3282,6 +3276,7 @@ public class StringUtil extends StringUtilRt { protected abstract void checkCanceled(); + @NotNull @Override public CharSequence subSequence(int i, int i1) { check(); diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentPackedBitsArray.java b/platform/util/src/com/intellij/util/containers/ConcurrentPackedBitsArray.java index f7facc262c3b..17757ee73818 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentPackedBitsArray.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentPackedBitsArray.java @@ -42,6 +42,7 @@ public class ConcurrentPackedBitsArray { * The returned bits are LSB, other (64-bitsPerChunk) higher bits are undefined */ public long get(int id) { + assert id >= 0 : id; int bitIndex = id/chunksPerWord * 64 + (id%chunksPerWord)*bitsPerChunk; long word = bits.getWord(bitIndex) >> bitIndex; return word; @@ -49,6 +50,7 @@ public class ConcurrentPackedBitsArray { // stores chunk atomically, returns previous chunk public long set(int id, final long flags) { + assert id >= 0 : id; if ((flags & ~mask) != 0) { throw new IllegalArgumentException("Flags must be between 0 and "+ mask +" but got:"+flags); } From 87107c0a5831235d24d69a35b56859002fc1d594 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 27 Aug 2015 14:56:22 +0200 Subject: [PATCH 010/172] groovy compilation: when class dependencies fail to be loaded, don't mark it as checked --- .../compiler/rt/ClassDependencyLoader.java | 18 ++++++++++++++---- .../groovy/compiler/GroovyCompilerTest.groovy | 11 ++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/ClassDependencyLoader.java b/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/ClassDependencyLoader.java index bbe739a59f55..596736914ac3 100644 --- a/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/ClassDependencyLoader.java +++ b/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/ClassDependencyLoader.java @@ -99,11 +99,21 @@ public class ClassDependencyLoader { aPackage.getAnnotations(); } } - catch (LinkageError e) { - throw new ClassNotFoundException(name); + catch (Error e) { + myVisited.remove(aClass); + //noinspection InstanceofCatchParameter + if (e instanceof LinkageError) { + throw new ClassNotFoundException(name); + } + throw e; } - catch (TypeNotPresentException e) { - throw new ClassNotFoundException(name); + catch (RuntimeException e) { + myVisited.remove(aClass); + //noinspection InstanceofCatchParameter + if (e instanceof TypeNotPresentException) { + throw new ClassNotFoundException(name); + } + throw e; } } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index a5ea26bcc2b7..15cac8b9e450 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -884,11 +884,20 @@ class AppTest { } public void "test extend groovy classes with additional dependencies"() { + def anotherModule = addModule("another", true) + addGroovyLibrary(anotherModule) + PsiTestUtil.addLibrary(myModule, "junit", GroovyFacetUtil.libDirectory, "junit.jar"); - PsiTestUtil.addLibrary(myModule, "cli", FileUtil.toCanonicalPath(PluginPathManager.getPluginHomePath("groovy") + "/../../build/lib"), "commons-cli-1.2.jar"); + + def cliPath = FileUtil.toCanonicalPath(PluginPathManager.getPluginHomePath("groovy") + "/../../build/lib") + PsiTestUtil.addLibrary(myModule, "cli", cliPath, "commons-cli-1.2.jar"); + PsiTestUtil.addLibrary(anotherModule, "cli", cliPath, "commons-cli-1.2.jar"); myFixture.addFileToProject("a.groovy", "class Foo extends GroovyTestCase {}") myFixture.addFileToProject("b.groovy", "class Bar extends CliBuilder {}") + + myFixture.addFileToProject("another/b.groovy", "class AnotherBar extends CliBuilder {}") + assertEmpty(make()) } From d032220be156503a542185a0d5ea9c6e54c61728 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 27 Aug 2015 16:02:15 +0300 Subject: [PATCH 011/172] Rename option --- .../ide/actions/ToggleDistractionFreeModeAction.java | 2 +- .../openapi/editor/ex/EditorSettingsExternalizable.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToggleDistractionFreeModeAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToggleDistractionFreeModeAction.java index 72c4e8a6b21d..497f2e6a1dba 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ToggleDistractionFreeModeAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToggleDistractionFreeModeAction.java @@ -95,7 +95,7 @@ public class ToggleDistractionFreeModeAction extends DumbAwareAction { p.setValue(before + "ARE_LINE_NUMBERS_SHOWN", valueOf(eo.ARE_LINE_NUMBERS_SHOWN)); eo.ARE_LINE_NUMBERS_SHOWN = p.getBoolean(after + "ARE_LINE_NUMBERS_SHOWN", value); p.setValue(before + "IS_RIGHT_MARGIN_SHOWN", valueOf(eo.IS_RIGHT_MARGIN_SHOWN)); eo.IS_RIGHT_MARGIN_SHOWN = p.getBoolean(after + "IS_RIGHT_MARGIN_SHOWN", value); p.setValue(before + "IS_INDENT_GUIDES_SHOWN", valueOf(eo.IS_INDENT_GUIDES_SHOWN)); eo.IS_INDENT_GUIDES_SHOWN = p.getBoolean(after + "IS_INDENT_GUIDES_SHOWN", value); - p.setValue(before + "ARE_BREADCRUMBS_SHOWN", valueOf(eo.ARE_BREADCRUMBS_SHOWN)); eo.ARE_BREADCRUMBS_SHOWN = p.getBoolean(after + "ARE_BREADCRUMBS_SHOWN", value); + p.setValue(before + "SHOW_BREADCRUMBS", valueOf(eo.SHOW_BREADCRUMBS)); eo.SHOW_BREADCRUMBS = p.getBoolean(after + "SHOW_BREADCRUMBS", value); p.setValue(before + "SHOW_METHOD_SEPARATORS", valueOf(ds.SHOW_METHOD_SEPARATORS)); ds.SHOW_METHOD_SEPARATORS = p.getBoolean(after + "SHOW_METHOD_SEPARATORS", value); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java index b416e2b4683d..53c00623ea88 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java @@ -52,7 +52,7 @@ public class EditorSettingsExternalizable implements PersistentStateComponent Date: Thu, 27 Aug 2015 16:15:24 +0300 Subject: [PATCH 012/172] IDEA-144350 Smart step into proposes weird options --- .../actions/JavaSmartStepIntoHandler.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java index e23f017b6de3..4cfc4ba97d7d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java @@ -126,6 +126,24 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { } } + @Override + public void visitField(PsiField field) { + TextRange range = field.getTextRange(); + if (lineRange.intersects(range)) { + //textRange.set(textRange.get().union(range)); + super.visitField(field); + } + } + + @Override + public void visitMethod(PsiMethod method) { + TextRange range = method.getTextRange(); + if (lineRange.intersects(range)) { + //textRange.set(textRange.get().union(range)); + super.visitMethod(method); + } + } + @Override public void visitStatement(PsiStatement statement) { TextRange range = statement.getTextRange(); From c483efa47943f8d0ad945e271573886ab4c96f2c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 27 Aug 2015 15:47:12 +0200 Subject: [PATCH 013/172] IDEA-30246 (Merge else-if kills comments) --- .../ipp/trivialif/MergeElseIfIntention.java | 62 +++++++++++++++--- .../trivialif/MergeElseIfIntentionTest.java | 63 +++++++++++++++++++ 2 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/MergeElseIfIntentionTest.java diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeElseIfIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeElseIfIntention.java index ab81f4cbdad9..7f4212d4d115 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeElseIfIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeElseIfIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,31 +16,73 @@ package com.siyeh.ipp.trivialif; import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + public class MergeElseIfIntention extends Intention { + @Override @NotNull public PsiElementPredicate getElementPredicate() { return new MergeElseIfPredicate(); } - public void processIntention(PsiElement element) - throws IncorrectOperationException { + @Override + public void processIntention(PsiElement element) { final PsiJavaToken token = (PsiJavaToken)element; - final PsiIfStatement parentStatement = - (PsiIfStatement)token.getParent(); + final PsiIfStatement parentStatement = (PsiIfStatement)token.getParent(); assert parentStatement != null; - final PsiBlockStatement elseBranch = - (PsiBlockStatement)parentStatement.getElseBranch(); + final PsiBlockStatement elseBranch = (PsiBlockStatement)parentStatement.getElseBranch(); assert elseBranch != null; + final PsiElement lastChild = elseBranch.getLastChild(); final PsiCodeBlock elseBranchBlock = elseBranch.getCodeBlock(); - final PsiStatement elseBranchContents = - elseBranchBlock.getStatements()[0]; + final PsiStatement elseBranchContents = elseBranchBlock.getStatements()[0]; + final PsiElement grandParent = parentStatement.getParent(); + if (lastChild instanceof PsiComment) { + addElementAndPrevWhiteSpace(lastChild, grandParent, parentStatement); + } + final List before = new ArrayList(1); + final List after = new ArrayList(1); + collectComments(elseBranchContents, before, after); + for (PsiComment comment : before) { + addElementAndPrevWhiteSpace(comment, parentStatement, token); + } + for (PsiComment comment : after) { + grandParent.addAfter(comment, parentStatement); + } PsiReplacementUtil.replaceStatement(elseBranch, elseBranchContents.getText()); } + + private static void addElementAndPrevWhiteSpace(PsiElement element, PsiElement container, PsiElement anchor) { + final PsiElement sibling = element.getPrevSibling(); + container.addAfter(element, anchor); + if (sibling instanceof PsiWhiteSpace) { + container.addAfter(sibling, anchor); + } + } + + /** + * Before comments are added in reverse order of appearance in the code. + */ + private static void collectComments(PsiStatement statement, List before, List after) { + PsiElement prevSibling = statement.getPrevSibling(); + while (prevSibling != null) { + if (prevSibling instanceof PsiComment) { + before.add((PsiComment)prevSibling); + } + prevSibling = prevSibling.getPrevSibling(); + } + PsiElement nextSibing = statement.getNextSibling(); + while (nextSibing != null) { + if (nextSibing instanceof PsiComment) { + after.add((PsiComment)nextSibing); + } + nextSibing = nextSibing.getNextSibling(); + } + } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/MergeElseIfIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/MergeElseIfIntentionTest.java new file mode 100644 index 000000000000..fb4324e1e99e --- /dev/null +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/trivialif/MergeElseIfIntentionTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2015 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. + */ + +/** + * (c) 2015 Silent Forest AB + * created: 27 August 2015 + */ +package com.siyeh.ipp.trivialif; + +import com.siyeh.ipp.IPPTestCase; + +/** + * @author Bas Leijdekkers + */ +public class MergeElseIfIntentionTest extends IPPTestCase { + + public void testCommentsAreKept() { + doTest("class X {\n" + + " void test(boolean foo, boolean bar) {\n" + + " if (foo) { //asdf\n" + + "\n" + + " } else/*_Merge 'else if'*/ {\n" + + " // blubb\n" + + " // blabb\n" + + " if (bar) { // asdf3\n" + + "\n" + + " } // other\n" + + " // bla\n" + + " } // asdf1\n" + + " // asdf4\n" + + " }\n" + + "}\n", + + "class X {\n" + + " void test(boolean foo, boolean bar) {\n" + + " if (foo) { //asdf\n" + + "\n" + + " } else\n" + + " // blubb\n" + + " // blabb\n" + + " if (bar) { // asdf3\n" + + "\n" + + " } // other\n" + + "// bla\n" + + "// asdf1\n" + + " // asdf4\n" + + " }\n" + + "}\n"); + } +} From 4e5faa4c7bcd2f629f3edd1906670325c127cf3c Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 27 Aug 2015 15:38:30 +0200 Subject: [PATCH 014/172] unify how java lookup elements determine their type --- .../completion/ConstructorInsertHandler.java | 2 +- .../completion/JavaCompletionContributor.java | 2 +- .../completion/JavaCompletionUtil.java | 42 +------------------ .../JavaPsiClassReferenceElement.java | 15 ++++--- .../NullSmartCompletionContributor.java | 2 - .../TypeArgumentCompletionProvider.java | 2 +- .../codeInsight/lookup/PsiTypeLookupItem.java | 15 +++---- .../template/macro/ComponentTypeOfMacro.java | 5 +-- .../codeInsight/lookup/LookupItem.java | 1 - .../completion/GroovyNoVariantsDelegator.java | 21 +++++++++- 10 files changed, 43 insertions(+), 64 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index 64a16addf3c3..4c81a4e2a87a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -178,7 +178,7 @@ public class ConstructorInsertHandler implements InsertHandler { +public class JavaPsiClassReferenceElement extends LookupItem implements TypedLookupItem { public static final Key PACKAGE_NAME = Key.create("PACKAGE_NAME"); public static final ClassConditionKey CLASS_CONDITION_KEY = ClassConditionKey.create(JavaPsiClassReferenceElement.class); private final Object myClass; @@ -63,6 +60,14 @@ public class JavaPsiClassReferenceElement extends LookupItem { return myForcedPresentableName; } + @Nullable + @Override + public PsiType getType() { + PsiClass psiClass = getObject(); + final PsiSubstitutor substitutor = (PsiSubstitutor)getAttribute(LookupItem.SUBSTITUTOR); + return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, substitutor == null ? PsiSubstitutor.EMPTY : substitutor); + } + @NotNull @Override public String getLookupString() { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/NullSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/NullSmartCompletionContributor.java index fdfd1b3f93f0..6e433c81d280 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/NullSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/NullSmartCompletionContributor.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiKeyword; import com.intellij.psi.PsiPrimitiveType; -import com.intellij.psi.PsiType; import java.util.Collection; import java.util.LinkedHashSet; @@ -53,7 +52,6 @@ public class NullSmartCompletionContributor extends CompletionContributor{ for (final ExpectedTypeInfo info : infos) { if (!(info.getType() instanceof PsiPrimitiveType)) { final LookupItem item = (LookupItem)BasicExpressionCompletionContributor.createKeywordLookupItem(parameters.getPosition(), PsiKeyword.NULL); - item.setAttribute(LookupItem.TYPE, PsiType.NULL); result.addElement(JavaSmartCompletionContributor.decorate(item, infos)); return; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java index 7f6920917c96..8c7af834937d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java @@ -217,7 +217,7 @@ class TypeArgumentCompletionProvider extends CompletionProvider DEFAULT_IMPORT_FIXER = new InsertHandler() { @Override public void handleInsert(InsertionContext context, PsiTypeLookupItem item) { @@ -65,13 +65,14 @@ public class PsiTypeLookupItem extends LookupItem { } @NotNull - public PsiType getPsiType() { + @Override + public PsiType getType() { Object object = getObject(); PsiType type = object instanceof PsiType ? (PsiType)object : JavaPsiFacade.getElementFactory(((PsiClass) object).getProject()).createType((PsiClass)object); for (int i = 0; i < getBracketsCount(); i++) { type = new PsiArrayType(type); } - return type; + return getSubstitutor().substitute(type); } @@ -191,18 +192,14 @@ public class PsiTypeLookupItem extends LookupItem { } - public static PsiTypeLookupItem createLookupItem(@NotNull PsiType type, @Nullable PsiElement context, boolean isDiamond, InsertHandler importFixer) { - final PsiType original = type; + public static PsiTypeLookupItem createLookupItem(@NotNull PsiType type, @Nullable PsiElement context, boolean isDiamond, InsertHandler importFixer) { int dim = 0; while (type instanceof PsiArrayType) { type = ((PsiArrayType)type).getComponentType(); dim++; } - PsiTypeLookupItem item = doCreateItem(type, context, dim, isDiamond, importFixer); - - item.setAttribute(TYPE, original); - return item; + return doCreateItem(type, context, dim, isDiamond, importFixer); } private static PsiTypeLookupItem doCreateItem(final PsiType type, diff --git a/java/java-impl/src/com/intellij/codeInsight/template/macro/ComponentTypeOfMacro.java b/java/java-impl/src/com/intellij/codeInsight/template/macro/ComponentTypeOfMacro.java index d4ecc14c003e..5ab66a10ad6b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/macro/ComponentTypeOfMacro.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/macro/ComponentTypeOfMacro.java @@ -20,7 +20,6 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.PsiTypeLookupItem; import com.intellij.codeInsight.template.*; import com.intellij.psi.PsiArrayType; -import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiType; import com.intellij.util.containers.ContainerUtil; @@ -49,7 +48,7 @@ public class ComponentTypeOfMacro extends Macro { for (LookupElement element : lookupItems) { PsiTypeLookupItem lookupItem = element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY); if (lookupItem != null) { - PsiType psiType = lookupItem.getPsiType(); + PsiType psiType = lookupItem.getType(); if (psiType instanceof PsiArrayType) { result.add(PsiTypeLookupItem.createLookupItem(((PsiArrayType)psiType).getComponentType(), null)); } @@ -83,7 +82,7 @@ public class ComponentTypeOfMacro extends Macro { for (LookupElement element : elements) { PsiTypeLookupItem typeLookupItem = element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY); if (typeLookupItem != null) { - PsiType psiType = typeLookupItem.getPsiType(); + PsiType psiType = typeLookupItem.getType(); if (psiType instanceof PsiArrayType) { return new PsiTypeResult(((PsiArrayType)psiType).getComponentType(), context.getProject()); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java index 9b846da394f5..d1dc8be21110 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java @@ -53,7 +53,6 @@ public class LookupItem extends MutableLookupElement implements Comparable public static final Object FORCE_QUALIFY = Key.create("FORCE_QUALIFY"); public static final Object SUBSTITUTOR = Key.create("SUBSTITUTOR"); - public static final Object TYPE = Key.create("TYPE"); public static final Object CASE_INSENSITIVE = Key.create("CASE_INSENSITIVE"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java index cb272e202350..2de1abf9f2df 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java @@ -25,6 +25,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; @@ -118,7 +119,7 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { final CompletionResultSet qualifiedCollector = result.withPrefixMatcher(fullPrefix); InheritorsHolder inheritors = new InheritorsHolder(result); for (final LookupElement base : suggestQualifierItems(parameters, (GrReferenceElement)qualifier, inheritors)) { - final PsiType type = JavaCompletionUtil.getLookupElementType(base); + final PsiType type = getPsiType(base.getObject()); if (type != null && !PsiType.VOID.equals(type)) { GrReferenceElement ref = createMockReference(position, type, base); PsiElement refName = ref.getReferenceNameElement(); @@ -139,6 +140,24 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { } } + @Nullable + private static PsiType getPsiType(final Object o) { + if (o instanceof ResolveResult) { + return getPsiType(((ResolveResult)o).getElement()); + } + if (o instanceof PsiVariable) { + return ((PsiVariable)o).getType(); + } + else if (o instanceof PsiMethod) { + return ((PsiMethod)o).getReturnType(); + } + else if (o instanceof PsiClass) { + final PsiClass psiClass = (PsiClass)o; + return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); + } + return null; + } + private static GrReferenceElement createMockReference(final PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) { GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(place.getProject()); if (qualifierItem.getObject() instanceof PsiClass) { From 5dbe3518bf981c23cd3d5cb8e1885b6ec4f78f19 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 20 Aug 2015 20:01:53 +0300 Subject: [PATCH 015/172] diff: allow to pass additional actions via action group --- .../actions/impl/FocusOppositePaneAction.java | 10 ++++++++-- .../com/intellij/diff/merge/TextMergeTool.java | 5 +++-- .../diff/tools/fragmented/UnifiedDiffViewer.java | 8 +++++++- .../diff/tools/simple/SimpleDiffViewer.java | 10 ++++++++-- .../tools/simple/SimpleOnesideDiffViewer.java | 8 +++++++- .../tools/simple/SimpleThreesideDiffViewer.java | 8 +++++++- .../diff/tools/util/base/DiffViewerBase.java | 16 +++++++++------- .../openapi/actionSystem/IdeActions.java | 2 ++ .../src/idea/PlatformActions.xml | 2 ++ 9 files changed, 53 insertions(+), 16 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java index 3415e681255f..982623b5fe0a 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java @@ -33,6 +33,8 @@ public class FocusOppositePaneAction extends AnAction implements DumbAware { public FocusOppositePaneAction(boolean scrollToPosition) { myScrollToPosition = scrollToPosition; setEnabledInModalContext(true); + + EmptyAction.setupAction(this, getActionId(), null); } @Override @@ -41,7 +43,11 @@ public class FocusOppositePaneAction extends AnAction implements DumbAware { } public void setupAction(@NotNull JComponent component) { - String action = myScrollToPosition ? "Diff.FocusOppositePaneAndScroll" : "Diff.FocusOppositePane"; - EmptyAction.setupAction(this, action, component); + registerCustomShortcutSet(getShortcutSet(), component); + } + + @NotNull + private String getActionId() { + return myScrollToPosition ? "Diff.FocusOppositePaneAndScroll" : "Diff.FocusOppositePane"; } } \ No newline at end of file diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java index a82a03b741c4..0b24f14f1633 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeTool.java @@ -30,6 +30,7 @@ import com.intellij.diff.requests.SimpleDiffRequest; import com.intellij.diff.tools.simple.ThreesideTextDiffViewerEx; import com.intellij.diff.tools.util.DiffNotifications; import com.intellij.diff.tools.util.KeyboardModifierListener; +import com.intellij.diff.tools.util.base.TextDiffViewerUtil; import com.intellij.diff.util.*; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; @@ -273,9 +274,9 @@ public class TextMergeTool implements MergeTool { group.add(new ApplySelectedChangesAction(Side.RIGHT, false)); group.add(new IgnoreSelectedChangesAction(Side.LEFT, false)); group.add(new IgnoreSelectedChangesAction(Side.RIGHT, false)); - group.add(Separator.getInstance()); - group.addAll(super.createEditorPopupActions()); + group.add(Separator.getInstance()); + group.addAll(TextDiffViewerUtil.createEditorPopupActions()); return group; } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java index dae717310766..d54b5158f70f 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedDiffViewer.java @@ -191,6 +191,9 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { group.add(new MyReadOnlyLockAction()); group.add(myEditorSettingsAction); + group.add(Separator.getInstance()); + group.addAll(super.createToolbarActions()); + return group; } @@ -206,6 +209,9 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { group.add(Separator.getInstance()); group.add(new MyToggleExpandByDefaultAction()); + group.add(Separator.getInstance()); + group.addAll(super.createPopupActions()); + return group; } @@ -219,8 +225,8 @@ public class UnifiedDiffViewer extends ListenerDiffViewerBase { group.add(new AppendSelectedChangesAction(Side.RIGHT, false)); group.add(new RevertSelectedChangesAction(Side.LEFT)); group.add(new RevertSelectedChangesAction(Side.RIGHT)); - group.add(Separator.getInstance()); + group.add(Separator.getInstance()); group.addAll(TextDiffViewerUtil.createEditorPopupActions()); return group; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java index a2d0a598e953..d33009779ff7 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java @@ -115,10 +115,13 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { group.add(new MyReadOnlyLockAction()); group.add(myEditorSettingsAction); + group.add(Separator.getInstance()); + group.addAll(super.createToolbarActions()); + return group; } - @Nullable + @NotNull @Override protected List createPopupActions() { List group = new ArrayList(); @@ -131,6 +134,9 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { group.add(new MyToggleAutoScrollAction()); group.add(new MyToggleExpandByDefaultAction()); + group.add(Separator.getInstance()); + group.addAll(super.createPopupActions()); + return group; } @@ -145,8 +151,8 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { group.add(new AppendSelectedChangesAction(Side.RIGHT, false)); group.add(new RevertSelectedChangesAction(Side.LEFT)); group.add(new RevertSelectedChangesAction(Side.RIGHT)); - group.add(Separator.getInstance()); + group.add(Separator.getInstance()); group.addAll(super.createEditorPopupActions()); return group; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleOnesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleOnesideDiffViewer.java index ad630c48639b..9f76fe97368a 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleOnesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleOnesideDiffViewer.java @@ -80,10 +80,13 @@ public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer { group.add(new MyReadOnlyLockAction()); group.add(myEditorSettingsAction); + group.add(Separator.getInstance()); + group.addAll(super.createToolbarActions()); + return group; } - @Nullable + @NotNull @Override protected List createPopupActions() { List group = new ArrayList(); @@ -93,6 +96,9 @@ public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer { group.add(Separator.getInstance()); group.add(new MyHighlightPolicySettingAction().getPopupGroup()); + group.add(Separator.getInstance()); + group.addAll(super.createPopupActions()); + return group; } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java index adc2a32c1489..bf76d6ca144d 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java @@ -78,10 +78,13 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx { group.add(new ShowBaseRightPartialDiffAction()); group.add(new ShowLeftRightPartialDiffAction()); + group.add(Separator.getInstance()); + group.addAll(super.createToolbarActions()); + return group; } - @Nullable + @NotNull @Override protected List createPopupActions() { List group = new ArrayList(); @@ -94,6 +97,9 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx { group.add(new MyToggleAutoScrollAction()); group.add(new MyToggleExpandByDefaultAction()); + group.add(Separator.getInstance()); + group.addAll(super.createPopupActions()); + return group; } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java index 657e0d3a5561..a17deb7f07df 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java @@ -21,9 +21,7 @@ import com.intellij.diff.FrameDiffTool.DiffViewer; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.tools.util.DiffDataKeys; import com.intellij.diff.util.DiffTaskQueue; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -33,10 +31,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.util.Alarm; import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.*; import javax.swing.*; +import java.util.ArrayList; import java.util.List; public abstract class DiffViewerBase implements DiffViewer, DataProvider { @@ -186,14 +186,16 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider { return myContext.isWindowFocused(); } - @Nullable protected List createToolbarActions() { - return null; + List group = new ArrayList(); + ContainerUtil.addAll(group, ((ActionGroup)ActionManager.getInstance().getAction(IdeActions.DIFF_VIEWER_TOOLBAR)).getChildren(null)); + return group; } - @Nullable protected List createPopupActions() { - return null; + List group = new ArrayList(); + ContainerUtil.addAll(group, ((ActionGroup)ActionManager.getInstance().getAction(IdeActions.DIFF_VIEWER_POPUP)).getChildren(null)); + return group; } @Nullable diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java index 07ba96c59abc..7f2c50e9e5ce 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java @@ -167,6 +167,8 @@ public interface IdeActions { @NonNls String ACTION_PREVIOUS_DIFF = "PreviousDiff"; @NonNls String ACTION_NEXT_DIFF = "NextDiff"; @NonNls String GROUP_DIFF_EDITOR_POPUP = "Diff.EditorPopupMenu"; + @NonNls String DIFF_VIEWER_POPUP = "Diff.ViewerPopupMenu"; + @NonNls String DIFF_VIEWER_TOOLBAR = "Diff.ViewerToolbar"; @NonNls String ACTION_EXPAND_ALL = "ExpandAll"; @NonNls String ACTION_COLLAPSE_ALL = "CollapseAll"; diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index a37ba12507c0..0ba0116e1aa7 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -191,6 +191,8 @@ + + From 92a54c928df0691102ecbad53a06d8ce519bb075 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 30 Mar 2015 01:09:27 +0300 Subject: [PATCH 016/172] [vcs-log] big labels redesign * no more borders (flat labels); * 2 variants of label design: round with flags or square underlined; * improve colors (they do not make my eyes bleed anymore); * unify hg and git colors; * rewrite reference painter; * labels scale with increasing ui font; * group labels by root in branches panel. --- .../util/resources/misc/registry.properties | 1 + .../vcs/log/printer/idea/PrintParameters.java | 4 +- .../vcs/log/VcsLogStandardColors.java | 32 +++ .../vcs/log/ui/VcsLogColorManager.java | 12 - .../vcs/log/ui/VcsLogColorManagerImpl.java | 48 ++-- .../vcs/log/ui/frame/BranchesPanel.java | 113 ++++----- .../vcs/log/ui/frame/DetailsPanel.java | 56 +++-- .../vcs/log/ui/frame/VcsLogGraphTable.java | 14 +- .../log/ui/render/GraphCommitCellRender.java | 31 ++- .../vcs/log/ui/render/LabelPainters.java | 216 ++++++++++++++++++ .../vcs/log/ui/render/RefPainter.java | 177 -------------- .../src/git4idea/log/GitRefManager.java | 26 +-- .../org/zmlx/hg4idea/log/HgRefManager.java | 23 +- 13 files changed, 403 insertions(+), 350 deletions(-) create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/VcsLogStandardColors.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/RefPainter.java diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 9bbbe1a58742..9b7ad38fe876 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -237,6 +237,7 @@ vcs.showConsole=true vcs.log.bek.sort=true vcs.log.bek.sort.disabled=false vcs.log.linear.bek.sort=false +vcs.log.square.labels=false vcs.executable.validator.timeout.sec=60 diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PrintParameters.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PrintParameters.java index ae1849186f43..b2a066130fdf 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PrintParameters.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PrintParameters.java @@ -1,8 +1,5 @@ package com.intellij.vcs.log.printer.idea; -/** - * @author erokhins - */ public class PrintParameters { public static final int WIDTH_NODE = 15; @@ -11,4 +8,5 @@ public class PrintParameters { public static final float THICK_LINE = 1.5f; public static final float SELECT_THICK_LINE = 2.5f; + public static final int LABEL_PADDING = 3; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/VcsLogStandardColors.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/VcsLogStandardColors.java new file mode 100644 index 000000000000..3d4caee3ec24 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/VcsLogStandardColors.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2015 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.vcs.log; + +import com.intellij.ui.ColorUtil; +import com.intellij.ui.JBColor; + +import java.awt.*; + +public class VcsLogStandardColors { + public static class Refs { + public static final Color TIP = new JBColor(new Color(0xedea74), new Color(113, 111, 64)); + public static final Color LEAF = new JBColor(new Color(0xf478cc), new Color(0x6e2857)); + public static final Color BRANCH = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F)); + public static final Color BRANCH_REF = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker()); + public static final Color TAG = + new JBColor(ColorUtil.darker(new Color(255, 255, 255), 1), ColorUtil.brighter(new Color(60, 63, 65), 3)); + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManager.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManager.java index a9d942e5085a..6999f9a0f2ba 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManager.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManager.java @@ -23,16 +23,4 @@ public interface VcsLogColorManager { */ boolean isMultipleRoots(); - /** - * Returns the color of the border drawn around a reference label. - */ - @NotNull - Color getReferenceBorderColor(); - - /** - * Returns the color of the border separating the thin root indicator drawn at the left of the commit table. - */ - @NotNull - Color getRootIndicatorBorder(); - } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java index cfce5de26983..61064fe51bf6 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java @@ -1,9 +1,11 @@ package com.intellij.vcs.log.ui; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ColorUtil; import com.intellij.ui.JBColor; +import com.intellij.util.NotNullProducer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -16,15 +18,10 @@ import java.util.List; * @author Kirill Likhodedov */ public class VcsLogColorManagerImpl implements VcsLogColorManager { - - private static final Color REF_BORDER = JBColor.GRAY; - private static final Color ROOT_INDICATOR_BORDER = JBColor.LIGHT_GRAY; private static final Logger LOG = Logger.getInstance(VcsLogColorManagerImpl.class); - private static Color[] ROOT_COLORS = { - JBColor.RED, JBColor.GREEN, JBColor.BLUE, - JBColor.ORANGE, JBColor.CYAN, JBColor.YELLOW, - JBColor.MAGENTA, JBColor.PINK}; + private static Color[] ROOT_COLORS = + {JBColor.RED, JBColor.GREEN, JBColor.BLUE, JBColor.ORANGE, JBColor.CYAN, JBColor.YELLOW, JBColor.MAGENTA, JBColor.PINK}; @NotNull private final List myRoots; @@ -56,6 +53,30 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager { } } + @NotNull + public static JBColor getBackgroundVersion(@NotNull final Color rootColor) { + return new JBColor(new NotNullProducer() { + @NotNull + @Override + public Color produce() { + return ColorUtil.mix(rootColor, UIUtil.getTableBackground(), 0.75); + } + }); + } + + @NotNull + public static JBColor getIndicatorVersion(@NotNull final Color rootColor) { + if (Registry.is("vcs.log.square.labels")) return getBackgroundVersion(rootColor); + return new JBColor(new NotNullProducer() { + @NotNull + @Override + public Color produce() { + if (UIUtil.isUnderDarcula()) return rootColor; + return ColorUtil.darker(ColorUtil.softer(rootColor), 2); + } + }); + } + @Override public boolean isMultipleRoots() { return myRoots.size() > 1; @@ -75,17 +96,4 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager { private static Color getDefaultRootColor() { return UIUtil.getTableBackground(); } - - @NotNull - @Override - public Color getReferenceBorderColor() { - return REF_BORDER; - } - - @NotNull - @Override - public Color getRootIndicatorBorder() { - return ROOT_INDICATOR_BORDER; - } - } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java index 0a417a5bfb10..0c8cd92dac35 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java @@ -16,8 +16,9 @@ import com.intellij.vcs.log.data.RefsModel; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.impl.SingletonRefGroup; import com.intellij.vcs.log.impl.VcsLogUtil; +import com.intellij.vcs.log.ui.VcsLogColorManagerImpl; import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.render.RefPainter; +import com.intellij.vcs.log.ui.render.LabelPainters.ReferencePainter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,19 +28,23 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.*; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; /** * Panel with branch labels, above the graph. */ public class BranchesPanel extends JPanel { - + private static final int SMALL_ROOTS_GAP = 3; + private static final int BIG_ROOTS_GAP = 7; + private static final int VERTICAL_SPACE = 3; private final VcsLogDataHolder myDataHolder; private final VcsLogUiImpl myUI; - private List myRefGroups; - private final RefPainter myRefPainter; + private LinkedHashMap> myRefGroups; + private final ReferencePainter myReferencePainter; @Nullable private Collection myRoots = null; private Map myRefPositions = ContainerUtil.newHashMap(); @@ -48,9 +53,9 @@ public class BranchesPanel extends JPanel { myDataHolder = dataHolder; myUI = UI; myRefGroups = getRefsToDisplayOnPanel(initialRefsModel); - myRefPainter = new RefPainter(myUI.getColorManager(), true); + myReferencePainter = new ReferencePainter(myUI.getColorManager(), true); - setPreferredSize(new Dimension(-1, RefPainter.REF_HEIGHT + UIUtil.DEFAULT_VGAP)); + setPreferredSize(new Dimension(-1, myReferencePainter.getHeight(this) + UIUtil.DEFAULT_VGAP + VERTICAL_SPACE)); addMouseListener(new MouseAdapter() { @Override @@ -68,7 +73,7 @@ public class BranchesPanel extends JPanel { myUI.jumpToCommit(ref.getCommitHash()); } else { - final RefPopupComponent view = new RefPopupComponent(group, myUI, myRefPainter); + final ReferencePopupComponent view = new ReferencePopupComponent(group, myUI, myReferencePainter); JBPopup popup = view.getPopup(); popup.show(new RelativePoint(BranchesPanel.this, new Point(e.getX(), BranchesPanel.this.getHeight()))); } @@ -85,6 +90,11 @@ public class BranchesPanel extends JPanel { }); } + @Override + public Dimension getPreferredSize() { + return new Dimension(-1, myReferencePainter.getHeight(this) + 10); + } + @Nullable private RefGroup findRef(MouseEvent e) { List sortedPositions = Ordering.natural().sortedCopy(myRefPositions.keySet()); @@ -101,16 +111,21 @@ public class BranchesPanel extends JPanel { @Override protected void paintComponent(Graphics g) { myRefPositions = ContainerUtil.newHashMap(); - int paddingX = 0; - for (RefGroup group : myRefGroups) { - // TODO it is assumed here that all refs in a single group belong to a single root - VirtualFile root = group.getRefs().iterator().next().getRoot(); - if (myRoots == null || myRoots.contains(root)) { - Color rootIndicatorColor = myUI.getColorManager().getRootColor(root); - Rectangle rectangle = myRefPainter.drawLabel((Graphics2D)g, group.getName(), paddingX, group.getBgColor(), rootIndicatorColor); - paddingX += rectangle.width + UIUtil.DEFAULT_HGAP; - myRefPositions.put(rectangle.x, group); + int paddingX = BIG_ROOTS_GAP; + for (Map.Entry> entry : myRefGroups.entrySet()) { + VirtualFile root = entry.getKey(); + for (RefGroup group : entry.getValue()) { + // it is assumed here that all refs in a single group belong to a single root + if (myRoots == null || myRoots.contains(root)) { + Color rootIndicatorColor = VcsLogColorManagerImpl.getIndicatorVersion(myUI.getColorManager().getRootColor(root)); + Rectangle rectangle = myReferencePainter + .paintLabel(group.getName(), g, paddingX, (getHeight() - myReferencePainter.getHeight(this)) / 2 - VERTICAL_SPACE, group.getBgColor(), + rootIndicatorColor); + paddingX += rectangle.width + SMALL_ROOTS_GAP; + myRefPositions.put(rectangle.x, group); + } } + paddingX += BIG_ROOTS_GAP - SMALL_ROOTS_GAP; } } @@ -120,16 +135,15 @@ public class BranchesPanel extends JPanel { } @NotNull - private List getRefsToDisplayOnPanel(@NotNull VcsLogRefs refsModel) { + private LinkedHashMap> getRefsToDisplayOnPanel(@NotNull VcsLogRefs refsModel) { Collection allRefs = refsModel.getBranches(); - List groups = ContainerUtil.newArrayList(); + LinkedHashMap> groups = ContainerUtil.newLinkedHashMap(); for (Map.Entry> entry : VcsLogUtil.groupRefsByRoot(allRefs).entrySet()) { VirtualFile root = entry.getKey(); - Collection refs = entry.getValue(); - VcsLogProvider provider = myDataHolder.getLogProvider(root); - VcsLogRefManager refManager = provider.getReferenceManager(); - groups.addAll(expandExpandableGroups(refManager.group(refs))); + List list = ContainerUtil.newArrayList(); + list.addAll(expandExpandableGroups(myDataHolder.getLogProvider(root).getReferenceManager().group(entry.getValue()))); + groups.put(root, list); } return groups; @@ -158,27 +172,22 @@ public class BranchesPanel extends JPanel { getParent().repaint(); } - private static class RefPopupComponent extends JPanel { + private static class ReferencePopupComponent extends JPanel { + @NotNull private final JBPopup myPopup; + @NotNull private final JBList myList; + @NotNull private final VcsLogUiImpl myUi; + @NotNull private final SingleReferenceComponent myRendererComponent; + @NotNull private final ListCellRenderer myCellRenderer; - private final JBPopup myPopup; - private final JBList myList; - private final VcsLogUiImpl myUi; - private final RefPainter myRefPainter; - - private final SingleRefComponent myRendererComponent; - - private final ListCellRenderer myCellRenderer; - - RefPopupComponent(RefGroup group, VcsLogUiImpl ui, RefPainter refPainter) { + ReferencePopupComponent(@NotNull RefGroup group, @NotNull VcsLogUiImpl ui, @NotNull ReferencePainter referencePainter) { super(new BorderLayout()); myUi = ui; - myRefPainter = refPainter; - myRendererComponent = new SingleRefComponent(myRefPainter); + myRendererComponent = new SingleReferenceComponent(referencePainter); myCellRenderer = new ListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - myRendererComponent.setRef((VcsRef)value); + myRendererComponent.setReference((VcsRef)value); myRendererComponent.setSelected(isSelected); return myRendererComponent; } @@ -256,15 +265,16 @@ public class BranchesPanel extends JPanel { } } - private static class SingleRefComponent extends JPanel { + private static class SingleReferenceComponent extends JPanel { + private static final int PADDING_Y = 2; + private static final int PADDING_X = 5; + @NotNull private final ReferencePainter myReferencePainter; - private final RefPainter myRefPainter; - - private VcsRef myRef; + @Nullable private VcsRef myReference; public boolean mySelected; - public SingleRefComponent(RefPainter refPainter) { - myRefPainter = refPainter; + public SingleReferenceComponent(@NotNull ReferencePainter referencePainter) { + myReferencePainter = referencePainter; } @Override @@ -272,23 +282,20 @@ public class BranchesPanel extends JPanel { g.setColor(mySelected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground()); g.fillRect(0, 0, getWidth(), getHeight()); - if (myRef != null) { - myRefPainter.draw((Graphics2D)g, Collections.singletonList(myRef), 0, calcWidth()); + if (myReference != null) { + myReferencePainter.paintReference(myReference, g, PADDING_X, PADDING_Y); } } @Override public Dimension getPreferredSize() { - return new Dimension(calcWidth(), RefPainter.REF_HEIGHT); + if (myReference == null) return super.getPreferredSize(); + Dimension size = myReferencePainter.getSize(myReference, this); + return new Dimension(size.width + 2 * PADDING_X, size.height + 2 * PADDING_Y); } - private int calcWidth() { - FontMetrics metrics = getFontMetrics(getFont()); - return metrics.stringWidth(myRef.getName()); - } - - public void setRef(@NotNull VcsRef ref) { - myRef = ref; + public void setReference(@NotNull VcsRef reference) { + myReference = reference; } public void setSelected(boolean selected) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 4da2b17eddbe..fa3ac58030fd 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -43,7 +43,7 @@ import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.ui.VcsLogColorManager; -import com.intellij.vcs.log.ui.render.RefPainter; +import com.intellij.vcs.log.ui.render.LabelPainters.ReferencePainter; import com.intellij.vcs.log.ui.tables.GraphTableModel; import net.miginfocom.swing.MigLayout; import org.jetbrains.annotations.NotNull; @@ -80,7 +80,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @NotNull private final VcsLogDataHolder myLogDataHolder; @NotNull private final VcsLogGraphTable myGraphTable; - @NotNull private final RefsPanel myRefsPanel; + @NotNull private final ReferencesPanel myReferencesPanel; @NotNull private final DataPanel myCommitDetailsPanel; @NotNull private final MessagePanel myMessagePanel; @NotNull private final JScrollPane myScrollPane; @@ -101,7 +101,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myColorManager = colorManager; myDataPack = initialDataPack; - myRefsPanel = new RefsPanel(myColorManager); + myReferencesPanel = new ReferencesPanel(myColorManager); myCommitDetailsPanel = new DataPanel(logDataHolder.getProject(), logDataHolder.isMultiRoot(), logDataHolder); myScrollPane = new JBScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); @@ -117,7 +117,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myScrollPane.setOpaque(false); myScrollPane.getViewport().setOpaque(false); myScrollPane.setViewportView(myMainContentPanel); - myMainContentPanel.add(myRefsPanel, ""); + myMainContentPanel.add(myReferencesPanel, ""); myMainContentPanel.add(myCommitDetailsPanel, ""); myLoadingPanel = new JBLoadingPanel(new BorderLayout(), logDataHolder, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS) { @@ -175,13 +175,13 @@ class DetailsPanel extends JPanel implements ListSelectionListener { if (commitData instanceof LoadingDetails) { myLoadingPanel.startLoading(); myCommitDetailsPanel.setData(null); - myRefsPanel.setRefs(Collections.emptyList()); + myReferencesPanel.setReferences(Collections.emptyList()); updateDetailsBorder(null); } else { myLoadingPanel.stopLoading(); myCommitDetailsPanel.setData(commitData); - myRefsPanel.setRefs(sortRefs(commitData.getId(), commitData.getRoot())); + myReferencesPanel.setReferences(sortRefs(commitData.getId(), commitData.getRoot())); updateDetailsBorder(commitData); newCommitDetails = commitData; } @@ -204,7 +204,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myMainContentPanel.setBorder(BorderFactory.createEmptyBorder()); } else { - JBColor color = VcsLogGraphTable.getRootBackgroundColor(data.getRoot(), myColorManager); + Color color = VcsLogGraphTable.getRootBackgroundColor(data.getRoot(), myColorManager); myMainContentPanel.setBorder(new CompoundBorder(new MatteBorder(0, VcsLogGraphTable.ROOT_INDICATOR_COLORED_WIDTH, 0, 0, color), new MatteBorder(0, VcsLogGraphTable.ROOT_INDICATOR_WHITE_WIDTH, 0, 0, new JBColor(new NotNullProducer() { @@ -455,25 +455,24 @@ class DetailsPanel extends JPanel implements ListSelectionListener { } } - private static class RefsPanel extends JPanel { + private static class ReferencesPanel extends JPanel { + @NotNull private final ReferencePainter myReferencePainter; + @NotNull private List myReferences; - @NotNull private final RefPainter myRefPainter; - @NotNull private List myRefs; - - RefsPanel(@NotNull VcsLogColorManager colorManager) { - super(new FlowLayout(FlowLayout.LEADING, 0, 2)); - myRefPainter = new RefPainter(colorManager, false); - myRefs = Collections.emptyList(); + ReferencesPanel(@NotNull VcsLogColorManager colorManager) { + super(new FlowLayout(FlowLayout.LEADING, 5, 2)); + myReferencePainter = new ReferencePainter(colorManager, false); + myReferences = Collections.emptyList(); setOpaque(false); } - void setRefs(@NotNull List refs) { + void setReferences(@NotNull List references) { removeAll(); - myRefs = refs; - for (VcsRef ref : refs) { - add(new SingleRefPanel(myRefPainter, ref)); + myReferences = references; + for (VcsRef reference : references) { + add(new SingleReferencePanel(myReferencePainter, reference)); } - setVisible(!myRefs.isEmpty()); + setVisible(!myReferences.isEmpty()); revalidate(); repaint(); } @@ -484,19 +483,19 @@ class DetailsPanel extends JPanel implements ListSelectionListener { } } - private static class SingleRefPanel extends JPanel { - @NotNull private final RefPainter myRefPainter; - @NotNull private VcsRef myRef; + private static class SingleReferencePanel extends JPanel { + @NotNull private final ReferencePainter myRefPainter; + @NotNull private VcsRef myReference; - SingleRefPanel(@NotNull RefPainter refPainter, @NotNull VcsRef ref) { - myRefPainter = refPainter; - myRef = ref; + SingleReferencePanel(@NotNull ReferencePainter referencePainter, @NotNull VcsRef reference) { + myRefPainter = referencePainter; + myReference = reference; setOpaque(false); } @Override protected void paintComponent(Graphics g) { - myRefPainter.draw((Graphics2D)g, Collections.singleton(myRef), 0, getWidth()); + myRefPainter.paintReference(myReference, g, 0, 0); } @Override @@ -506,8 +505,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @Override public Dimension getPreferredSize() { - int width = myRefPainter.getLabelWidth(myRef.getName(), getFontMetrics(RefPainter.DEFAULT_FONT)); - return new Dimension(width, RefPainter.REF_HEIGHT + UIUtil.DEFAULT_VGAP); + return myRefPainter.getSize(myReference, this); } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index 66e2820b01b9..a2499832afa4 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -31,7 +31,6 @@ import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; import com.intellij.ui.table.JBTable; import com.intellij.util.Function; -import com.intellij.util.NotNullProducer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.JBUI; @@ -48,10 +47,10 @@ import com.intellij.vcs.log.printer.idea.GraphCellPainter; import com.intellij.vcs.log.printer.idea.PositionUtil; import com.intellij.vcs.log.printer.idea.SimpleGraphCellPainter; import com.intellij.vcs.log.ui.VcsLogColorManager; +import com.intellij.vcs.log.ui.VcsLogColorManagerImpl; import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.render.GraphCommitCell; import com.intellij.vcs.log.ui.render.GraphCommitCellRender; -import com.intellij.vcs.log.ui.render.RefPainter; import com.intellij.vcs.log.ui.tables.GraphTableModel; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; @@ -118,7 +117,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C setDefaultRenderer(GraphCommitCell.class, new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, this)); setDefaultRenderer(String.class, new StringCellRenderer()); - setRowHeight(RefPainter.REF_HEIGHT); + setRowHeight(22); setShowHorizontalLines(false); setIntercellSpacing(JBUI.emptySize()); @@ -410,14 +409,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } public static JBColor getRootBackgroundColor(@NotNull VirtualFile root, @NotNull VcsLogColorManager colorManager) { - final Color rootColor = colorManager.getRootColor(root); - return new JBColor(new NotNullProducer() { - @NotNull - @Override - public Color produce() { - return ColorUtil.mix(rootColor, UIUtil.getTableBackground(), 0.75); - } - }); + return VcsLogColorManagerImpl.getBackgroundVersion(colorManager.getRootColor(root)); } public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange, @Nullable Selection previousSelection) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index 59ed3b25720d..6424d17e0f97 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -32,7 +32,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { @NotNull private final VcsLogDataHolder myDataHolder; @NotNull private final GraphCellPainter myPainter; @NotNull private final VcsLogGraphTable myGraphTable; - @NotNull private final RefPainter myRefPainter; + @NotNull private final LabelPainters.LabelPainter myLabelPainter; @NotNull private final IssueLinkRenderer myIssueLinkRenderer; @Nullable private PaintInfo myGraphImage; @@ -45,12 +45,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { myDataHolder = dataHolder; myPainter = painter; myGraphTable = table; - myRefPainter = new RefPainter(colorManager, false) { - @Override - protected int getRowHeight() { - return myGraphTable.getRowHeight(); - } - }; + myLabelPainter = LabelPainters.createPainter(false); myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); } @@ -59,7 +54,14 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { super.paintComponent(g); if (myRefs != null) { - myRefPainter.drawLabels((Graphics2D)g, collectLabelsForRefs(myRefs), myGraphImage != null ? myGraphImage.getWidth() : 0); + int paddingX = (myGraphImage != null ? myGraphImage.getWidth() : 0) + PrintParameters.LABEL_PADDING; + Map labelsForReferences = collectLabelsForRefs(myRefs); + for (Map.Entry entry : labelsForReferences.entrySet()) { + Dimension size = myLabelPainter.calculateSize(entry.getKey(), g.getFontMetrics()); + int paddingY = (myGraphTable.getRowHeight() - size.height) / 2; + myLabelPainter.paintLabel((Graphics2D)g, entry.getKey(), paddingX, paddingY, entry.getValue()); + paddingX += size.width + PrintParameters.LABEL_PADDING; + } } if (myGraphImage != null) { @@ -90,7 +92,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { else { graphPadding = 0; } - int textPadding = graphPadding + calcRefsPadding(myRefs); + int textPadding = graphPadding + calculateReferencePadding(myRefs); setBorder(null); append(""); @@ -132,8 +134,15 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { return getLabelsForRefs(branches, tags); } - private int calcRefsPadding(@NotNull Collection refs) { - return myRefPainter.getLabelsWidth(collectLabelsForRefs(refs).keySet(), this.getFontMetrics(RefPainter.DEFAULT_FONT)); + private int calculateReferencePadding(@NotNull Collection references) { + if (references.isEmpty()) return 0; + + int paddingX = 2 * PrintParameters.LABEL_PADDING; + for (String label : collectLabelsForRefs(references).keySet()) { + Dimension size = myLabelPainter.calculateSize(label, this.getFontMetrics(LabelPainters.getFont())); + paddingX += size.width + PrintParameters.LABEL_PADDING; + } + return paddingX; } @NotNull diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java new file mode 100644 index 000000000000..fa61ebfe060e --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java @@ -0,0 +1,216 @@ +/* + * Copyright 2000-2015 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.vcs.log.ui.render; + +import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.JBColor; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.VcsRef; +import com.intellij.vcs.log.ui.VcsLogColorManager; +import com.intellij.vcs.log.ui.VcsLogColorManagerImpl; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.geom.RoundRectangle2D; + +public class LabelPainters { + + public static LabelPainter createPainter(boolean paintFlag) { + boolean square = Registry.is("vcs.log.square.labels"); + if (paintFlag) { + return square ? new UnderlinedLabelPainter() : new FlagLabelPainter(); + } + else { + return new LabelPainter(square); + } + } + + public static Font getFont() { + return UIUtil.getLabelFont(); + } + + public static class ReferencePainter { + @NotNull private final VcsLogColorManager myColorManager; + @NotNull private final LabelPainter myLabelPainter; + + public ReferencePainter(@NotNull VcsLogColorManager colorManager, boolean paintRoot) { + myColorManager = colorManager; + myLabelPainter = createPainter(paintRoot && colorManager.isMultipleRoots()); + } + + public void paintReference(@NotNull VcsRef reference, @NotNull Graphics g, int paddingX, int paddingY) { + myLabelPainter.paintLabel((Graphics2D)g, reference.getName(), paddingX, paddingY, reference.getType().getBackgroundColor(), + VcsLogColorManagerImpl.getIndicatorVersion(myColorManager.getRootColor(reference.getRoot()))); + } + + public Rectangle paintLabel(@NotNull String text, + @NotNull Graphics g, + int paddingX, + int paddingY, + @NotNull Color color, + @NotNull Color flagColor) { + return myLabelPainter.paintLabel((Graphics2D)g, text, paddingX, paddingY, color, flagColor); + } + + public Dimension getSize(@NotNull VcsRef reference, @NotNull JComponent component) { + return myLabelPainter.calculateSize(reference.getName(), component.getFontMetrics(getFont())); + } + + public int getHeight(@NotNull JComponent component) { + return myLabelPainter.calculateSize("", component.getFontMetrics(getFont())).height; + } + } + + public static class LabelPainter { + protected static final int TEXT_PADDING_X = 5; + protected static final int TOP_TEXT_PADDING = 2; + protected static final int BOTTOM_TEXT_PADDING = 1; + + private static final int LABEL_ARC = 5; + + private final boolean mySquare; + + public LabelPainter(boolean square) { + mySquare = square; + } + + protected Rectangle paintLabel(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + int textPadding, + @NotNull Color color) { + g2.setFont(getFont()); + g2.setStroke(new BasicStroke(1.5f)); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + FontMetrics fontMetrics = g2.getFontMetrics(); + int width = fontMetrics.stringWidth(text) + 2 * TEXT_PADDING_X + textPadding; + int height = fontMetrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING; + + g2.setColor(color); + if (mySquare) { + g2.fillRect(paddingX, paddingY, width, height); + } + else { + g2.fill(new RoundRectangle2D.Double(paddingX, paddingY, width, height, LABEL_ARC, LABEL_ARC)); + } + + g2.setColor(JBColor.BLACK); + int x = paddingX + textPadding + TEXT_PADDING_X; + int y = paddingY + fontMetrics.getHeight() / 2 + TOP_TEXT_PADDING + (fontMetrics.getAscent() - fontMetrics.getDescent()) / 2; + g2.drawString(text, x, y); + + return new Rectangle(x, y, width, height); + } + + public Rectangle paintLabel(@NotNull Graphics2D g2, @NotNull String text, int paddingX, int paddingY, @NotNull Color color) { + return paintLabel(g2, text, paddingX, paddingY, 0, color); + } + + public Rectangle paintLabel(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + @NotNull Color labelColor, + @NotNull Color flagColor) { + return paintLabel(g2, text, paddingX, paddingY, 0, labelColor); + } + + public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { + int width = metrics.stringWidth(text) + 2 * TEXT_PADDING_X; + int height = metrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING; + return new Dimension(width, height); + } + + } + + public static class FlagLabelPainter extends LabelPainter { + private static final int FLAG_WIDTH = 8; + private static final int FLAG_PADDING = 6; + private static final int FLAG_TOP_INDENT = 2; + + public FlagLabelPainter() { + super(false); + } + + @Override + public Rectangle paintLabel(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + @NotNull Color labelColor, + @NotNull Color flagColor) { + + Rectangle rectangle = + super.paintLabel(g2, text, paddingX, paddingY + FLAG_TOP_INDENT, FLAG_WIDTH + 2 * FLAG_PADDING - TEXT_PADDING_X, labelColor); + + g2.setColor(flagColor); + int x0 = paddingX + FLAG_PADDING; + int xMid = x0 + FLAG_WIDTH / 2; + int xRight = x0 + FLAG_WIDTH; + + int y0 = paddingY; + int yMid = y0 + 2 * rectangle.height / 3 - 2; + int yBottom = y0 + rectangle.height - 4; + + // something like a knight flag + Polygon polygon = new Polygon(new int[]{x0, xRight, xRight, xMid, x0}, new int[]{y0, y0, yMid, yBottom, yMid}, 5); + g2.fillPolygon(polygon); + + return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + FLAG_TOP_INDENT); + } + + @Override + public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { + Dimension size = super.calculateSize(text, metrics); + return new Dimension(size.width + FLAG_WIDTH + 2 * FLAG_PADDING, size.height + FLAG_TOP_INDENT); + } + } + + public static class UnderlinedLabelPainter extends LabelPainter { + + private static final int LINE_GAP = 1; + private static final int LINE_HEIGHT = 4; + + public UnderlinedLabelPainter() { + super(true); + } + + @Override + public Rectangle paintLabel(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + @NotNull Color labelColor, + @NotNull Color flagColor) { + + Rectangle rectangle = super.paintLabel(g2, text, paddingX, paddingY, 0, labelColor); + + g2.setColor(flagColor); + g2.fillRect(paddingX, paddingY + rectangle.height + LINE_GAP, rectangle.width, LINE_HEIGHT); + + return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + LINE_GAP + LINE_HEIGHT); + } + + @Override + public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { + Dimension size = super.calculateSize(text, metrics); + return new Dimension(size.width, size.height + LINE_GAP + LINE_HEIGHT); + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/RefPainter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/RefPainter.java deleted file mode 100644 index ffec0d4b87a1..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/RefPainter.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.intellij.vcs.log.ui.render; - -import com.intellij.ui.JBColor; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.ui.VcsLogColorManager; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.awt.font.FontRenderContext; -import java.awt.geom.RoundRectangle2D; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * @author erokhins - */ -public class RefPainter { - private static final int RECTANGLE_X_PADDING = 4; - private static final int RECTANGLE_Y_PADDING = 3; - private static final int REF_PADDING = 13; - private static final int LABEL_PADDING = 3; - - private static final int FLAG_WIDTH = 8; - private static final int FLAG_PADDING = 8; - private static final int FLAG_TOP_INDENT = 2; - - private static final int ROUND_RADIUS = 5; - - public static final Font DEFAULT_FONT = new Font("Arial", Font.PLAIN, 12); // wtf, shouldn't we use ui font? - private static final Color DEFAULT_FONT_COLOR = JBColor.BLACK; - public static final int REF_HEIGHT = 22; - - @NotNull private final VcsLogColorManager myColorManager; - private final boolean myDrawMultiRepoIndicator; - - public RefPainter(@NotNull VcsLogColorManager manager, boolean drawMultiRepoIndicator) { - myColorManager = manager; - myDrawMultiRepoIndicator = drawMultiRepoIndicator; - } - - protected int getRowHeight() { - return REF_HEIGHT; - } - - public int getLabelWidth(@NotNull String str, FontMetrics metrics) { - return getHorizontalDimensions(str, 0, metrics).width + LABEL_PADDING; - } - - public int getLabelsWidth(@NotNull Collection refs, FontMetrics fontMetrics) { - if (refs.isEmpty()) return 0; - - int p = 2 * LABEL_PADDING; // additional padding after all references looks better - for (String ref : refs) { - HorizontalDimensions horizontalDimensions = getHorizontalDimensions(ref, p, fontMetrics); - p += horizontalDimensions.width + LABEL_PADDING; - } - - return p; - } - - public Map draw(@NotNull Graphics2D g2, @NotNull Collection refs, int startPadding, int maxWidth) { - float currentPadding = startPadding; - setupGraphics(g2); - FontRenderContext renderContext = g2.getFontRenderContext(); - Map positions = new HashMap(); - for (VcsRef ref : refs) { - int x = - drawLabel(g2, ref.getName(), (int)currentPadding, ref.getType().getBackgroundColor(), myColorManager.getRootColor(ref.getRoot())).x; - positions.put(x, ref); - currentPadding += paddingStr(ref.getName(), renderContext); - if (maxWidth > 0 && x >= maxWidth) { - break; - } - } - return positions; - } - - public void drawLabels(@NotNull Graphics2D g2, @NotNull Map labels, int startPadding) { - int padding = startPadding; - for (Map.Entry entry : labels.entrySet()) { - Rectangle rectangle = drawLabel(g2, entry.getKey(), padding, entry.getValue(), null); - padding += rectangle.width + LABEL_PADDING; - } - } - - public Rectangle drawLabel(@NotNull Graphics2D g2, - @NotNull String label, - int paddingX, - @NotNull Color bgColor, - @Nullable Color rootIndicatorColor) { - setupGraphics(g2); - FontMetrics metrics = g2.getFontMetrics(); - HorizontalDimensions horizontalDimensions = getHorizontalDimensions(label, paddingX, metrics); - int x = horizontalDimensions.x; - int width = horizontalDimensions.width; - int y = RECTANGLE_Y_PADDING + (getRowHeight() - REF_HEIGHT) / 2; - int height = REF_HEIGHT - 2 * RECTANGLE_Y_PADDING; - RoundRectangle2D rectangle2D = new RoundRectangle2D.Double(x, y, width, height, ROUND_RADIUS, ROUND_RADIUS); - - g2.setColor(bgColor); - g2.fill(rectangle2D); - - g2.setColor(myColorManager.getReferenceBorderColor()); - g2.draw(rectangle2D); - - g2.setColor(JBColor.BLACK); - drawText(g2, label, paddingX + flagWidth(), (getRowHeight() - REF_HEIGHT) / 2); - - if (rootIndicatorColor != null && myColorManager.isMultipleRoots() && myDrawMultiRepoIndicator) { - drawRootIndicator(g2, paddingX, y, height, rootIndicatorColor); - } - - return new Rectangle(x, y, width, height); - } - - private void drawRootIndicator(@NotNull Graphics2D g2, int x, int y, int height, @NotNull Color rootIndicatorColor) { - g2.setColor(rootIndicatorColor); - int x0 = x + FLAG_PADDING; - int xMid = x0 + FLAG_WIDTH / 2; - int xRight = x0 + FLAG_WIDTH; - - int y0 = y - FLAG_TOP_INDENT; - int yMid = y0 + 2 * height / 3 - 2; - int yBottom = y0 + height - 4; - - // something like a knight flag - Polygon polygon = new Polygon(new int[]{x0, xRight, xRight, xMid, x0}, new int[]{y0, y0, yMid, yBottom, yMid}, 5); - g2.fillPolygon(polygon); - g2.setColor(myColorManager.getReferenceBorderColor()); - g2.drawPolygon(polygon); - } - - private HorizontalDimensions getHorizontalDimensions(String label, int paddingX, FontMetrics metrics) { - int x = paddingX + REF_PADDING / 2 - RECTANGLE_X_PADDING; - int width = metrics.stringWidth(label) + 2 * RECTANGLE_X_PADDING + flagWidth(); - return new HorizontalDimensions(x, width); - } - - private double paddingStr(@NotNull String str, @NotNull FontRenderContext renderContext) { - return getStringWidth(str, renderContext) + REF_PADDING + flagWidth(); - } - - private int flagWidth() { - return myColorManager.isMultipleRoots() && myDrawMultiRepoIndicator ? FLAG_WIDTH + FLAG_PADDING : 0; - } - - private static double getStringWidth(@NotNull String str, @NotNull FontRenderContext renderContext) { - return DEFAULT_FONT.getStringBounds(str, renderContext).getWidth(); - } - - private static void drawText(@NotNull Graphics2D g2, @NotNull String str, int paddingX, int paddingY) { - FontMetrics metrics = g2.getFontMetrics(); - g2.setColor(DEFAULT_FONT_COLOR); - int x = paddingX + REF_PADDING / 2; - int y = paddingY + REF_HEIGHT / 2 + (metrics.getAscent() - metrics.getDescent()) / 2; - g2.drawString(str, x, y); - } - - private static void setupGraphics(Graphics2D g2) { - g2.setFont(DEFAULT_FONT); - g2.setStroke(new BasicStroke(1.5f)); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - } - - private static class HorizontalDimensions { - private final int x; - private final int width; - - private HorizontalDimensions(int x, int width) { - this.x = x; - this.width = width; - } - } - -} diff --git a/plugins/git4idea/src/git4idea/log/GitRefManager.java b/plugins/git4idea/src/git4idea/log/GitRefManager.java index 6d4894ad3eea..2aab1c8b2666 100644 --- a/plugins/git4idea/src/git4idea/log/GitRefManager.java +++ b/plugins/git4idea/src/git4idea/log/GitRefManager.java @@ -4,15 +4,11 @@ import com.intellij.dvcs.repo.RepositoryManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.JBColor; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; -import com.intellij.vcs.log.RefGroup; -import com.intellij.vcs.log.VcsLogRefManager; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.VcsRefType; +import com.intellij.vcs.log.*; import com.intellij.vcs.log.impl.SingletonRefGroup; import com.intellij.vcs.log.impl.VcsLogUtil; import git4idea.GitBranch; @@ -31,17 +27,11 @@ import java.util.List; * @author Kirill Likhodedov */ public class GitRefManager implements VcsLogRefManager { - - private static final Color HEAD_COLOR = new JBColor(new Color(0xf1ef9e), new Color(113, 111, 64)); - private static final Color LOCAL_BRANCH_COLOR = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F)); - private static final Color REMOTE_BRANCH_COLOR = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker()); - private static final Color TAG_COLOR = JBColor.WHITE; - - public static final VcsRefType HEAD = new SimpleRefType(true, HEAD_COLOR, "HEAD"); - public static final VcsRefType LOCAL_BRANCH = new SimpleRefType(true, LOCAL_BRANCH_COLOR, "LOCAL_BRANCH"); - public static final VcsRefType REMOTE_BRANCH = new SimpleRefType(true, REMOTE_BRANCH_COLOR, "REMOTE_BRANCH"); - public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR, "TAG"); - public static final VcsRefType OTHER = new SimpleRefType(false, TAG_COLOR, "OTHER"); + public static final VcsRefType HEAD = new SimpleRefType(true, VcsLogStandardColors.Refs.TIP, "HEAD"); + public static final VcsRefType LOCAL_BRANCH = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH, "LOCAL_BRANCH"); + public static final VcsRefType REMOTE_BRANCH = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH_REF, "REMOTE_BRANCH"); + public static final VcsRefType TAG = new SimpleRefType(false, VcsLogStandardColors.Refs.TAG, "TAG"); + public static final VcsRefType OTHER = new SimpleRefType(false, VcsLogStandardColors.Refs.TAG, "OTHER"); private static final String MASTER = "master"; private static final String ORIGIN_MASTER = "origin/master"; @@ -262,7 +252,7 @@ public class GitRefManager implements VcsLogRefManager { @NotNull @Override public Color getBgColor() { - return HEAD_COLOR; + return VcsLogStandardColors.Refs.TIP; } } @@ -295,7 +285,7 @@ public class GitRefManager implements VcsLogRefManager { @NotNull @Override public Color getBgColor() { - return REMOTE_BRANCH_COLOR; + return VcsLogStandardColors.Refs.BRANCH_REF; } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgRefManager.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgRefManager.java index 08fc07260b18..fe3a08730058 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgRefManager.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgRefManager.java @@ -18,10 +18,7 @@ package org.zmlx.hg4idea.log; import com.intellij.ui.JBColor; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import com.intellij.vcs.log.RefGroup; -import com.intellij.vcs.log.VcsLogRefManager; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.VcsRefType; +import com.intellij.vcs.log.*; import com.intellij.vcs.log.impl.SingletonRefGroup; import com.intellij.vcs.log.impl.VcsLogUtil; import org.jetbrains.annotations.NotNull; @@ -33,25 +30,19 @@ import java.util.Comparator; import java.util.List; public class HgRefManager implements VcsLogRefManager { - - private static final Color TIP_COLOR = new JBColor(new Color(0xf1ef9e), new Color(113, 111, 64)); - private static final Color HEAD_COLOR = new JBColor(new Color(0xF10FA9), new Color(0xF10FA9).darker()); - private static final Color BRANCH_COLOR = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F)); private static final Color CLOSED_BRANCH_COLOR = new JBColor(new Color(0xee7f8a), new Color(0xee7f8a).darker()); - private static final Color BOOKMARK_COLOR = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker()); - private static final Color TAG_COLOR = JBColor.WHITE; private static final Color LOCAL_TAG_COLOR = JBColor.CYAN; private static final Color MQ_TAG_COLOR = new JBColor(new Color(0x1764ff), new Color(0x1764ff).darker()); - public static final VcsRefType TIP = new SimpleRefType(true, TIP_COLOR); - public static final VcsRefType HEAD = new SimpleRefType(true, HEAD_COLOR); - public static final VcsRefType BRANCH = new SimpleRefType(true, BRANCH_COLOR); + public static final VcsRefType TIP = new SimpleRefType(true, VcsLogStandardColors.Refs.TIP); + public static final VcsRefType HEAD = new SimpleRefType(true, VcsLogStandardColors.Refs.LEAF); + public static final VcsRefType BRANCH = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH); public static final VcsRefType CLOSED_BRANCH = new SimpleRefType(false, CLOSED_BRANCH_COLOR); - public static final VcsRefType BOOKMARK = new SimpleRefType(true, BOOKMARK_COLOR); - public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR); + public static final VcsRefType BOOKMARK = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH_REF); + public static final VcsRefType TAG = new SimpleRefType(false, VcsLogStandardColors.Refs.TAG); public static final VcsRefType LOCAL_TAG = new SimpleRefType(false, LOCAL_TAG_COLOR); public static final VcsRefType MQ_APPLIED_TAG = new SimpleRefType(false, MQ_TAG_COLOR); - + // first has the highest priority private static final List REF_TYPE_PRIORITIES = Arrays.asList(TIP, HEAD, BRANCH, BOOKMARK, TAG); From a0e26af3c80bb729324b66e9bb0b3eef91040ec4 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Thu, 30 Apr 2015 19:19:28 +0300 Subject: [PATCH 017/172] [vcs-log] calculate row height so that labels could nicely fit --- .../intellij/vcs/log/ui/frame/VcsLogGraphTable.java | 10 ++++++++-- .../vcs/log/ui/render/GraphCommitCellRender.java | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index a2499832afa4..fd65c6e31e22 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -91,6 +91,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } } }; + private final GraphCommitCellRender myGraphCommitCellRenderer; private boolean myColumnsSizeInitialized = false; @@ -112,12 +113,12 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C super(); myUI = UI; myLogDataHolder = logDataHolder; + myGraphCommitCellRenderer = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, this); setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI)); - setDefaultRenderer(GraphCommitCell.class, new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, this)); + setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRenderer); setDefaultRenderer(String.class, new StringCellRenderer()); - setRowHeight(22); setShowHorizontalLines(false); setIntercellSpacing(JBUI.emptySize()); @@ -750,6 +751,11 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C return myDummyEditor; } + @Override + public int getRowHeight() { + return myGraphCommitCellRenderer.getPreferredHeight(); + } + private class StringCellRenderer extends ColoredTableCellRenderer { @Override protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index 6424d17e0f97..79e6d5c563e1 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -49,6 +49,17 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); } + @NotNull + @Override + public Dimension getPreferredSize() { + Dimension preferredSize = super.getPreferredSize(); + return new Dimension(preferredSize.width, getPreferredHeight()); + } + + public int getPreferredHeight() { + return myLabelPainter.calculateSize("", getFontMetrics(LabelPainters.getFont())).height + 4; + } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); From b8d37cad60c85177ab34c912ab736df726c688c7 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 5 May 2015 19:17:01 +0300 Subject: [PATCH 018/172] [vcs-log] minor: remove unused field --- .../src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java | 2 +- .../com/intellij/vcs/log/ui/render/GraphCommitCellRender.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index fd65c6e31e22..d864d6f5db1f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -113,7 +113,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C super(); myUI = UI; myLogDataHolder = logDataHolder; - myGraphCommitCellRenderer = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, this); + myGraphCommitCellRenderer = new GraphCommitCellRender(logDataHolder, myGraphCellPainter, this); setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI)); setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRenderer); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index 79e6d5c563e1..2d845a5694a8 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -12,7 +12,6 @@ import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.graph.PrintElement; import com.intellij.vcs.log.printer.idea.GraphCellPainter; import com.intellij.vcs.log.printer.idea.PrintParameters; -import com.intellij.vcs.log.ui.VcsLogColorManager; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,8 +37,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { @Nullable private PaintInfo myGraphImage; @Nullable private Collection myRefs; - public GraphCommitCellRender(@NotNull VcsLogColorManager colorManager, - @NotNull VcsLogDataHolder dataHolder, + public GraphCommitCellRender(@NotNull VcsLogDataHolder dataHolder, @NotNull GraphCellPainter painter, @NotNull VcsLogGraphTable table) { myDataHolder = dataHolder; From 195c223e7555a891a511a3d992af553207119473 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Fri, 8 May 2015 21:58:26 +0300 Subject: [PATCH 019/172] [vcs-log] provide correct font for measuring label size --- .../com/intellij/vcs/log/ui/render/GraphCommitCellRender.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index 2d845a5694a8..49bfd96556c3 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -66,7 +66,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { int paddingX = (myGraphImage != null ? myGraphImage.getWidth() : 0) + PrintParameters.LABEL_PADDING; Map labelsForReferences = collectLabelsForRefs(myRefs); for (Map.Entry entry : labelsForReferences.entrySet()) { - Dimension size = myLabelPainter.calculateSize(entry.getKey(), g.getFontMetrics()); + Dimension size = myLabelPainter.calculateSize(entry.getKey(), g.getFontMetrics(LabelPainters.getFont())); int paddingY = (myGraphTable.getRowHeight() - size.height) / 2; myLabelPainter.paintLabel((Graphics2D)g, entry.getKey(), paddingX, paddingY, entry.getValue()); paddingX += size.width + PrintParameters.LABEL_PADDING; From f3bf05a400cf9222d63aade8c9f47c07f943f575 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Sat, 9 May 2015 02:11:22 +0300 Subject: [PATCH 020/172] [vcs-log] use the same baseline finding method from SimpleColoredComponent (used in commit cell renderer for message) for labels --- .../impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java index fa61ebfe060e..8d04e8a6caf0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java @@ -17,6 +17,7 @@ package com.intellij.vcs.log.ui.render; import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.JBColor; +import com.intellij.ui.SimpleColoredComponent; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.VcsRef; import com.intellij.vcs.log.ui.VcsLogColorManager; @@ -112,7 +113,7 @@ public class LabelPainters { g2.setColor(JBColor.BLACK); int x = paddingX + textPadding + TEXT_PADDING_X; - int y = paddingY + fontMetrics.getHeight() / 2 + TOP_TEXT_PADDING + (fontMetrics.getAscent() - fontMetrics.getDescent()) / 2; + int y = paddingY + SimpleColoredComponent.getTextBaseLine(fontMetrics, height); g2.drawString(text, x, y); return new Rectangle(x, y, width, height); From 4f9cf97d51e4400f2393f07c75ee19c4b0f6247b Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Sat, 9 May 2015 18:33:01 +0300 Subject: [PATCH 021/172] [vcs-log] rename getIndicatorVersion -> getIndicatorColor, getBackgroundVersion -> getBackgroundColor --- .../intellij/vcs/log/ui/VcsLogColorManagerImpl.java | 12 ++++++------ .../com/intellij/vcs/log/ui/frame/BranchesPanel.java | 2 +- .../intellij/vcs/log/ui/frame/VcsLogGraphTable.java | 2 +- .../intellij/vcs/log/ui/render/LabelPainters.java | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java index 61064fe51bf6..0ff5df4bc36e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogColorManagerImpl.java @@ -54,25 +54,25 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager { } @NotNull - public static JBColor getBackgroundVersion(@NotNull final Color rootColor) { + public static JBColor getBackgroundColor(@NotNull final Color baseRootColor) { return new JBColor(new NotNullProducer() { @NotNull @Override public Color produce() { - return ColorUtil.mix(rootColor, UIUtil.getTableBackground(), 0.75); + return ColorUtil.mix(baseRootColor, UIUtil.getTableBackground(), 0.75); } }); } @NotNull - public static JBColor getIndicatorVersion(@NotNull final Color rootColor) { - if (Registry.is("vcs.log.square.labels")) return getBackgroundVersion(rootColor); + public static JBColor getIndicatorColor(@NotNull final Color baseRootColor) { + if (Registry.is("vcs.log.square.labels")) return getBackgroundColor(baseRootColor); return new JBColor(new NotNullProducer() { @NotNull @Override public Color produce() { - if (UIUtil.isUnderDarcula()) return rootColor; - return ColorUtil.darker(ColorUtil.softer(rootColor), 2); + if (UIUtil.isUnderDarcula()) return baseRootColor; + return ColorUtil.darker(ColorUtil.softer(baseRootColor), 2); } }); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java index 0c8cd92dac35..6d368cd0b722 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java @@ -117,7 +117,7 @@ public class BranchesPanel extends JPanel { for (RefGroup group : entry.getValue()) { // it is assumed here that all refs in a single group belong to a single root if (myRoots == null || myRoots.contains(root)) { - Color rootIndicatorColor = VcsLogColorManagerImpl.getIndicatorVersion(myUI.getColorManager().getRootColor(root)); + Color rootIndicatorColor = VcsLogColorManagerImpl.getIndicatorColor(myUI.getColorManager().getRootColor(root)); Rectangle rectangle = myReferencePainter .paintLabel(group.getName(), g, paddingX, (getHeight() - myReferencePainter.getHeight(this)) / 2 - VERTICAL_SPACE, group.getBgColor(), rootIndicatorColor); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index d864d6f5db1f..44d8f41bb8d5 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -410,7 +410,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } public static JBColor getRootBackgroundColor(@NotNull VirtualFile root, @NotNull VcsLogColorManager colorManager) { - return VcsLogColorManagerImpl.getBackgroundVersion(colorManager.getRootColor(root)); + return VcsLogColorManagerImpl.getBackgroundColor(colorManager.getRootColor(root)); } public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange, @Nullable Selection previousSelection) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java index 8d04e8a6caf0..973af640b84e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java @@ -55,7 +55,7 @@ public class LabelPainters { public void paintReference(@NotNull VcsRef reference, @NotNull Graphics g, int paddingX, int paddingY) { myLabelPainter.paintLabel((Graphics2D)g, reference.getName(), paddingX, paddingY, reference.getType().getBackgroundColor(), - VcsLogColorManagerImpl.getIndicatorVersion(myColorManager.getRootColor(reference.getRoot()))); + VcsLogColorManagerImpl.getIndicatorColor(myColorManager.getRootColor(reference.getRoot()))); } public Rectangle paintLabel(@NotNull String text, From a01ec2cc4e85f83ab5fdeecaf746a00b5553912f Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Sat, 9 May 2015 19:40:17 +0300 Subject: [PATCH 022/172] [vcs-log] rename ReferencePainter -> VcsRefPainter, LabelPainter -> TextLabelPainter, move them to separate files; rename paintLabel methods to just paint --- .../vcs/log/ui/frame/BranchesPanel.java | 19 +- .../vcs/log/ui/frame/DetailsPanel.java | 12 +- .../log/ui/frame/ReferencePopupComponent.java | 167 ++++++++++++++ .../log/ui/render/GraphCommitCellRender.java | 12 +- .../vcs/log/ui/render/LabelPainters.java | 217 ------------------ .../vcs/log/ui/render/TextLabelPainter.java | 177 ++++++++++++++ .../vcs/log/ui/render/VcsRefPainter.java | 60 +++++ 7 files changed, 426 insertions(+), 238 deletions(-) create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ReferencePopupComponent.java delete mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/TextLabelPainter.java create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/VcsRefPainter.java diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java index 6d368cd0b722..9da107563fad 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java @@ -18,7 +18,7 @@ import com.intellij.vcs.log.impl.SingletonRefGroup; import com.intellij.vcs.log.impl.VcsLogUtil; import com.intellij.vcs.log.ui.VcsLogColorManagerImpl; import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.render.LabelPainters.ReferencePainter; +import com.intellij.vcs.log.ui.render.VcsRefPainter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +44,7 @@ public class BranchesPanel extends JPanel { private final VcsLogUiImpl myUI; private LinkedHashMap> myRefGroups; - private final ReferencePainter myReferencePainter; + private final VcsRefPainter myReferencePainter; @Nullable private Collection myRoots = null; private Map myRefPositions = ContainerUtil.newHashMap(); @@ -53,7 +53,7 @@ public class BranchesPanel extends JPanel { myDataHolder = dataHolder; myUI = UI; myRefGroups = getRefsToDisplayOnPanel(initialRefsModel); - myReferencePainter = new ReferencePainter(myUI.getColorManager(), true); + myReferencePainter = new VcsRefPainter(myUI.getColorManager(), true); setPreferredSize(new Dimension(-1, myReferencePainter.getHeight(this) + UIUtil.DEFAULT_VGAP + VERTICAL_SPACE)); @@ -119,8 +119,9 @@ public class BranchesPanel extends JPanel { if (myRoots == null || myRoots.contains(root)) { Color rootIndicatorColor = VcsLogColorManagerImpl.getIndicatorColor(myUI.getColorManager().getRootColor(root)); Rectangle rectangle = myReferencePainter - .paintLabel(group.getName(), g, paddingX, (getHeight() - myReferencePainter.getHeight(this)) / 2 - VERTICAL_SPACE, group.getBgColor(), - rootIndicatorColor); + .paint(group.getName(), g, paddingX, (getHeight() - myReferencePainter.getHeight(this)) / 2 - VERTICAL_SPACE, + group.getBgColor(), + rootIndicatorColor); paddingX += rectangle.width + SMALL_ROOTS_GAP; myRefPositions.put(rectangle.x, group); } @@ -179,7 +180,7 @@ public class BranchesPanel extends JPanel { @NotNull private final SingleReferenceComponent myRendererComponent; @NotNull private final ListCellRenderer myCellRenderer; - ReferencePopupComponent(@NotNull RefGroup group, @NotNull VcsLogUiImpl ui, @NotNull ReferencePainter referencePainter) { + ReferencePopupComponent(@NotNull RefGroup group, @NotNull VcsLogUiImpl ui, @NotNull VcsRefPainter referencePainter) { super(new BorderLayout()); myUi = ui; @@ -268,12 +269,12 @@ public class BranchesPanel extends JPanel { private static class SingleReferenceComponent extends JPanel { private static final int PADDING_Y = 2; private static final int PADDING_X = 5; - @NotNull private final ReferencePainter myReferencePainter; + @NotNull private final VcsRefPainter myReferencePainter; @Nullable private VcsRef myReference; public boolean mySelected; - public SingleReferenceComponent(@NotNull ReferencePainter referencePainter) { + public SingleReferenceComponent(@NotNull VcsRefPainter referencePainter) { myReferencePainter = referencePainter; } @@ -283,7 +284,7 @@ public class BranchesPanel extends JPanel { g.fillRect(0, 0, getWidth(), getHeight()); if (myReference != null) { - myReferencePainter.paintReference(myReference, g, PADDING_X, PADDING_Y); + myReferencePainter.paint(myReference, g, PADDING_X, PADDING_Y); } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index fa3ac58030fd..da7d750e4945 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -43,7 +43,7 @@ import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.ui.VcsLogColorManager; -import com.intellij.vcs.log.ui.render.LabelPainters.ReferencePainter; +import com.intellij.vcs.log.ui.render.VcsRefPainter; import com.intellij.vcs.log.ui.tables.GraphTableModel; import net.miginfocom.swing.MigLayout; import org.jetbrains.annotations.NotNull; @@ -456,12 +456,12 @@ class DetailsPanel extends JPanel implements ListSelectionListener { } private static class ReferencesPanel extends JPanel { - @NotNull private final ReferencePainter myReferencePainter; + @NotNull private final VcsRefPainter myReferencePainter; @NotNull private List myReferences; ReferencesPanel(@NotNull VcsLogColorManager colorManager) { super(new FlowLayout(FlowLayout.LEADING, 5, 2)); - myReferencePainter = new ReferencePainter(colorManager, false); + myReferencePainter = new VcsRefPainter(colorManager, false); myReferences = Collections.emptyList(); setOpaque(false); } @@ -484,10 +484,10 @@ class DetailsPanel extends JPanel implements ListSelectionListener { } private static class SingleReferencePanel extends JPanel { - @NotNull private final ReferencePainter myRefPainter; + @NotNull private final VcsRefPainter myRefPainter; @NotNull private VcsRef myReference; - SingleReferencePanel(@NotNull ReferencePainter referencePainter, @NotNull VcsRef reference) { + SingleReferencePanel(@NotNull VcsRefPainter referencePainter, @NotNull VcsRef reference) { myRefPainter = referencePainter; myReference = reference; setOpaque(false); @@ -495,7 +495,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @Override protected void paintComponent(Graphics g) { - myRefPainter.paintReference(myReference, g, 0, 0); + myRefPainter.paint(myReference, g, 0, 0); } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ReferencePopupComponent.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ReferencePopupComponent.java new file mode 100644 index 000000000000..7c0ea6fab21e --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ReferencePopupComponent.java @@ -0,0 +1,167 @@ +/* + * Copyright 2000-2015 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.vcs.log.ui.frame; + +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.ui.ListUtil; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.RefGroup; +import com.intellij.vcs.log.VcsRef; +import com.intellij.vcs.log.ui.VcsLogUiImpl; +import com.intellij.vcs.log.ui.render.VcsRefPainter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +class ReferencePopupComponent extends JPanel { + @NotNull private final JBPopup myPopup; + @NotNull private final JBList myList; + @NotNull private final VcsLogUiImpl myUi; + @NotNull private final SingleReferenceComponent myRendererComponent; + @NotNull private final ListCellRenderer myCellRenderer; + + ReferencePopupComponent(@NotNull RefGroup group, @NotNull VcsLogUiImpl ui, @NotNull VcsRefPainter referencePainter) { + super(new BorderLayout()); + myUi = ui; + + myRendererComponent = new SingleReferenceComponent(referencePainter); + myCellRenderer = new ListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + myRendererComponent.setReference((VcsRef)value); + myRendererComponent.setSelected(isSelected); + return myRendererComponent; + } + }; + + myList = createList(group); + myPopup = createPopup(); + add(new JBScrollPane(myList)); + } + + private JBList createList(RefGroup group) { + JBList list = new JBList(createListModel(group)); + list.setCellRenderer(myCellRenderer); + ListUtil.installAutoSelectOnMouseMove(list); + list.setSelectedIndex(0); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + jumpOnMouseClick(list); + jumpOnEnter(list); + + return list; + } + + private void jumpOnMouseClick(JBList list) { + list.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + jumpToSelectedRef(); + } + }); + } + + private void jumpOnEnter(JBList list) { + list.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + jumpToSelectedRef(); + } + } + }); + } + + private JBPopup createPopup() { + return JBPopupFactory.getInstance(). + createComponentPopupBuilder(this, myList). + setCancelOnClickOutside(true). + setCancelOnWindowDeactivation(true). + setFocusable(true). + setRequestFocus(true). + setResizable(true). + setDimensionServiceKey(myUi.getProject(), "Vcs.Log.Branch.Panel.RefGroup.Popup", false). + createPopup(); + } + + private static DefaultListModel createListModel(RefGroup group) { + DefaultListModel model = new DefaultListModel(); + for (final VcsRef vcsRef : group.getRefs()) { + model.addElement(vcsRef); + } + return model; + } + + @NotNull + JBPopup getPopup() { + return myPopup; + } + + private void jumpToSelectedRef() { + myPopup.cancel(); // close the popup immediately not to stay at the front if jumping to a commits takes long time. + VcsRef selectedRef = (VcsRef)myList.getSelectedValue(); + if (selectedRef != null) { + myUi.jumpToCommit(selectedRef.getCommitHash()); + } + } + + private static class SingleReferenceComponent extends JPanel { + private static final int PADDING_Y = 2; + private static final int PADDING_X = 5; + @NotNull private final VcsRefPainter myReferencePainter; + + @Nullable private VcsRef myReference; + public boolean mySelected; + + public SingleReferenceComponent(@NotNull VcsRefPainter referencePainter) { + myReferencePainter = referencePainter; + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(mySelected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + + if (myReference != null) { + myReferencePainter.paint(myReference, g, PADDING_X, PADDING_Y); + } + } + + @Override + public Dimension getPreferredSize() { + if (myReference == null) return super.getPreferredSize(); + Dimension size = myReferencePainter.getSize(myReference, this); + return new Dimension(size.width + 2 * PADDING_X, size.height + 2 * PADDING_Y); + } + + public void setReference(@NotNull VcsRef reference) { + myReference = reference; + } + + public void setSelected(boolean selected) { + mySelected = selected; + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index 49bfd96556c3..c9fdbe6dba94 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -31,7 +31,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { @NotNull private final VcsLogDataHolder myDataHolder; @NotNull private final GraphCellPainter myPainter; @NotNull private final VcsLogGraphTable myGraphTable; - @NotNull private final LabelPainters.LabelPainter myLabelPainter; + @NotNull private final TextLabelPainter myTextLabelPainter; @NotNull private final IssueLinkRenderer myIssueLinkRenderer; @Nullable private PaintInfo myGraphImage; @@ -43,7 +43,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { myDataHolder = dataHolder; myPainter = painter; myGraphTable = table; - myLabelPainter = LabelPainters.createPainter(false); + myTextLabelPainter = TextLabelPainter.createPainter(false); myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); } @@ -55,7 +55,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { } public int getPreferredHeight() { - return myLabelPainter.calculateSize("", getFontMetrics(LabelPainters.getFont())).height + 4; + return myTextLabelPainter.calculateSize("", getFontMetrics(TextLabelPainter.getFont())).height + 4; } @Override @@ -66,9 +66,9 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { int paddingX = (myGraphImage != null ? myGraphImage.getWidth() : 0) + PrintParameters.LABEL_PADDING; Map labelsForReferences = collectLabelsForRefs(myRefs); for (Map.Entry entry : labelsForReferences.entrySet()) { - Dimension size = myLabelPainter.calculateSize(entry.getKey(), g.getFontMetrics(LabelPainters.getFont())); + Dimension size = myTextLabelPainter.calculateSize(entry.getKey(), g.getFontMetrics(TextLabelPainter.getFont())); int paddingY = (myGraphTable.getRowHeight() - size.height) / 2; - myLabelPainter.paintLabel((Graphics2D)g, entry.getKey(), paddingX, paddingY, entry.getValue()); + myTextLabelPainter.paint((Graphics2D)g, entry.getKey(), paddingX, paddingY, entry.getValue()); paddingX += size.width + PrintParameters.LABEL_PADDING; } } @@ -148,7 +148,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer { int paddingX = 2 * PrintParameters.LABEL_PADDING; for (String label : collectLabelsForRefs(references).keySet()) { - Dimension size = myLabelPainter.calculateSize(label, this.getFontMetrics(LabelPainters.getFont())); + Dimension size = myTextLabelPainter.calculateSize(label, this.getFontMetrics(TextLabelPainter.getFont())); paddingX += size.width + PrintParameters.LABEL_PADDING; } return paddingX; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java deleted file mode 100644 index 973af640b84e..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/LabelPainters.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2000-2015 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.vcs.log.ui.render; - -import com.intellij.openapi.util.registry.Registry; -import com.intellij.ui.JBColor; -import com.intellij.ui.SimpleColoredComponent; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.ui.VcsLogColorManager; -import com.intellij.vcs.log.ui.VcsLogColorManagerImpl; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.awt.geom.RoundRectangle2D; - -public class LabelPainters { - - public static LabelPainter createPainter(boolean paintFlag) { - boolean square = Registry.is("vcs.log.square.labels"); - if (paintFlag) { - return square ? new UnderlinedLabelPainter() : new FlagLabelPainter(); - } - else { - return new LabelPainter(square); - } - } - - public static Font getFont() { - return UIUtil.getLabelFont(); - } - - public static class ReferencePainter { - @NotNull private final VcsLogColorManager myColorManager; - @NotNull private final LabelPainter myLabelPainter; - - public ReferencePainter(@NotNull VcsLogColorManager colorManager, boolean paintRoot) { - myColorManager = colorManager; - myLabelPainter = createPainter(paintRoot && colorManager.isMultipleRoots()); - } - - public void paintReference(@NotNull VcsRef reference, @NotNull Graphics g, int paddingX, int paddingY) { - myLabelPainter.paintLabel((Graphics2D)g, reference.getName(), paddingX, paddingY, reference.getType().getBackgroundColor(), - VcsLogColorManagerImpl.getIndicatorColor(myColorManager.getRootColor(reference.getRoot()))); - } - - public Rectangle paintLabel(@NotNull String text, - @NotNull Graphics g, - int paddingX, - int paddingY, - @NotNull Color color, - @NotNull Color flagColor) { - return myLabelPainter.paintLabel((Graphics2D)g, text, paddingX, paddingY, color, flagColor); - } - - public Dimension getSize(@NotNull VcsRef reference, @NotNull JComponent component) { - return myLabelPainter.calculateSize(reference.getName(), component.getFontMetrics(getFont())); - } - - public int getHeight(@NotNull JComponent component) { - return myLabelPainter.calculateSize("", component.getFontMetrics(getFont())).height; - } - } - - public static class LabelPainter { - protected static final int TEXT_PADDING_X = 5; - protected static final int TOP_TEXT_PADDING = 2; - protected static final int BOTTOM_TEXT_PADDING = 1; - - private static final int LABEL_ARC = 5; - - private final boolean mySquare; - - public LabelPainter(boolean square) { - mySquare = square; - } - - protected Rectangle paintLabel(@NotNull Graphics2D g2, - @NotNull String text, - int paddingX, - int paddingY, - int textPadding, - @NotNull Color color) { - g2.setFont(getFont()); - g2.setStroke(new BasicStroke(1.5f)); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - FontMetrics fontMetrics = g2.getFontMetrics(); - int width = fontMetrics.stringWidth(text) + 2 * TEXT_PADDING_X + textPadding; - int height = fontMetrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING; - - g2.setColor(color); - if (mySquare) { - g2.fillRect(paddingX, paddingY, width, height); - } - else { - g2.fill(new RoundRectangle2D.Double(paddingX, paddingY, width, height, LABEL_ARC, LABEL_ARC)); - } - - g2.setColor(JBColor.BLACK); - int x = paddingX + textPadding + TEXT_PADDING_X; - int y = paddingY + SimpleColoredComponent.getTextBaseLine(fontMetrics, height); - g2.drawString(text, x, y); - - return new Rectangle(x, y, width, height); - } - - public Rectangle paintLabel(@NotNull Graphics2D g2, @NotNull String text, int paddingX, int paddingY, @NotNull Color color) { - return paintLabel(g2, text, paddingX, paddingY, 0, color); - } - - public Rectangle paintLabel(@NotNull Graphics2D g2, - @NotNull String text, - int paddingX, - int paddingY, - @NotNull Color labelColor, - @NotNull Color flagColor) { - return paintLabel(g2, text, paddingX, paddingY, 0, labelColor); - } - - public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { - int width = metrics.stringWidth(text) + 2 * TEXT_PADDING_X; - int height = metrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING; - return new Dimension(width, height); - } - - } - - public static class FlagLabelPainter extends LabelPainter { - private static final int FLAG_WIDTH = 8; - private static final int FLAG_PADDING = 6; - private static final int FLAG_TOP_INDENT = 2; - - public FlagLabelPainter() { - super(false); - } - - @Override - public Rectangle paintLabel(@NotNull Graphics2D g2, - @NotNull String text, - int paddingX, - int paddingY, - @NotNull Color labelColor, - @NotNull Color flagColor) { - - Rectangle rectangle = - super.paintLabel(g2, text, paddingX, paddingY + FLAG_TOP_INDENT, FLAG_WIDTH + 2 * FLAG_PADDING - TEXT_PADDING_X, labelColor); - - g2.setColor(flagColor); - int x0 = paddingX + FLAG_PADDING; - int xMid = x0 + FLAG_WIDTH / 2; - int xRight = x0 + FLAG_WIDTH; - - int y0 = paddingY; - int yMid = y0 + 2 * rectangle.height / 3 - 2; - int yBottom = y0 + rectangle.height - 4; - - // something like a knight flag - Polygon polygon = new Polygon(new int[]{x0, xRight, xRight, xMid, x0}, new int[]{y0, y0, yMid, yBottom, yMid}, 5); - g2.fillPolygon(polygon); - - return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + FLAG_TOP_INDENT); - } - - @Override - public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { - Dimension size = super.calculateSize(text, metrics); - return new Dimension(size.width + FLAG_WIDTH + 2 * FLAG_PADDING, size.height + FLAG_TOP_INDENT); - } - } - - public static class UnderlinedLabelPainter extends LabelPainter { - - private static final int LINE_GAP = 1; - private static final int LINE_HEIGHT = 4; - - public UnderlinedLabelPainter() { - super(true); - } - - @Override - public Rectangle paintLabel(@NotNull Graphics2D g2, - @NotNull String text, - int paddingX, - int paddingY, - @NotNull Color labelColor, - @NotNull Color flagColor) { - - Rectangle rectangle = super.paintLabel(g2, text, paddingX, paddingY, 0, labelColor); - - g2.setColor(flagColor); - g2.fillRect(paddingX, paddingY + rectangle.height + LINE_GAP, rectangle.width, LINE_HEIGHT); - - return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + LINE_GAP + LINE_HEIGHT); - } - - @Override - public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { - Dimension size = super.calculateSize(text, metrics); - return new Dimension(size.width, size.height + LINE_GAP + LINE_HEIGHT); - } - } -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/TextLabelPainter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/TextLabelPainter.java new file mode 100644 index 000000000000..de7759e2b443 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/TextLabelPainter.java @@ -0,0 +1,177 @@ +/* + * Copyright 2000-2015 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.vcs.log.ui.render; + +import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.JBColor; +import com.intellij.ui.SimpleColoredComponent; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.awt.geom.RoundRectangle2D; + +public class TextLabelPainter { + protected static final int TEXT_PADDING_X = 5; + protected static final int TOP_TEXT_PADDING = 2; + protected static final int BOTTOM_TEXT_PADDING = 1; + + private static final int LABEL_ARC = 5; + + private final boolean mySquare; + + public TextLabelPainter(boolean square) { + mySquare = square; + } + + public static TextLabelPainter createPainter(boolean paintFlag) { + boolean square = Registry.is("vcs.log.square.labels"); + if (paintFlag) { + return square ? new UnderlinedLabelPainter() : new FlagLabelPainter(); + } + else { + return new TextLabelPainter(square); + } + } + + public static Font getFont() { + return UIUtil.getLabelFont(); + } + + protected Rectangle paint(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + int textPadding, + @NotNull Color color) { + g2.setFont(getFont()); + g2.setStroke(new BasicStroke(1.5f)); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + FontMetrics fontMetrics = g2.getFontMetrics(); + int width = fontMetrics.stringWidth(text) + 2 * TEXT_PADDING_X + textPadding; + int height = fontMetrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING; + + g2.setColor(color); + if (mySquare) { + g2.fillRect(paddingX, paddingY, width, height); + } + else { + g2.fill(new RoundRectangle2D.Double(paddingX, paddingY, width, height, LABEL_ARC, LABEL_ARC)); + } + + g2.setColor(JBColor.BLACK); + int x = paddingX + textPadding + TEXT_PADDING_X; + int y = paddingY + SimpleColoredComponent.getTextBaseLine(fontMetrics, height); + g2.drawString(text, x, y); + + return new Rectangle(x, y, width, height); + } + + public Rectangle paint(@NotNull Graphics2D g2, @NotNull String text, int paddingX, int paddingY, @NotNull Color color) { + return paint(g2, text, paddingX, paddingY, 0, color); + } + + public Rectangle paint(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + @NotNull Color labelColor, + @NotNull Color flagColor) { + return paint(g2, text, paddingX, paddingY, 0, labelColor); + } + + public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { + int width = metrics.stringWidth(text) + 2 * TEXT_PADDING_X; + int height = metrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING; + return new Dimension(width, height); + } + + private static class FlagLabelPainter extends TextLabelPainter { + private static final int FLAG_WIDTH = 8; + private static final int FLAG_PADDING = 6; + private static final int FLAG_TOP_INDENT = 2; + + public FlagLabelPainter() { + super(false); + } + + @Override + public Rectangle paint(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + @NotNull Color labelColor, + @NotNull Color flagColor) { + + Rectangle rectangle = + super.paint(g2, text, paddingX, paddingY + FLAG_TOP_INDENT, FLAG_WIDTH + 2 * FLAG_PADDING - TEXT_PADDING_X, labelColor); + + g2.setColor(flagColor); + int x0 = paddingX + FLAG_PADDING; + int xMid = x0 + FLAG_WIDTH / 2; + int xRight = x0 + FLAG_WIDTH; + + int y0 = paddingY; + int yMid = y0 + 2 * rectangle.height / 3 - 2; + int yBottom = y0 + rectangle.height - 4; + + // something like a knight flag + Polygon polygon = new Polygon(new int[]{x0, xRight, xRight, xMid, x0}, new int[]{y0, y0, yMid, yBottom, yMid}, 5); + g2.fillPolygon(polygon); + + return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + FLAG_TOP_INDENT); + } + + @Override + public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { + Dimension size = super.calculateSize(text, metrics); + return new Dimension(size.width + FLAG_WIDTH + 2 * FLAG_PADDING - TEXT_PADDING_X, size.height + FLAG_TOP_INDENT); + } + } + + private static class UnderlinedLabelPainter extends TextLabelPainter { + + private static final int LINE_GAP = 1; + private static final int LINE_HEIGHT = 4; + + public UnderlinedLabelPainter() { + super(true); + } + + @Override + public Rectangle paint(@NotNull Graphics2D g2, + @NotNull String text, + int paddingX, + int paddingY, + @NotNull Color labelColor, + @NotNull Color flagColor) { + + Rectangle rectangle = super.paint(g2, text, paddingX, paddingY, 0, labelColor); + + g2.setColor(flagColor); + g2.fillRect(paddingX, paddingY + rectangle.height + LINE_GAP, rectangle.width, LINE_HEIGHT); + + return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + LINE_GAP + LINE_HEIGHT); + } + + @Override + public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) { + Dimension size = super.calculateSize(text, metrics); + return new Dimension(size.width, size.height + LINE_GAP + LINE_HEIGHT); + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/VcsRefPainter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/VcsRefPainter.java new file mode 100644 index 000000000000..a2c2becc5812 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/VcsRefPainter.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2015 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.vcs.log.ui.render; + +import com.intellij.vcs.log.VcsRef; +import com.intellij.vcs.log.ui.VcsLogColorManager; +import com.intellij.vcs.log.ui.VcsLogColorManagerImpl; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +public class VcsRefPainter { + @NotNull private final VcsLogColorManager myColorManager; + @NotNull private final TextLabelPainter myTextLabelPainter; + + public VcsRefPainter(@NotNull VcsLogColorManager colorManager, boolean paintRoot) { + myColorManager = colorManager; + myTextLabelPainter = TextLabelPainter.createPainter(paintRoot && colorManager.isMultipleRoots()); + } + + public void paint(@NotNull VcsRef reference, @NotNull Graphics g, int paddingX, int paddingY) { + myTextLabelPainter.paint((Graphics2D)g, reference.getName(), paddingX, paddingY, reference.getType().getBackgroundColor(), + VcsLogColorManagerImpl.getIndicatorColor(myColorManager.getRootColor(reference.getRoot()))); + } + + public Rectangle paint(@NotNull String text, + @NotNull Graphics g, + int paddingX, + int paddingY, + @NotNull Color color, + @NotNull Color flagColor) { + return myTextLabelPainter.paint((Graphics2D)g, text, paddingX, paddingY, color, flagColor); + } + + public Dimension getSize(@NotNull VcsRef reference, @NotNull JComponent component) { + return getSize(reference.getName(), component); + } + + public Dimension getSize(@NotNull String referenceName, @NotNull JComponent component) { + return myTextLabelPainter.calculateSize(referenceName, component.getFontMetrics(TextLabelPainter.getFont())); + } + + public int getHeight(@NotNull JComponent component) { + return myTextLabelPainter.calculateSize("", component.getFontMetrics(TextLabelPainter.getFont())).height; + } +} From 5ca4e12431a89e9733ef17785f116693ef7f9522 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 18 Aug 2015 22:16:38 +0300 Subject: [PATCH 023/172] [vcs-log] keep arrows with edges, not with nodes (cherry picked from commit aa04742d1126bdc8648508f860a96f1443c6660b) --- .../vcs/log/graph/EdgePrintElement.java | 4 +- ...rintElement.java => NodePrintElement.java} | 16 +--- .../graph/impl/facade/VisibleGraphImpl.java | 12 ++- .../print/AbstractPrintElementGenerator.java | 55 ++++++++++-- .../impl/print/PrintElementGeneratorImpl.java | 11 ++- .../print/elements/EdgePrintElementImpl.java | 10 +++ .../elements/SimplePrintElementImpl.java | 20 +---- .../vcs/log/printer/idea/PositionUtil.java | 5 +- .../printer/idea/SimpleGraphCellPainter.java | 50 ++++------- .../com/intellij/vcs/log/graph/StrUtils.kt | 12 +-- .../elementGenerator/longEdges_out.txt | 88 ++++++++----------- .../elementGenerator/specialElements_out.txt | 12 +-- 12 files changed, 142 insertions(+), 153 deletions(-) rename platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/{SimplePrintElement.java => NodePrintElement.java} (76%) diff --git a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/EdgePrintElement.java b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/EdgePrintElement.java index 99267898368c..8c20356fb754 100644 --- a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/EdgePrintElement.java +++ b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/EdgePrintElement.java @@ -17,8 +17,6 @@ package com.intellij.vcs.log.graph; import org.jetbrains.annotations.NotNull; -/** - */ public interface EdgePrintElement extends PrintElement { int getPositionInOtherRow(); @@ -29,6 +27,8 @@ public interface EdgePrintElement extends PrintElement { @NotNull LineStyle getLineStyle(); + boolean hasArrow(); + enum Type { UP, DOWN diff --git a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/SimplePrintElement.java b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/NodePrintElement.java similarity index 76% rename from platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/SimplePrintElement.java rename to platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/NodePrintElement.java index bdcd529bc57b..db1b9e39384a 100644 --- a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/SimplePrintElement.java +++ b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/NodePrintElement.java @@ -15,19 +15,5 @@ */ package com.intellij.vcs.log.graph; -import org.jetbrains.annotations.NotNull; - -/** - */ -public interface SimplePrintElement extends PrintElement { - - @NotNull - Type getType(); - - enum Type { - NODE, - UP_ARROW, - DOWN_ARROW - } - +public interface NodePrintElement extends PrintElement { } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java index c230e0fc0fa6..a1c40e759dfe 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java @@ -35,8 +35,6 @@ import java.awt.*; import java.util.Collection; import java.util.Collections; -import static com.intellij.vcs.log.graph.SimplePrintElement.Type.DOWN_ARROW; -import static com.intellij.vcs.log.graph.SimplePrintElement.Type.UP_ARROW; import static com.intellij.vcs.log.graph.utils.LinearGraphUtils.getCursor; public class VisibleGraphImpl implements VisibleGraph { @@ -128,9 +126,9 @@ public class VisibleGraphImpl implements VisibleGraph { @Nullable private GraphAnswer performArrowAction(@NotNull LinearGraphAction action) { PrintElementWithGraphElement affectedElement = action.getAffectedElement(); - if (!(affectedElement instanceof SimplePrintElement)) return null; - SimplePrintElement.Type printElementType = ((SimplePrintElement)affectedElement).getType(); - if (printElementType != DOWN_ARROW && printElementType != UP_ARROW) return null; + if (!(affectedElement instanceof EdgePrintElement)) return null; + EdgePrintElement edgePrintElement = (EdgePrintElement)affectedElement; + if (!edgePrintElement.hasArrow()) return null; GraphElement graphElement = affectedElement.getGraphElement(); if (!(graphElement instanceof GraphEdge)) return null; @@ -138,11 +136,11 @@ public class VisibleGraphImpl implements VisibleGraph { Integer targetId = null; if (edge.getType() == GraphEdgeType.NOT_LOAD_COMMIT) { - assert printElementType == DOWN_ARROW; + assert edgePrintElement.getType().equals(EdgePrintElement.Type.DOWN); targetId = edge.getTargetId(); } if (edge.getType().isNormalEdge()) { - if (printElementType == DOWN_ARROW) { + if (edgePrintElement.getType().equals(EdgePrintElement.Type.DOWN)) { targetId = convertToNodeId(edge.getDownNodeIndex()); } else { diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/AbstractPrintElementGenerator.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/AbstractPrintElementGenerator.java index 3906f8831766..8bf88dade069 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/AbstractPrintElementGenerator.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/AbstractPrintElementGenerator.java @@ -15,9 +15,9 @@ */ package com.intellij.vcs.log.graph.impl.print; +import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.graph.EdgePrintElement; import com.intellij.vcs.log.graph.PrintElement; -import com.intellij.vcs.log.graph.SimplePrintElement; import com.intellij.vcs.log.graph.api.LinearGraph; import com.intellij.vcs.log.graph.api.elements.GraphEdge; import com.intellij.vcs.log.graph.api.elements.GraphElement; @@ -30,6 +30,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; +import java.util.Map; public abstract class AbstractPrintElementGenerator implements PrintElementGenerator { @@ -45,30 +46,59 @@ public abstract class AbstractPrintElementGenerator implements PrintElementGener public Collection getPrintElements(int rowIndex) { Collection result = new ArrayList(); + Map arrows = ContainerUtil.newHashMap(); + + for (SimpleRowElement rowElement : getSimpleRowElements(rowIndex)) { + if (!rowElement.myType.equals(RowElementType.NODE)) { + arrows.put((GraphEdge)rowElement.myElement, rowElement); + } + } + if (rowIndex < myLinearGraph.nodesCount() - 1) { for (ShortEdge shortEdge : getDownShortEdges(rowIndex)) { - result.add(createEdgePrintElement(rowIndex, shortEdge, EdgePrintElement.Type.DOWN)); + RowElementType rowElementType = RowElementType.NODE; + if ((arrows.get(shortEdge.myEdge) != null) && RowElementType.DOWN_ARROW.equals(arrows.get(shortEdge.myEdge).myType)) { + rowElementType = RowElementType.DOWN_ARROW; + arrows.remove(shortEdge.myEdge); + } + result.add(createEdgePrintElement(rowIndex, shortEdge, EdgePrintElement.Type.DOWN, !rowElementType.equals(RowElementType.NODE))); } } if (rowIndex > 0) { for (ShortEdge shortEdge : getDownShortEdges(rowIndex - 1)) { - result.add(createEdgePrintElement(rowIndex, shortEdge, EdgePrintElement.Type.UP)); + RowElementType rowElementType = RowElementType.NODE; + if ((arrows.get(shortEdge.myEdge) != null) && RowElementType.UP_ARROW.equals(arrows.get(shortEdge.myEdge).myType)) { + rowElementType = RowElementType.UP_ARROW; + arrows.remove(shortEdge.myEdge); + } + result.add(createEdgePrintElement(rowIndex, shortEdge, EdgePrintElement.Type.UP, !rowElementType.equals(RowElementType.NODE))); } } + for (SimpleRowElement arrow : arrows.values()) { + result.add(new EdgePrintElementImpl(rowIndex, arrow.myPosition, arrow.myPosition, + arrow.myType == RowElementType.UP_ARROW ? EdgePrintElement.Type.UP : EdgePrintElement.Type.DOWN, + (GraphEdge)arrow.myElement, true, myPrintElementManager)); + } + for (SimpleRowElement rowElement : getSimpleRowElements(rowIndex)) { - result.add(createSimplePrintElement(rowIndex, rowElement)); + if (rowElement.myType.equals(RowElementType.NODE)) { + result.add(createSimplePrintElement(rowIndex, rowElement)); + } } return result; } private SimplePrintElementImpl createSimplePrintElement(int rowIndex, SimpleRowElement rowElement) { - return new SimplePrintElementImpl(rowIndex, rowElement.myPosition, rowElement.myType, rowElement.myElement, myPrintElementManager); + return new SimplePrintElementImpl(rowIndex, rowElement.myPosition, rowElement.myElement, myPrintElementManager); } - private EdgePrintElementImpl createEdgePrintElement(int rowIndex, @NotNull ShortEdge shortEdge, @NotNull EdgePrintElement.Type type) { + private EdgePrintElementImpl createEdgePrintElement(int rowIndex, + @NotNull ShortEdge shortEdge, + @NotNull EdgePrintElement.Type type, + @NotNull boolean hasArrow) { int positionInCurrentRow, positionInOtherRow; if (type == EdgePrintElement.Type.DOWN) { positionInCurrentRow = shortEdge.myUpPosition; @@ -78,7 +108,8 @@ public abstract class AbstractPrintElementGenerator implements PrintElementGener positionInCurrentRow = shortEdge.myDownPosition; positionInOtherRow = shortEdge.myUpPosition; } - return new EdgePrintElementImpl(rowIndex, positionInCurrentRow, positionInOtherRow, type, shortEdge.myEdge, myPrintElementManager); + return new EdgePrintElementImpl(rowIndex, positionInCurrentRow, positionInOtherRow, type, shortEdge.myEdge, hasArrow, + myPrintElementManager); } @NotNull @@ -116,13 +147,19 @@ public abstract class AbstractPrintElementGenerator implements PrintElementGener protected static class SimpleRowElement { @NotNull public final GraphElement myElement; - @NotNull public final SimplePrintElement.Type myType; + @NotNull public final RowElementType myType; public final int myPosition; - public SimpleRowElement(@NotNull GraphElement element, @NotNull SimplePrintElement.Type type, int position) { + public SimpleRowElement(@NotNull GraphElement element, @NotNull RowElementType type, int position) { myElement = element; myPosition = position; myType = type; } } + + enum RowElementType { + NODE, + UP_ARROW, + DOWN_ARROW + } } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java index c254c220d69d..49b25e3ccf46 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java @@ -20,7 +20,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.util.NullableFunction; import com.intellij.util.SmartList; import com.intellij.util.containers.SLRUMap; -import com.intellij.vcs.log.graph.SimplePrintElement; import com.intellij.vcs.log.graph.api.EdgeFilter; import com.intellij.vcs.log.graph.api.LinearGraph; import com.intellij.vcs.log.graph.api.elements.GraphEdge; @@ -151,7 +150,7 @@ public class PrintElementGeneratorImpl extends AbstractPrintElementGenerator { for (int position = 0; position < sortedVisibleElementsInRow.size(); position++) { GraphElement element = sortedVisibleElementsInRow.get(position); if (element instanceof GraphNode) { - result.add(new SimpleRowElement(element, SimplePrintElement.Type.NODE, position)); + result.add(new SimpleRowElement(element, RowElementType.NODE, position)); } if (element instanceof GraphEdge) { @@ -172,13 +171,13 @@ public class PrintElementGeneratorImpl extends AbstractPrintElementGenerator { case DOTTED_ARROW_DOWN: case NOT_LOAD_COMMIT: if (intEqual(edge.getUpNodeIndex(), visibleRowIndex - 1)) { - result.add(new SimpleRowElement(edge, SimplePrintElement.Type.DOWN_ARROW, position)); + result.add(new SimpleRowElement(edge, RowElementType.DOWN_ARROW, position)); } break; case DOTTED_ARROW_UP: if (intEqual(edge.getDownNodeIndex(), visibleRowIndex + 1)) // todo case 0-row arrow { - result.add(new SimpleRowElement(edge, SimplePrintElement.Type.UP_ARROW, position)); + result.add(new SimpleRowElement(edge, RowElementType.UP_ARROW, position)); } break; default: @@ -196,9 +195,9 @@ public class PrintElementGeneratorImpl extends AbstractPrintElementGenerator { int upOffset, int downOffset, int showingPartSize) { - if (upOffset == showingPartSize) result.add(new SimpleRowElement(edge, SimplePrintElement.Type.DOWN_ARROW, position)); + if (upOffset == showingPartSize) result.add(new SimpleRowElement(edge, RowElementType.DOWN_ARROW, position)); - if (downOffset == showingPartSize) result.add(new SimpleRowElement(edge, SimplePrintElement.Type.UP_ARROW, position)); + if (downOffset == showingPartSize) result.add(new SimpleRowElement(edge, RowElementType.UP_ARROW, position)); } private boolean edgeIsVisibleInRow(@NotNull GraphEdge edge, int visibleRowIndex) { diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/EdgePrintElementImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/EdgePrintElementImpl.java index d8e95beec9cb..84e33a588ee2 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/EdgePrintElementImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/EdgePrintElementImpl.java @@ -41,17 +41,20 @@ public class EdgePrintElementImpl extends PrintElementWithGraphElement implement @NotNull private final Type myType; @NotNull private final LineStyle myLineStyle; private final int myPositionInOtherRow; + private final boolean myHasArrow; public EdgePrintElementImpl(int rowIndex, int positionInCurrentRow, int positionInOtherRow, @NotNull Type type, @NotNull GraphEdge graphEdge, + @NotNull boolean hasArrow, @NotNull PrintElementManager printElementManager) { super(rowIndex, positionInCurrentRow, graphEdge, printElementManager); myType = type; myLineStyle = convertToLineStyle(graphEdge.getType()); myPositionInOtherRow = positionInOtherRow; + myHasArrow = hasArrow; } @Override @@ -71,6 +74,11 @@ public class EdgePrintElementImpl extends PrintElementWithGraphElement implement return myLineStyle; } + @Override + public boolean hasArrow() { + return myHasArrow; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -82,6 +90,7 @@ public class EdgePrintElementImpl extends PrintElementWithGraphElement implement if (myPositionInOtherRow != that.getPositionInOtherRow()) return false; if (myRowIndex != that.getRowIndex()) return false; if (myType != that.getType()) return false; + if (myHasArrow != that.hasArrow()) return false; return true; } @@ -92,6 +101,7 @@ public class EdgePrintElementImpl extends PrintElementWithGraphElement implement result = 31 * result + myPositionInCurrentRow; result = 31 * result + myPositionInOtherRow; result = 37 * result + myType.hashCode(); + result = 31 * result + (myHasArrow ? 1 : 0); return result; } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/SimplePrintElementImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/SimplePrintElementImpl.java index 3dd25d75bc74..ed28cf196f08 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/SimplePrintElementImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/elements/SimplePrintElementImpl.java @@ -16,40 +16,29 @@ package com.intellij.vcs.log.graph.impl.print.elements; -import com.intellij.vcs.log.graph.SimplePrintElement; +import com.intellij.vcs.log.graph.NodePrintElement; import com.intellij.vcs.log.graph.api.elements.GraphElement; import com.intellij.vcs.log.graph.api.printer.PrintElementManager; import org.jetbrains.annotations.NotNull; -public class SimplePrintElementImpl extends PrintElementWithGraphElement implements SimplePrintElement { - - @NotNull private final Type myType; +public class SimplePrintElementImpl extends PrintElementWithGraphElement implements NodePrintElement { public SimplePrintElementImpl(int rowIndex, int positionInCurrentRow, - @NotNull Type type, @NotNull GraphElement graphElement, @NotNull PrintElementManager printElementManager) { super(rowIndex, positionInCurrentRow, graphElement, printElementManager); - myType = type; - } - - @NotNull - @Override - public Type getType() { - return myType; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof SimplePrintElement)) return false; + if (!(o instanceof NodePrintElement)) return false; - SimplePrintElement that = (SimplePrintElement)o; + NodePrintElement that = (NodePrintElement)o; if (myPositionInCurrentRow != that.getPositionInCurrentRow()) return false; if (myRowIndex != that.getRowIndex()) return false; - if (myType != that.getType()) return false; return true; } @@ -58,7 +47,6 @@ public class SimplePrintElementImpl extends PrintElementWithGraphElement impleme public int hashCode() { int result = myRowIndex; result = 31 * result + myPositionInCurrentRow; - result = 37 * result + myType.hashCode(); return result; } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PositionUtil.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PositionUtil.java index ea5d08ccc363..ce5e07c453a6 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PositionUtil.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/PositionUtil.java @@ -15,7 +15,6 @@ */ package com.intellij.vcs.log.printer.idea; -import com.intellij.vcs.log.graph.SimplePrintElement; import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -46,12 +45,10 @@ public class PositionUtil { return distance(x1, y1, x, y) + distance(x2, y2, x, y) < distance(x1, y1, x2, y2) + thick; } - public static boolean overNode(int position, int x, int y, SimplePrintElement.Type type, int rowHeight) { + public static boolean overNode(int position, int x, int y, int rowHeight) { int r = CIRCLE_RADIUS; int x0 = WIDTH_NODE * position + WIDTH_NODE / 2; int y0 = rowHeight / 2; - if (type == SimplePrintElement.Type.DOWN_ARROW) y0 = rowHeight - r; - if (type == SimplePrintElement.Type.UP_ARROW) y0 = r; return distance(x0, y0, x, y) <= r; } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java index a8175906322f..3dd0f5b63cd2 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java @@ -17,8 +17,8 @@ package com.intellij.vcs.log.printer.idea; import com.intellij.ui.JBColor; import com.intellij.vcs.log.graph.EdgePrintElement; +import com.intellij.vcs.log.graph.NodePrintElement; import com.intellij.vcs.log.graph.PrintElement; -import com.intellij.vcs.log.graph.SimplePrintElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -88,7 +88,6 @@ public class SimpleGraphCellPainter implements GraphCellPainter { int r = PrintParameters.CIRCLE_RADIUS; int y0 = getRowHeight() - r - 2; g2.setColor(color); - g2.drawLine(x0, getRowHeight() / 2, x0, y0 + r); g2.drawLine(x0, y0 + r, x0 + r, y0); g2.drawLine(x0, y0 + r, x0 - r, y0); } @@ -98,7 +97,6 @@ public class SimpleGraphCellPainter implements GraphCellPainter { int r = PrintParameters.CIRCLE_RADIUS; int y0 = r + 2; g2.setColor(color); - g2.drawLine(x0, getRowHeight() / 2, x0, y0 - r); g2.drawLine(x0, y0 - r, x0 + r, y0); g2.drawLine(x0, y0 - r, x0 - r, y0); } @@ -167,42 +165,28 @@ public class SimpleGraphCellPainter implements GraphCellPainter { if (edgePrintElement.getType() == EdgePrintElement.Type.DOWN) { paintDownLine(from, to, color); + if (edgePrintElement.hasArrow()) { + paintDownArrow(from, color); + } } else { paintUpLine(from, to, color); + if (edgePrintElement.hasArrow()) { + paintUpArrow(from, color); + } } } }; } - if (printElement instanceof SimplePrintElement) { - final int position = printElement.getPositionInCurrentRow(); - switch (((SimplePrintElement)printElement).getType()) { - case NODE: - if (printElement.isSelected()) { - paintCircle(position, MARK_COLOR, true); - paintCircle(position, getColor(printElement), false); - } - else { - paintCircle(position, getColor(printElement), false); - } - break; - case UP_ARROW: - printer = new LitePrinter() { - @Override - public void print(Color color) { - paintUpArrow(position, color); - } - }; - break; - case DOWN_ARROW: - printer = new LitePrinter() { - @Override - public void print(Color color) { - paintDownArrow(position, color); - } - }; - break; + if (printElement instanceof NodePrintElement) { + int position = printElement.getPositionInCurrentRow(); + if (printElement.isSelected()) { + paintCircle(position, MARK_COLOR, true); + paintCircle(position, getColor(printElement), false); + } + else { + paintCircle(position, getColor(printElement), false); } } @@ -214,8 +198,8 @@ public class SimpleGraphCellPainter implements GraphCellPainter { @Override public PrintElement mouseOver(@NotNull Collection printElements, int x, int y) { for (PrintElement printElement : printElements) { - if (printElement instanceof SimplePrintElement) { - if (PositionUtil.overNode(printElement.getPositionInCurrentRow(), x, y, ((SimplePrintElement)printElement).getType(), getRowHeight())) { + if (printElement instanceof NodePrintElement) { + if (PositionUtil.overNode(printElement.getPositionInCurrentRow(), x, y, getRowHeight())) { return printElement; } } diff --git a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/StrUtils.kt b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/StrUtils.kt index f857b9f174b7..195ebecf2976 100644 --- a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/StrUtils.kt +++ b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/StrUtils.kt @@ -61,15 +61,15 @@ fun PrintElementWithGraphElement.asString(): String { val pos = getPositionInCurrentRow() val sel = if (isSelected()) "Select" else "Unselect" return when (this) { - is SimplePrintElement -> { - val t = getType() - "Simple:${t}|-$row:${pos}|-$color:${sel}($element)" + is NodePrintElement -> { + "Simple:NODE|-$row:${pos}|-$color:${sel}($element)" } is EdgePrintElement -> { val t = getType() val ls = getLineStyle() val posO = getPositionInOtherRow() - "Edge:$t:${ls}|-$row:$pos:${posO}|-$color:$sel($element)" + val arrow = if (hasArrow()) "_ARROW" else "" + "Edge:$t${arrow}:${ls}|-$row:$pos:${posO}|-$color:$sel($element)" } else -> { @@ -85,8 +85,8 @@ fun PrintElementGenerator.asString(size: Int): String { if (row > 0) s.append("\n") val elements = getPrintElements(row).sortBy { val pos = it.getPositionInCurrentRow() - if (it is SimplePrintElement) { - 1024 * pos + it.getType().ordinal() + if (it is NodePrintElement) { + 1024 * pos } else if (it is EdgePrintElement) { 1024 * pos + (it.getType().ordinal() + 1) * 64 + it.getPositionInOtherRow() } else 0 diff --git a/platform/vcs-log/graph/testData/elementGenerator/longEdges_out.txt b/platform/vcs-log/graph/testData/elementGenerator/longEdges_out.txt index 174e2b26843f..50f72a31f891 100644 --- a/platform/vcs-log/graph/testData/elementGenerator/longEdges_out.txt +++ b/platform/vcs-log/graph/testData/elementGenerator/longEdges_out.txt @@ -11,9 +11,8 @@ Simple:NODE|-0:0|-0:Unselect(0_U) Edge:DOWN:SOLID|-0:0:9|-9:Unselect(0:9:n_U) Edge:DOWN:SOLID|-0:0:10|-10:Unselect(0:10:n_U) Edge:DOWN:SOLID|-0:0:11|-11:Unselect(0:11:n_U) -Simple:DOWN_ARROW|-1:0|-12:Unselect(0:12:n_U) - Edge:UP:SOLID|-1:0:0|-12:Unselect(0:12:n_U) - Edge:DOWN:SOLID|-1:0:0|-12:Unselect(0:12:n_U) +Edge:UP:SOLID|-1:0:0|-12:Unselect(0:12:n_U) + Edge:DOWN_ARROW:SOLID|-1:0:0|-12:Unselect(0:12:n_U) Simple:NODE|-1:1|-1:Unselect(1_U) Edge:UP:SOLID|-1:1:0|-1:Unselect(0:1:n_U) Edge:DOWN:SOLID|-1:1:1|-13:Unselect(1:12:n_U) @@ -33,17 +32,14 @@ Simple:DOWN_ARROW|-1:0|-12:Unselect(0:12:n_U) Edge:DOWN:SOLID|-1:8:8|-8:Unselect(0:8:n_U) Edge:UP:SOLID|-1:9:0|-9:Unselect(0:9:n_U) Edge:DOWN:SOLID|-1:9:9|-9:Unselect(0:9:n_U) - Simple:DOWN_ARROW|-1:10|-10:Unselect(0:10:n_U) Edge:UP:SOLID|-1:10:0|-10:Unselect(0:10:n_U) - Edge:DOWN:SOLID|-1:10:10|-10:Unselect(0:10:n_U) - Simple:DOWN_ARROW|-1:11|-11:Unselect(0:11:n_U) + Edge:DOWN_ARROW:SOLID|-1:10:10|-10:Unselect(0:10:n_U) Edge:UP:SOLID|-1:11:0|-11:Unselect(0:11:n_U) - Edge:DOWN:SOLID|-1:11:11|-11:Unselect(0:11:n_U) -Simple:DOWN_ARROW|-2:0|-12:Unselect(0:12:n_U) - Edge:UP:SOLID|-2:0:0|-12:Unselect(0:12:n_U) - Simple:DOWN_ARROW|-2:1|-13:Unselect(1:12:n_U) + Edge:DOWN_ARROW:SOLID|-1:11:11|-11:Unselect(0:11:n_U) +Edge:UP:SOLID|-2:0:0|-12:Unselect(0:12:n_U) + Edge:DOWN_ARROW:SOLID|-2:0:0|-12:Unselect(0:12:n_U) Edge:UP:SOLID|-2:1:1|-13:Unselect(1:12:n_U) - Edge:DOWN:SOLID|-2:1:0|-13:Unselect(1:12:n_U) + Edge:DOWN_ARROW:SOLID|-2:1:0|-13:Unselect(1:12:n_U) Simple:NODE|-2:2|-2:Unselect(2_U) Edge:UP:SOLID|-2:2:2|-2:Unselect(0:2:n_U) Edge:DOWN:SOLID|-2:2:1|-14:Unselect(2:12:n_U) @@ -55,21 +51,20 @@ Simple:DOWN_ARROW|-2:0|-12:Unselect(0:12:n_U) Edge:DOWN:SOLID|-2:5:4|-5:Unselect(0:5:n_U) Edge:UP:SOLID|-2:6:6|-6:Unselect(0:6:n_U) Edge:DOWN:SOLID|-2:6:5|-6:Unselect(0:6:n_U) - Simple:DOWN_ARROW|-2:7|-7:Unselect(0:7:n_U) Edge:UP:SOLID|-2:7:7|-7:Unselect(0:7:n_U) - Simple:DOWN_ARROW|-2:8|-8:Unselect(0:8:n_U) + Edge:DOWN_ARROW:SOLID|-2:7:7|-7:Unselect(0:7:n_U) Edge:UP:SOLID|-2:8:8|-8:Unselect(0:8:n_U) - Simple:DOWN_ARROW|-2:9|-9:Unselect(0:9:n_U) + Edge:DOWN_ARROW:SOLID|-2:8:8|-8:Unselect(0:8:n_U) Edge:UP:SOLID|-2:9:9|-9:Unselect(0:9:n_U) - Simple:DOWN_ARROW|-2:10|-10:Unselect(0:10:n_U) + Edge:DOWN_ARROW:SOLID|-2:9:9|-9:Unselect(0:9:n_U) Edge:UP:SOLID|-2:10:10|-10:Unselect(0:10:n_U) - Simple:DOWN_ARROW|-2:11|-11:Unselect(0:11:n_U) + Edge:DOWN_ARROW:SOLID|-2:10:10|-10:Unselect(0:10:n_U) Edge:UP:SOLID|-2:11:11|-11:Unselect(0:11:n_U) -Simple:DOWN_ARROW|-3:0|-13:Unselect(1:12:n_U) - Edge:UP:SOLID|-3:0:1|-13:Unselect(1:12:n_U) - Simple:DOWN_ARROW|-3:1|-14:Unselect(2:12:n_U) + Edge:DOWN_ARROW:SOLID|-2:11:11|-11:Unselect(0:11:n_U) +Edge:UP:SOLID|-3:0:1|-13:Unselect(1:12:n_U) + Edge:DOWN_ARROW:SOLID|-3:0:0|-13:Unselect(1:12:n_U) Edge:UP:SOLID|-3:1:2|-14:Unselect(2:12:n_U) - Edge:DOWN:SOLID|-3:1:0|-14:Unselect(2:12:n_U) + Edge:DOWN_ARROW:SOLID|-3:1:0|-14:Unselect(2:12:n_U) Simple:NODE|-3:2|-3:Unselect(3_U) Edge:UP:SOLID|-3:2:3|-3:Unselect(0:3:n_U) Edge:DOWN:SOLID|-3:2:1|-15:Unselect(3:12:n_U) @@ -79,8 +74,8 @@ Simple:DOWN_ARROW|-3:0|-13:Unselect(1:12:n_U) Edge:DOWN:SOLID|-3:4:3|-5:Unselect(0:5:n_U) Edge:UP:SOLID|-3:5:6|-6:Unselect(0:6:n_U) Edge:DOWN:SOLID|-3:5:4|-6:Unselect(0:6:n_U) -Simple:DOWN_ARROW|-4:0|-14:Unselect(2:12:n_U) - Edge:UP:SOLID|-4:0:1|-14:Unselect(2:12:n_U) +Edge:UP:SOLID|-4:0:1|-14:Unselect(2:12:n_U) + Edge:DOWN_ARROW:SOLID|-4:0:0|-14:Unselect(2:12:n_U) Edge:UP:SOLID|-4:1:2|-15:Unselect(3:12:n_U) Edge:DOWN:SOLID|-4:1:0|-15:Unselect(3:12:n_U) Simple:NODE|-4:2|-4:Unselect(4_U) @@ -90,8 +85,8 @@ Simple:DOWN_ARROW|-4:0|-14:Unselect(2:12:n_U) Edge:DOWN:SOLID|-4:3:2|-5:Unselect(0:5:n_U) Edge:UP:SOLID|-4:4:5|-6:Unselect(0:6:n_U) Edge:DOWN:SOLID|-4:4:3|-6:Unselect(0:6:n_U) -Simple:DOWN_ARROW|-5:0|-15:Unselect(3:12:n_U) - Edge:UP:SOLID|-5:0:1|-15:Unselect(3:12:n_U) +Edge:UP:SOLID|-5:0:1|-15:Unselect(3:12:n_U) + Edge:DOWN_ARROW:SOLID|-5:0:0|-15:Unselect(3:12:n_U) Edge:UP:SOLID|-5:1:2|-16:Unselect(4:12:n_U) Edge:DOWN:SOLID|-5:1:0|-16:Unselect(4:12:n_U) Simple:NODE|-5:2|-5:Unselect(5_U) @@ -99,10 +94,10 @@ Simple:DOWN_ARROW|-5:0|-15:Unselect(3:12:n_U) Edge:DOWN:SOLID|-5:2:1|-17:Unselect(5:12:n_U) Edge:UP:SOLID|-5:3:4|-6:Unselect(0:6:n_U) Edge:DOWN:SOLID|-5:3:2|-6:Unselect(0:6:n_U) - Simple:UP_ARROW|-5:4|-7:Unselect(0:7:n_U) + Edge:UP_ARROW:SOLID|-5:4:4|-7:Unselect(0:7:n_U) Edge:DOWN:SOLID|-5:4:3|-7:Unselect(0:7:n_U) -Simple:DOWN_ARROW|-6:0|-16:Unselect(4:12:n_U) - Edge:UP:SOLID|-6:0:1|-16:Unselect(4:12:n_U) +Edge:UP:SOLID|-6:0:1|-16:Unselect(4:12:n_U) + Edge:DOWN_ARROW:SOLID|-6:0:0|-16:Unselect(4:12:n_U) Edge:UP:SOLID|-6:1:2|-17:Unselect(5:12:n_U) Edge:DOWN:SOLID|-6:1:0|-17:Unselect(5:12:n_U) Simple:NODE|-6:2|-6:Unselect(6_U) @@ -110,10 +105,10 @@ Simple:DOWN_ARROW|-6:0|-16:Unselect(4:12:n_U) Edge:DOWN:SOLID|-6:2:1|-18:Unselect(6:12:n_U) Edge:UP:SOLID|-6:3:4|-7:Unselect(0:7:n_U) Edge:DOWN:SOLID|-6:3:2|-7:Unselect(0:7:n_U) - Simple:UP_ARROW|-6:4|-8:Unselect(0:8:n_U) + Edge:UP_ARROW:SOLID|-6:4:4|-8:Unselect(0:8:n_U) Edge:DOWN:SOLID|-6:4:3|-8:Unselect(0:8:n_U) -Simple:DOWN_ARROW|-7:0|-17:Unselect(5:12:n_U) - Edge:UP:SOLID|-7:0:1|-17:Unselect(5:12:n_U) +Edge:UP:SOLID|-7:0:1|-17:Unselect(5:12:n_U) + Edge:DOWN_ARROW:SOLID|-7:0:0|-17:Unselect(5:12:n_U) Edge:UP:SOLID|-7:1:2|-18:Unselect(6:12:n_U) Edge:DOWN:SOLID|-7:1:0|-18:Unselect(6:12:n_U) Simple:NODE|-7:2|-7:Unselect(7_U) @@ -121,7 +116,7 @@ Simple:DOWN_ARROW|-7:0|-17:Unselect(5:12:n_U) Edge:DOWN:SOLID|-7:2:1|-19:Unselect(7:12:n_U) Edge:UP:SOLID|-7:3:4|-8:Unselect(0:8:n_U) Edge:DOWN:SOLID|-7:3:2|-8:Unselect(0:8:n_U) - Simple:UP_ARROW|-7:4|-9:Unselect(0:9:n_U) + Edge:UP_ARROW:SOLID|-7:4:4|-9:Unselect(0:9:n_U) Edge:DOWN:SOLID|-7:4:3|-9:Unselect(0:9:n_U) Edge:UP:SOLID|-8:0:1|-18:Unselect(6:12:n_U) Edge:DOWN:SOLID|-8:0:0|-18:Unselect(6:12:n_U) @@ -132,7 +127,7 @@ Edge:UP:SOLID|-8:0:1|-18:Unselect(6:12:n_U) Edge:DOWN:SOLID|-8:2:2|-20:Unselect(8:12:n_U) Edge:UP:SOLID|-8:3:4|-9:Unselect(0:9:n_U) Edge:DOWN:SOLID|-8:3:3|-9:Unselect(0:9:n_U) - Simple:UP_ARROW|-8:4|-10:Unselect(0:10:n_U) + Edge:UP_ARROW:SOLID|-8:4:4|-10:Unselect(0:10:n_U) Edge:DOWN:SOLID|-8:4:4|-10:Unselect(0:10:n_U) Edge:UP:SOLID|-9:0:0|-18:Unselect(6:12:n_U) Edge:DOWN:SOLID|-9:0:6|-18:Unselect(6:12:n_U) @@ -143,22 +138,21 @@ Edge:UP:SOLID|-9:0:0|-18:Unselect(6:12:n_U) Simple:NODE|-9:3|-9:Unselect(9_U) Edge:UP:SOLID|-9:3:3|-9:Unselect(0:9:n_U) Edge:DOWN:SOLID|-9:3:9|-21:Unselect(9:12:n_U) - Simple:UP_ARROW|-9:4|-10:Unselect(0:10:n_U) - Edge:UP:SOLID|-9:4:4|-10:Unselect(0:10:n_U) + Edge:UP_ARROW:SOLID|-9:4:4|-10:Unselect(0:10:n_U) Edge:DOWN:SOLID|-9:4:10|-10:Unselect(0:10:n_U) - Simple:UP_ARROW|-9:5|-11:Unselect(0:11:n_U) + Edge:UP_ARROW:SOLID|-9:5:5|-11:Unselect(0:11:n_U) Edge:DOWN:SOLID|-9:5:11|-11:Unselect(0:11:n_U) -Simple:UP_ARROW|-10:0|-12:Unselect(0:12:n_U) +Edge:UP_ARROW:SOLID|-10:0:0|-12:Unselect(0:12:n_U) Edge:DOWN:SOLID|-10:0:0|-12:Unselect(0:12:n_U) - Simple:UP_ARROW|-10:1|-13:Unselect(1:12:n_U) + Edge:UP_ARROW:SOLID|-10:1:1|-13:Unselect(1:12:n_U) Edge:DOWN:SOLID|-10:1:1|-13:Unselect(1:12:n_U) - Simple:UP_ARROW|-10:2|-14:Unselect(2:12:n_U) + Edge:UP_ARROW:SOLID|-10:2:2|-14:Unselect(2:12:n_U) Edge:DOWN:SOLID|-10:2:2|-14:Unselect(2:12:n_U) - Simple:UP_ARROW|-10:3|-15:Unselect(3:12:n_U) + Edge:UP_ARROW:SOLID|-10:3:3|-15:Unselect(3:12:n_U) Edge:DOWN:SOLID|-10:3:3|-15:Unselect(3:12:n_U) - Simple:UP_ARROW|-10:4|-16:Unselect(4:12:n_U) + Edge:UP_ARROW:SOLID|-10:4:4|-16:Unselect(4:12:n_U) Edge:DOWN:SOLID|-10:4:4|-16:Unselect(4:12:n_U) - Simple:UP_ARROW|-10:5|-17:Unselect(5:12:n_U) + Edge:UP_ARROW:SOLID|-10:5:5|-17:Unselect(5:12:n_U) Edge:DOWN:SOLID|-10:5:5|-17:Unselect(5:12:n_U) Edge:UP:SOLID|-10:6:0|-18:Unselect(6:12:n_U) Edge:DOWN:SOLID|-10:6:6|-18:Unselect(6:12:n_U) @@ -171,17 +165,13 @@ Simple:UP_ARROW|-10:0|-12:Unselect(0:12:n_U) Simple:NODE|-10:10|-10:Unselect(10_U) Edge:UP:SOLID|-10:10:4|-10:Unselect(0:10:n_U) Edge:DOWN:SOLID|-10:10:10|-22:Unselect(10:12:n_U) - Simple:UP_ARROW|-10:11|-11:Unselect(0:11:n_U) - Edge:UP:SOLID|-10:11:5|-11:Unselect(0:11:n_U) + Edge:UP_ARROW:SOLID|-10:11:5|-11:Unselect(0:11:n_U) Edge:DOWN:SOLID|-10:11:11|-11:Unselect(0:11:n_U) -Simple:UP_ARROW|-11:0|-12:Unselect(0:12:n_U) - Edge:UP:SOLID|-11:0:0|-12:Unselect(0:12:n_U) +Edge:UP_ARROW:SOLID|-11:0:0|-12:Unselect(0:12:n_U) Edge:DOWN:SOLID|-11:0:0|-12:Unselect(0:12:n_U) - Simple:UP_ARROW|-11:1|-13:Unselect(1:12:n_U) - Edge:UP:SOLID|-11:1:1|-13:Unselect(1:12:n_U) + Edge:UP_ARROW:SOLID|-11:1:1|-13:Unselect(1:12:n_U) Edge:DOWN:SOLID|-11:1:0|-13:Unselect(1:12:n_U) - Simple:UP_ARROW|-11:2|-14:Unselect(2:12:n_U) - Edge:UP:SOLID|-11:2:2|-14:Unselect(2:12:n_U) + Edge:UP_ARROW:SOLID|-11:2:2|-14:Unselect(2:12:n_U) Edge:DOWN:SOLID|-11:2:0|-14:Unselect(2:12:n_U) Edge:UP:SOLID|-11:3:3|-15:Unselect(3:12:n_U) Edge:DOWN:SOLID|-11:3:0|-15:Unselect(3:12:n_U) diff --git a/platform/vcs-log/graph/testData/elementGenerator/specialElements_out.txt b/platform/vcs-log/graph/testData/elementGenerator/specialElements_out.txt index 7267b7f50520..1943c201a48d 100644 --- a/platform/vcs-log/graph/testData/elementGenerator/specialElements_out.txt +++ b/platform/vcs-log/graph/testData/elementGenerator/specialElements_out.txt @@ -2,17 +2,17 @@ Simple:NODE|-0:0|-0:Unselect(0_G) Edge:DOWN:DASHED|-0:0:0|-4:Unselect(0:4:n_D) Edge:DOWN:SOLID|-0:0:1|-0:Unselect(0:n:10_N) Edge:DOWN:DASHED|-0:0:2|-0:Unselect(0:n:11_O) - Simple:UP_ARROW|-0:1|-1:Unselect(n:1:0_P) + Edge:UP_ARROW:DASHED|-0:1:1|-1:Unselect(n:1:0_P) Edge:DOWN:DASHED|-0:1:3|-1:Unselect(n:1:0_P) Edge:UP:DASHED|-1:0:0|-4:Unselect(0:4:n_D) Edge:DOWN:DASHED|-1:0:0|-4:Unselect(0:4:n_D) - Simple:DOWN_ARROW|-1:1|-0:Unselect(0:n:10_N) Edge:UP:SOLID|-1:1:0|-0:Unselect(0:n:10_N) - Simple:DOWN_ARROW|-1:2|-0:Unselect(0:n:11_O) + Edge:DOWN_ARROW:SOLID|-1:1:1|-0:Unselect(0:n:10_N) Edge:UP:DASHED|-1:2:0|-0:Unselect(0:n:11_O) + Edge:DOWN_ARROW:DASHED|-1:2:2|-0:Unselect(0:n:11_O) Simple:NODE|-1:3|-1:Unselect(1_U) Edge:UP:DASHED|-1:3:1|-1:Unselect(n:1:0_P) - Simple:UP_ARROW|-1:4|-2:Unselect(n:2:0_P) + Edge:UP_ARROW:DASHED|-1:4:4|-2:Unselect(n:2:0_P) Edge:DOWN:DASHED|-1:4:1|-2:Unselect(n:2:0_P) Edge:UP:DASHED|-2:0:0|-4:Unselect(0:4:n_D) Edge:DOWN:DASHED|-2:0:0|-4:Unselect(0:4:n_D) @@ -22,10 +22,10 @@ Edge:UP:DASHED|-2:0:0|-4:Unselect(0:4:n_D) Edge:DOWN:SOLID|-2:1:2|-2:Unselect(2:n:12_N) Edge:UP:DASHED|-3:0:0|-4:Unselect(0:4:n_D) Edge:DOWN:DASHED|-3:0:0|-4:Unselect(0:4:n_D) - Simple:DOWN_ARROW|-3:1|-2:Unselect(2:n:3_O) Edge:UP:DASHED|-3:1:1|-2:Unselect(2:n:3_O) - Simple:DOWN_ARROW|-3:2|-2:Unselect(2:n:12_N) + Edge:DOWN_ARROW:DASHED|-3:1:1|-2:Unselect(2:n:3_O) Edge:UP:SOLID|-3:2:1|-2:Unselect(2:n:12_N) + Edge:DOWN_ARROW:SOLID|-3:2:2|-2:Unselect(2:n:12_N) Simple:NODE|-3:3|-3:Unselect(3_G) Simple:NODE|-4:0|-4:Unselect(4_U) Edge:UP:DASHED|-4:0:0|-4:Unselect(0:4:n_D) \ No newline at end of file From deea3a9c45e9533f2fb228fd9b2481e314811523 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 18 Aug 2015 22:39:29 +0300 Subject: [PATCH 024/172] [vcs-log] minor: inline paint(Up|Down)Arrow methods (cherry picked from commit 1de267c0a5ee023e422a575c11a0bed06b138ceb) --- .../printer/idea/SimpleGraphCellPainter.java | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java index 3dd0f5b63cd2..0d9304b90b0a 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java @@ -53,22 +53,34 @@ public class SimpleGraphCellPainter implements GraphCellPainter { return ROW_HEIGHT; } - private void paintUpLine(int from, int to, Color color) { + private void paintUpLine(int from, int to, Color color, boolean hasArrow) { int x1 = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; int y1 = getRowHeight() / 2; int x2 = PrintParameters.WIDTH_NODE * to + PrintParameters.WIDTH_NODE / 2; int y2 = -getRowHeight() / 2; g2.setColor(color); g2.drawLine(x2, y2, x1, y1); + if (hasArrow) { + int r = PrintParameters.CIRCLE_RADIUS; + int y = r + 2; + g2.drawLine(x1, y - r, x1 + r, y); + g2.drawLine(x1, y - r, x1 - r, y); + } } - private void paintDownLine(int from, int to, Color color) { + private void paintDownLine(int from, int to, Color color, boolean hasArrow) { int x1 = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; int y1 = getRowHeight() / 2; int x2 = PrintParameters.WIDTH_NODE * to + PrintParameters.WIDTH_NODE / 2; int y2 = getRowHeight() + getRowHeight() / 2; g2.setColor(color); g2.drawLine(x1, y1, x2, y2); + if (hasArrow) { + int r = PrintParameters.CIRCLE_RADIUS; + int y = getRowHeight() - r - 2; + g2.drawLine(x1, y + r, x1 + r, y); + g2.drawLine(x1, y + r, x1 - r, y); + } } private void paintCircle(int position, Color color, boolean select) { @@ -83,24 +95,6 @@ public class SimpleGraphCellPainter implements GraphCellPainter { g2.fill(circle); } - private void paintDownArrow(int position, Color color) { - int x0 = PrintParameters.WIDTH_NODE * position + PrintParameters.WIDTH_NODE / 2; - int r = PrintParameters.CIRCLE_RADIUS; - int y0 = getRowHeight() - r - 2; - g2.setColor(color); - g2.drawLine(x0, y0 + r, x0 + r, y0); - g2.drawLine(x0, y0 + r, x0 - r, y0); - } - - private void paintUpArrow(int position, Color color) { - int x0 = PrintParameters.WIDTH_NODE * position + PrintParameters.WIDTH_NODE / 2; - int r = PrintParameters.CIRCLE_RADIUS; - int y0 = r + 2; - g2.setColor(color); - g2.drawLine(x0, y0 - r, x0 + r, y0); - g2.drawLine(x0, y0 - r, x0 - r, y0); - } - private void setStroke(boolean usual, boolean select) { if (usual) { if (select) { @@ -164,16 +158,10 @@ public class SimpleGraphCellPainter implements GraphCellPainter { int to = edgePrintElement.getPositionInOtherRow(); if (edgePrintElement.getType() == EdgePrintElement.Type.DOWN) { - paintDownLine(from, to, color); - if (edgePrintElement.hasArrow()) { - paintDownArrow(from, color); - } + paintDownLine(from, to, color, edgePrintElement.hasArrow()); } else { - paintUpLine(from, to, color); - if (edgePrintElement.hasArrow()) { - paintUpArrow(from, color); - } + paintUpLine(from, to, color, edgePrintElement.hasArrow()); } } }; From f926dc2deee8dcc73512b86a47ed5c28b90de88b Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Thu, 20 Aug 2015 19:35:07 +0300 Subject: [PATCH 025/172] [vcs-log] fix lines and arrows painting (fixes IDEA-135359): - vertical lines have normal size and do not have visible junctions anymore; - diagonals are still twice the size (impossible to make them connect to each other well otherwize); - arrows rotate with lines. (cherry picked from commit 25aefc664e63121bdd7d82c298154dd22489c7f9) --- .../printer/idea/SimpleGraphCellPainter.java | 74 ++++++++++++++----- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java index 0d9304b90b0a..90a35c3991ee 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/printer/idea/SimpleGraphCellPainter.java @@ -15,6 +15,7 @@ */ package com.intellij.vcs.log.printer.idea; +import com.intellij.openapi.util.Pair; import com.intellij.ui.JBColor; import com.intellij.vcs.log.graph.EdgePrintElement; import com.intellij.vcs.log.graph.NodePrintElement; @@ -24,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; import java.util.Collection; /** @@ -33,6 +35,8 @@ public class SimpleGraphCellPainter implements GraphCellPainter { private static final Color MARK_COLOR = JBColor.BLACK; private static final int ROW_HEIGHT = 24; + private static final double ARROW_ANGLE_COS2 = 0.7; + private static final double ARROW_LENGTH = 0.3; private final Stroke usual = new BasicStroke(PrintParameters.THICK_LINE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL); private final Stroke hide = @@ -54,35 +58,67 @@ public class SimpleGraphCellPainter implements GraphCellPainter { } private void paintUpLine(int from, int to, Color color, boolean hasArrow) { - int x1 = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; - int y1 = getRowHeight() / 2; - int x2 = PrintParameters.WIDTH_NODE * to + PrintParameters.WIDTH_NODE / 2; - int y2 = -getRowHeight() / 2; - g2.setColor(color); - g2.drawLine(x2, y2, x1, y1); - if (hasArrow) { - int r = PrintParameters.CIRCLE_RADIUS; - int y = r + 2; - g2.drawLine(x1, y - r, x1 + r, y); - g2.drawLine(x1, y - r, x1 - r, y); + // paint vertical lines normal size + // paint non-vertical lines twice the size to make them dock with each other well + if (from == to) { + int x = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; + int y1 = getRowHeight() / 2 - 1; + int y2 = 0; + paintLine(color, hasArrow, x, y1, x, y2, x, y2); + } + else { + int x1 = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; + int y1 = getRowHeight() / 2; + int x2 = PrintParameters.WIDTH_NODE * to + PrintParameters.WIDTH_NODE / 2; + int y2 = -getRowHeight() / 2; + paintLine(color, hasArrow, x1, y1, x2, y2, (x1 + x2) / 2, (y1 + y2) / 2); } } private void paintDownLine(int from, int to, Color color, boolean hasArrow) { - int x1 = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; - int y1 = getRowHeight() / 2; - int x2 = PrintParameters.WIDTH_NODE * to + PrintParameters.WIDTH_NODE / 2; - int y2 = getRowHeight() + getRowHeight() / 2; + if (from == to) { + int y2 = getRowHeight() - 1; + int y1 = getRowHeight() / 2; + int x = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; + paintLine(color, hasArrow, x, y1, x, y2, x, y2); + } + else { + int x1 = PrintParameters.WIDTH_NODE * from + PrintParameters.WIDTH_NODE / 2; + int y1 = getRowHeight() / 2; + int x2 = PrintParameters.WIDTH_NODE * to + PrintParameters.WIDTH_NODE / 2; + int y2 = getRowHeight() + getRowHeight() / 2; + paintLine(color, hasArrow, x1, y1, x2, y2, (x1 + x2) / 2, (y1 + y2) / 2); + } + } + + private void paintLine(Color color, boolean hasArrow, int x1, int y1, int x2, int y2, int startArrowX, int startArrowY) { g2.setColor(color); g2.drawLine(x1, y1, x2, y2); if (hasArrow) { - int r = PrintParameters.CIRCLE_RADIUS; - int y = getRowHeight() - r - 2; - g2.drawLine(x1, y + r, x1 + r, y); - g2.drawLine(x1, y + r, x1 - r, y); + Pair rotate1 = + rotate(x1, y1, startArrowX, startArrowY, Math.sqrt(ARROW_ANGLE_COS2), Math.sqrt(1 - ARROW_ANGLE_COS2), ARROW_LENGTH * getRowHeight()); + Pair rotate2 = + rotate(x1, y1, startArrowX, startArrowY, Math.sqrt(ARROW_ANGLE_COS2), -Math.sqrt(1 - ARROW_ANGLE_COS2), ARROW_LENGTH * getRowHeight()); + g2.drawLine(startArrowX, startArrowY, rotate1.first, rotate1.second); + g2.drawLine(startArrowX, startArrowY, rotate2.first, rotate2.second); } } + @NotNull + private static Pair rotate(double x, double y, double centerX, double centerY, double cos, double sin, double arrowLength) { + double translateX = (x - centerX); + double translateY = (y - centerY); + + double d = Math.sqrt(translateX * translateX + translateY * translateY); + double scaleX = arrowLength * translateX / d; + double scaleY = arrowLength * translateY / d; + + double rotateX = scaleX * cos - scaleY * sin; + double rotateY = scaleX * sin + scaleY * cos; + + return Pair.create((int)Math.round(rotateX + centerX), (int)Math.round(rotateY + centerY)); + } + private void paintCircle(int position, Color color, boolean select) { int x0 = PrintParameters.WIDTH_NODE * position + PrintParameters.WIDTH_NODE / 2; int y0 = getRowHeight() / 2; From ff0dce837937f102f1b9bd807894ebda9f19c474 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Thu, 27 Aug 2015 17:54:18 +0300 Subject: [PATCH 026/172] [Hg]: Remove history limit for annotate command (IDEA-137686) * without file details it shouldn't lead to any performance problem --- .../zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java index 451e113618ee..110d67a2b1f0 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java @@ -36,8 +36,6 @@ import java.util.List; public class HgAnnotationProvider implements AnnotationProvider { - private static final int DEFAULT_LIMIT = 500; - @NotNull private final Project myProject; public HgAnnotationProvider(@NotNull Project project) { @@ -63,7 +61,7 @@ public class HgAnnotationProvider implements AnnotationProvider { try { HgLogCommand logCommand = new HgLogCommand(myProject); logCommand.setFollowCopies(true); - logResult = logCommand.execute(fileToAnnotate, DEFAULT_LIMIT, false); + logResult = logCommand.execute(fileToAnnotate, -1, false); } catch (HgCommandException e) { throw new VcsException("Can not annotate, " + HgVcsMessages.message("hg4idea.error.log.command.execution"), e); From d57591cd2c3b1990f01ca50a21e8e2e2bf27d561 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 27 Aug 2015 17:44:06 +0200 Subject: [PATCH 027/172] IDEA-142912 (Intention: replace switch with if failed with bit operator (operator precedence)) --- .../impl/quickfix/ConvertSwitchToIfIntention.java | 7 +++++-- .../quickFix/convertSwitchToIf/after4.java | 13 +++++++++++++ .../quickFix/convertSwitchToIf/before4.java | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/after4.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/before4.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java index 72df2025348f..44cd9f7dc587 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -25,6 +25,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.ParenthesesUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -117,7 +118,9 @@ public class ConvertSwitchToIfIntention implements IntentionAction { else { hadSideEffects = false; declarationString = null; - expressionText = switchExpression.getText(); + expressionText = ParenthesesUtils.getPrecedence(switchExpression) > ParenthesesUtils.EQUALITY_PRECEDENCE + ? '(' + switchExpression.getText() + ')' + : switchExpression.getText(); } final PsiCodeBlock body = switchStatement.getBody(); if (body == null) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/after4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/after4.java new file mode 100644 index 000000000000..8ab4527ff5a4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/after4.java @@ -0,0 +1,13 @@ +// "Replace 'switch' with 'if'" "true" +class Precedence { + + void m() { + int a = 10; + if ((a & 1) == 0) { + System.out.println("0"); + + } else if ((a & 1) == 1) { + System.out.println("1"); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/before4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/before4.java new file mode 100644 index 000000000000..7301511c7ef4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertSwitchToIf/before4.java @@ -0,0 +1,14 @@ +// "Replace 'switch' with 'if'" "true" +class Precedence { + + void m() { + int a = 10; + switch(a & 1) { + case 0: + System.out.println("0"); + break; + case 1: + System.out.println("1"); + } + } +} \ No newline at end of file From 0461737812508d93d9c9f36eaa4fe3563d1e9124 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Thu, 27 Aug 2015 11:35:43 +0300 Subject: [PATCH 028/172] Added base class for creating list of formatting blocks for any ASTNode, code building array initializer blocks moved into separate class, fixed IDEA-55518 --- .../psi/formatter/java/AbstractJavaBlock.java | 28 +++- .../java/ArrayInitializerBlocksBuilder.java | 73 +++++++++ .../java/BlockContainingJavaBlock.java | 10 +- .../psi/formatter/java/BlockFactory.java | 34 +++++ .../formatter/java/ChildrenBlocksBuilder.java | 142 ++++++++++++++++++ 5 files changed, 275 insertions(+), 12 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java create mode 100644 java/java-impl/src/com/intellij/psi/formatter/java/BlockFactory.java create mode 100644 java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index d4f1a12ccba8..25bd89226a38 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -69,6 +69,23 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo private Map myPreferredWraps; private AbstractJavaBlock myParentBlock; + private BlockFactory myBlockFactory = new BlockFactory() { + @Override + public Block createBlock(ASTNode node, Indent indent, Alignment alignment, Wrap wrap) { + return new SimpleJavaBlock(node, wrap, AlignmentStrategy.wrap(alignment), indent, mySettings, myJavaSettings); + } + + @Override + public CommonCodeStyleSettings getSettings() { + return mySettings; + } + + @Override + public JavaCodeStyleSettings getJavaSettings() { + return myJavaSettings; + } + }; + protected AbstractJavaBlock(@NotNull final ASTNode node, final Wrap wrap, final Alignment alignment, @@ -476,12 +493,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo if (nodeType == JavaElementType.POLYADIC_EXPRESSION) nodeType = JavaElementType.BINARY_EXPRESSION; if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ARRAY_INITIALIZER_EXPRESSION) { - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); - child = processParenthesisBlock(JavaTokenType.LBRACE, JavaTokenType.RBRACE, - result, - child, - WrappingStrategy.createDoNotWrapCommaStrategy(wrap), - mySettings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION); + ArrayInitializerBlocksBuilder builder = new ArrayInitializerBlocksBuilder(myNode, myBlockFactory); + List newlyCreated = builder.buildBlocks(); + + child = myNode.getLastChildNode(); + result.addAll(newlyCreated); } else if (childType == JavaTokenType.LBRACE && nodeType == JavaElementType.ANNOTATION_ARRAY_INITIALIZER) { final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java new file mode 100644 index 000000000000..44b605b55600 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2015 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.psi.formatter.java; + +import com.intellij.formatting.Alignment; +import com.intellij.formatting.Block; +import com.intellij.formatting.Indent; +import com.intellij.formatting.Wrap; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.util.PsiTreeUtil; + +import java.util.List; + +import static com.intellij.psi.formatter.java.JavaFormatterUtil.getWrapType; + +public class ArrayInitializerBlocksBuilder { + private final ASTNode myNode; + private final BlockFactory myBlockFactory; + private final CommonCodeStyleSettings mySettings; + + public ArrayInitializerBlocksBuilder(ASTNode node, BlockFactory blockFactory) { + myNode = node; + myBlockFactory = blockFactory; + mySettings = myBlockFactory.getSettings(); + } + + public List buildBlocks() { + Wrap wrap = Wrap.createWrap(getWrapType(mySettings.ARRAY_INITIALIZER_WRAP), false); + Alignment alignment = mySettings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION ? Alignment.createAlignment() : null; + + ChildrenBlocksBuilder.Config config = new ChildrenBlocksBuilder.Config() + .setDefaultIndent(Indent.getContinuationWithoutFirstIndent()) + .setIndent(JavaTokenType.RBRACE, Indent.getNoneIndent()) + .setIndent(JavaTokenType.LBRACE, Indent.getNoneIndent()) + + .setDefaultWrap(wrap) + .setNoWrap(JavaTokenType.COMMA) + .setNoWrap(JavaTokenType.RBRACE) + .setNoWrap(JavaTokenType.LBRACE) + + .setDefaultAlignment(alignment) + .setNoAlignment(JavaTokenType.COMMA) + .setNoAlignment(JavaTokenType.LBRACE) + .setAlignmentIf(JavaTokenType.RBRACE, alignment, new Condition() { + @Override + public boolean value(ASTNode node) { + PsiElement prev = PsiTreeUtil.skipSiblingsBackward(node.getPsi(), PsiWhiteSpace.class); + if (prev == null) return false; + return prev.getNode().getElementType() == JavaTokenType.COMMA; + } + }); + + return config.createBuilder().buildNodeChildBlocks(myNode, myBlockFactory); + } +} diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java index 3ba6ef5e263b..9c1da188c90e 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java @@ -17,9 +17,7 @@ package com.intellij.psi.formatter.java; import com.intellij.formatting.*; import com.intellij.lang.ASTNode; -import com.intellij.psi.JavaTokenType; -import com.intellij.psi.PsiStatement; -import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.*; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; @@ -255,8 +253,8 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{ if (prevBlock instanceof ASTBlock && nextBlock instanceof ASTBlock) { ASTNode prevNode = ((ASTBlock)prevBlock).getNode(); ASTNode nextNode = ((ASTBlock)nextBlock).getNode(); - if (prevNode != null && nextNode != null && prevNode.getElementType() == JavaTokenType.RPARENTH - && nextNode.getElementType() != JavaTokenType.LBRACE) + if (prevNode != null && nextNode != null && prevNode.getElementType() == JavaTokenType.RPARENTH + && nextNode.getElementType() != JavaTokenType.LBRACE) { useExternalIndent = true; } @@ -267,7 +265,7 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{ return new ChildAttributes(getCodeBlockChildExternalIndent(newChildIndex), null); } else { - return new ChildAttributes(myIndentsBefore.get(newChildIndex), null); + return new ChildAttributes(myIndentsBefore.get(newChildIndex), getUsedAlignment(newChildIndex)); } } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/BlockFactory.java b/java/java-impl/src/com/intellij/psi/formatter/java/BlockFactory.java new file mode 100644 index 000000000000..3069d2339065 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/formatter/java/BlockFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2015 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.psi.formatter.java; + +import com.intellij.formatting.Alignment; +import com.intellij.formatting.Block; +import com.intellij.formatting.Indent; +import com.intellij.formatting.Wrap; +import com.intellij.lang.ASTNode; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.codeStyle.JavaCodeStyleSettings; + +public interface BlockFactory { + + Block createBlock(ASTNode node, Indent indent, Alignment alignment, Wrap wrap); + + CommonCodeStyleSettings getSettings(); + + JavaCodeStyleSettings getJavaSettings(); + +} diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java new file mode 100644 index 000000000000..0697a0b8098a --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java @@ -0,0 +1,142 @@ +/* + * Copyright 2000-2015 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.psi.formatter.java; + +import com.intellij.formatting.Alignment; +import com.intellij.formatting.Block; +import com.intellij.formatting.Indent; +import com.intellij.formatting.Wrap; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.formatter.FormatterUtil; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; + +public class ChildrenBlocksBuilder { + private Config myConfig; + + private ChildrenBlocksBuilder(Config builder) { + myConfig = builder; + } + + public List buildNodeChildBlocks(ASTNode node, BlockFactory factory) { + List blocks = ContainerUtil.newArrayList(); + + for (ASTNode child : node.getChildren(null)) { + if (FormatterUtil.isWhitespaceOrEmpty(child)) { + continue; + } + + Alignment alignment = myConfig.getAlignment(child); + + IElementType type = child.getElementType(); + Indent indent = myConfig.getIndent(type); + Wrap wrap = myConfig.getWrap(type); + + blocks.add(factory.createBlock(child, indent, alignment, wrap)); + } + + return blocks; + } + + public static class Config { + private static final Alignment NO_ALIGNMENT = Alignment.createAlignment(); + private static final Wrap NO_WRAP = Wrap.createWrap(0, false); + + private Map myAlignments = ContainerUtil.newHashMap(); + private Map myIndents = ContainerUtil.newHashMap(); + private Map myWraps = ContainerUtil.newHashMap(); + + private Map> myApplyAlignCondition = ContainerUtil.newHashMap(); + + private Alignment myDefaultAlignment; + private Indent myDefaultIndent; + private Wrap myDefaultWrap; + + public ChildrenBlocksBuilder createBuilder() { + return new ChildrenBlocksBuilder(this); + } + + public Config setDefaultAlignment(Alignment alignment) { + myDefaultAlignment = alignment; + return this; + } + + public Config setDefaultWrap(Wrap wrap) { + myDefaultWrap = wrap; + return this; + } + + public Config setDefaultIndent(Indent indent) { + myDefaultIndent = indent; + return this; + } + + public Config setAlignment(@NotNull IElementType elementType, @NotNull Alignment alignment) { + myAlignments.put(elementType, alignment); + return this; + } + + public Config setNoAlignment(IElementType elementType) { + myAlignments.put(elementType, NO_ALIGNMENT); + return this; + } + + public Config setAlignmentIf(IElementType elementType, Alignment alignment, Condition applyAlignCondition) { + myAlignments.put(elementType, alignment); + myApplyAlignCondition.put(elementType, applyAlignCondition); + return this; + } + + public Config setIndent(IElementType elementType, Indent indent) { + myIndents.put(elementType, indent); + return this; + } + + private Indent getIndent(IElementType elementType) { + Indent indent = myIndents.get(elementType); + return indent != null ? indent : myDefaultIndent; + } + + private Alignment getAlignment(ASTNode node) { + IElementType elementType = node.getElementType(); + Alignment alignment = myAlignments.get(elementType); + if (alignment != null) { + Condition applyAlignCondition = myApplyAlignCondition.get(elementType); + if (applyAlignCondition == null || applyAlignCondition.value(node)) { + return alignment == NO_ALIGNMENT ? null : alignment; + } + } + return myDefaultAlignment; + } + + private Wrap getWrap(IElementType elementType) { + Wrap wrap = myWraps.get(elementType); + if (wrap == NO_WRAP) return null; + return wrap != null ? wrap : myDefaultWrap; + } + + public Config setNoWrap(IElementType elementType) { + myWraps.put(elementType, NO_WRAP); + return this; + } + + } +} From 5ee8d4b090f5a908c76f816e4108c110ebcf706c Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Thu, 27 Aug 2015 18:52:58 +0300 Subject: [PATCH 029/172] IDEA-144205 Bad grammar --- .../src/messages/ApplicationBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index dbb2f09d4ee4..a89267e997c6 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -384,7 +384,7 @@ label.collapse.by.default=Collapse by default: checkbox.show.code.folding.outline=Show code folding outline group.tab.appearance=Tab Appearance editbox.tab.limit=Tab limit: -checkbox.smart.tab.reuse=Navigation from not-modified tab will reuse it +checkbox.smart.tab.reuse=Navigation from non-modified tab will reuse it combobox.editor.tab.placement=Placement: checkbox.editor.tabs.in.single.row=Show tabs in single row checkbox.editor.tabs.show.close.button=Show "close" button on editor tabs From 23a6b58d69067e43d81d3d9ea0b128754068981f Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 27 Aug 2015 12:55:56 +0300 Subject: [PATCH 030/172] EA-71215 - assert: AnonymousCanBeLambdaInspection.replacePsiElementWithLambda --- .../codeInspection/AnonymousCanBeLambdaInspection.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index 953ac60f2bc1..ade25c7b1d5d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -211,7 +211,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return null; final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass(); - LOG.assertTrue(anonymousClass != null); + if (anonymousClass == null) return null; ChangeContextUtil.encodeContextInfo(anonymousClass, true); final PsiElement lambdaContext = anonymousClass.getParent().getParent(); @@ -229,10 +229,10 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection } else { method = anonymousClass.getMethods()[0]; } - LOG.assertTrue(method != null); + if (method == null) return null; final PsiCodeBlock body = method.getBody(); - LOG.assertTrue(body != null); + if (body == null) return null; final ForbiddenRefsChecker checker = new ForbiddenRefsChecker(method, anonymousClass); body.accept(checker); From 35b509e1f94a11a8294bb7e9818f30f80c6c5d03 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 27 Aug 2015 16:47:34 +0300 Subject: [PATCH 031/172] guava fluent: replace method parameters with field refactoring; simplification --- .../GuavaFluentIterableInspection.java | 13 +- .../GuavaFluentIterableMethodConverters.java | 132 ++++++++---------- 2 files changed, 70 insertions(+), 75 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableInspection.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableInspection.java index bfc25cb7e8f6..1b1337674244 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableInspection.java @@ -56,8 +56,7 @@ public class GuavaFluentIterableInspection extends BaseJavaBatchLocalInspectionT return null; } final Project project = manager.getProject(); - final PsiClass fluentIterable = JavaPsiFacade.getInstance(project) - .findClass(GUAVA_FLUENT_ITERABLE, GlobalSearchScope.allScope(project)); + final PsiClass fluentIterable = JavaPsiFacade.getInstance(project).findClass(GUAVA_FLUENT_ITERABLE, file.getResolveScope()); if (fluentIterable == null) { return null; } @@ -394,7 +393,7 @@ public class GuavaFluentIterableInspection extends BaseJavaBatchLocalInspectionT if (parameterType instanceof PsiClassType) { final PsiClass resolvedParameterClass = ((PsiClassType)parameterType).resolve(); final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(methodCallExpression.getProject()); - final GlobalSearchScope scope = GlobalSearchScope.allScope(methodCallExpression.getProject()); + final GlobalSearchScope scope = methodCallExpression.getResolveScope(); final PsiClass optional = javaPsiFacade.findClass(GUAVA_OPTIONAL, scope); final PsiClass immutableMap = javaPsiFacade.findClass(GUAVA_IMMUTABLE_MAP, scope); if (resolvedParameterClass != null && @@ -474,16 +473,20 @@ public class GuavaFluentIterableInspection extends BaseJavaBatchLocalInspectionT final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project); final PsiElementFactory elementFactory = javaPsiFacade.getElementFactory(); final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); + final GuavaFluentIterableMethodConverters converters = new GuavaFluentIterableMethodConverters(elementFactory); for (SmartPsiElementPointer usage : myFoundUsages) { final PsiExpression element = usage.getElement(); if (element != null) { - GuavaFluentIterableMethodConverters.convert(element, elementFactory, codeStyleManager); + PsiElement converted = converters.convert(element); + if (converted != null) { + codeStyleManager.shortenClassReferences(converted); + } } } if (myVariable != null) { final PsiLocalVariable element = myVariable.getElement(); if (element != null) { - GuavaFluentIterableMethodConverters.convert(element, elementFactory, codeStyleManager); + codeStyleManager.shortenClassReferences(converters.convert(element)); } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableMethodConverters.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableMethodConverters.java index 1a44ef29a563..ade6ce30c197 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableMethodConverters.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFluentIterableMethodConverters.java @@ -18,9 +18,7 @@ package com.intellij.codeInspection.java18StreamApi; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -42,6 +40,11 @@ public class GuavaFluentIterableMethodConverters { private static final Map METHOD_INDEX = new HashMap(); private static final Map TO_OTHER_COLLECTION_METHODS = new HashMap(); private static final Set STOP_METHODS = new HashSet(); + private final PsiElementFactory myElementFactory; + + public GuavaFluentIterableMethodConverters(PsiElementFactory elementFactory) { + myElementFactory = elementFactory; + } static { METHOD_INDEX.put("allMatch", new FluentIterableMethodTransformer.OneParameterMethodTransformer(StreamApiConstants.ALL_MATCH + "(%s)", true)); @@ -86,52 +89,44 @@ public class GuavaFluentIterableMethodConverters { return STOP_METHODS.contains(methodName); } - public static void convert(final PsiLocalVariable localVariable, - final PsiElementFactory elementFactory, - final JavaCodeStyleManager codeStyleManager) { + public PsiLocalVariable convert(final PsiLocalVariable localVariable) { final PsiTypeElement typeElement = localVariable.getTypeElement(); final PsiReferenceParameterList generics = PsiTreeUtil.findChildOfType(typeElement, PsiReferenceParameterList.class); - typeElement.replace(elementFactory.createTypeElementFromText( + typeElement.replace(myElementFactory.createTypeElementFromText( StreamApiConstants.JAVA_UTIL_STREAM_STREAM + (generics == null ? "" : generics.getText()), null)); final PsiExpression initializer = localVariable.getInitializer(); if (initializer != null) { - PsiMethodCallExpression initializerMethodCall = (PsiMethodCallExpression)initializer; - convertMethodCallDeep(elementFactory, initializerMethodCall); + convertMethodCallDeep((PsiMethodCallExpression)initializer); } - codeStyleManager.shortenClassReferences(localVariable); + return localVariable; } - public static void convert(PsiExpression expression, - final PsiElementFactory elementFactory, - final JavaCodeStyleManager codeStyleManager) { + public PsiElement convert(PsiExpression expression) { if (expression instanceof PsiReferenceExpression) { final PsiElement expressionParent = expression.getParent(); if (expressionParent instanceof PsiReturnStatement || isIterableMethodParameter(expressionParent, expression)) { - expression = (PsiExpression)expression.replace( - elementFactory.createExpressionFromText(expression.getText() + ".collect(java.util.stream.Collectors.toList())", null)); - codeStyleManager.shortenClassReferences(expression); + return addCollectionToList(expression); } - return; + return null; } final PsiMethodCallExpression parentMethodCall = PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class); if (parentMethodCall != null && parentMethodCall.getMethodExpression().getQualifierExpression() == expression) { final PsiMethod seqTailMethod = parentMethodCall.resolveMethod(); if (seqTailMethod == null) { - return; + return null; } final PsiClass seqTailMethodClass = seqTailMethod.getContainingClass(); if (seqTailMethodClass != null && GuavaFluentIterableInspection.GUAVA_OPTIONAL.equals(seqTailMethodClass.getQualifiedName())) { - final PsiMethodCallExpression newParentMethodCall = - GuavaOptionalConverter.convertGuavaOptionalToJava(parentMethodCall, elementFactory); + final PsiMethodCallExpression newParentMethodCall = GuavaOptionalConverter.convertGuavaOptionalToJava(parentMethodCall, myElementFactory); expression = newParentMethodCall.getMethodExpression().getQualifierExpression(); } } if (expression instanceof PsiMethodCallExpression) { - expression = convertMethodCallDeep(elementFactory, (PsiMethodCallExpression)expression); + expression = convertMethodCallDeep((PsiMethodCallExpression)expression); } if (expression == null) { - return; + return null; } final PsiElement parent = expression.getParent(); if (parent instanceof PsiExpressionList) { @@ -142,28 +137,28 @@ public class GuavaFluentIterableMethodConverters { final PsiMethod method = methodCall.resolveMethod(); LOG.assertTrue(method != null); final PsiType parameterType = method.getParameterList().getParameters()[index].getType(); - expression = addCollectToListIfNeed(expression, parameterType, elementFactory); - } else if (parent instanceof PsiReturnStatement) { + return addCollectToListIfNeed(expression, parameterType); + } + else if (parent instanceof PsiReturnStatement) { final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); LOG.assertTrue(containingMethod != null); final PsiType returnType = containingMethod.getReturnType(); - expression = addCollectToListIfNeed(expression, returnType, elementFactory); - } - codeStyleManager.shortenClassReferences(expression); - } - - private static PsiExpression addCollectToListIfNeed(PsiExpression expression, PsiType type, PsiElementFactory elementFactory) { - if (type instanceof PsiClassType) { - PsiClass resolvedParamClass = ((PsiClassType)type).resolve(); - if (resolvedParamClass != null && CommonClassNames.JAVA_LANG_ITERABLE.equals(resolvedParamClass.getQualifiedName())) { - final PsiExpression newExpression = - elementFactory.createExpressionFromText(expression.getText() + ".collect(java.util.stream.Collectors.toList())", null); - return (PsiExpression) expression.replace(newExpression); - } + return addCollectToListIfNeed(expression, returnType); } return expression; } + private PsiExpression addCollectToListIfNeed(PsiExpression expression, PsiType type) { + if (type instanceof PsiClassType && ((PsiClassType)type).rawType().equalsToText(CommonClassNames.JAVA_LANG_ITERABLE)) { + return (PsiExpression)addCollectionToList(expression); + } + return expression; + } + + private PsiElement addCollectionToList(PsiElement expression) { + return expression.replace(myElementFactory.createExpressionFromText(expression.getText() + ".collect(java.util.stream.Collectors.toList())", null)); + } + private static boolean isIterableMethodParameter(PsiElement listExpression, PsiExpression parameterExpression) { if (!(listExpression instanceof PsiExpressionList)) { return false; @@ -172,28 +167,38 @@ public class GuavaFluentIterableMethodConverters { return false; } final Project project = parameterExpression.getProject(); - final PsiClass fluentIterable = JavaPsiFacade.getInstance(project) - .findClass(GuavaFluentIterableInspection.GUAVA_FLUENT_ITERABLE, GlobalSearchScope.allScope(project)); + final PsiClass fluentIterable = JavaPsiFacade.getInstance(project).findClass(GuavaFluentIterableInspection.GUAVA_FLUENT_ITERABLE, + listExpression.getResolveScope()); return GuavaFluentIterableInspection.isMethodWithParamAcceptsConversion((PsiMethodCallExpression)listExpression.getParent(), parameterExpression, fluentIterable); } @Nullable - private static PsiMethodCallExpression convertMethodCallDeep(PsiElementFactory elementFactory, - @NotNull PsiMethodCallExpression methodCall) { + private PsiMethodCallExpression convertMethodCallDeep(@NotNull PsiMethodCallExpression methodCall) { PsiMethodCallExpression newMethodCall = methodCall; PsiMethodCallExpression returnCall = null; while (true) { - final Pair converted = convertMethodCall(elementFactory, newMethodCall); - if (converted.getSecond()) { + final PsiReferenceExpression methodExpression = newMethodCall.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + PsiMethodCallExpression converted = convertFromMethodCall(newMethodCall); + if (converted != null) { return returnCall; } + if (TO_OTHER_COLLECTION_METHODS.containsKey(name)) { + converted = convertToCollection(newMethodCall, name); + } + else { + final FluentIterableMethodTransformer transformer = METHOD_INDEX.get(name); + LOG.assertTrue(transformer != null, name); + converted = transformer.transform(newMethodCall, myElementFactory); + } + if (converted == null) { + return returnCall; + } + if (returnCall == null) { - returnCall = converted.getFirst(); + returnCall = converted; } - if (converted.getFirst() == null) { - return returnCall; - } - newMethodCall = converted.getFirst(); + newMethodCall = converted; final PsiExpression expression = newMethodCall.getMethodExpression().getQualifierExpression(); if (expression instanceof PsiMethodCallExpression) { newMethodCall = (PsiMethodCallExpression)expression; @@ -203,42 +208,30 @@ public class GuavaFluentIterableMethodConverters { } } } - - public static Pair convertMethodCall(PsiElementFactory elementFactory, PsiMethodCallExpression methodCall) { - final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); - final String name = methodExpression.getReferenceName(); - if (TO_OTHER_COLLECTION_METHODS.containsKey(name)) { - return Pair.create(convertToCollection(methodCall, name, elementFactory), false); - } - else if (GuavaFluentIterableInspection.FLUENT_ITERABLE_FROM.equals(name)) { + + private PsiMethodCallExpression convertFromMethodCall(PsiMethodCallExpression methodCall) { + if (GuavaFluentIterableInspection.FLUENT_ITERABLE_FROM.equals(methodCall.getMethodExpression().getReferenceName())) { final PsiExpression[] argumentList = methodCall.getArgumentList().getExpressions(); LOG.assertTrue(argumentList.length == 1); final PsiExpression expression = argumentList[0]; final PsiType type = expression.getType(); LOG.assertTrue(type instanceof PsiClassType); - final PsiClass resolvedClass = ((PsiClassType)type).resolve(); final String newExpressionText; - if (InheritanceUtil.isInheritor(resolvedClass, CommonClassNames.JAVA_UTIL_COLLECTION)) { + if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_COLLECTION)) { newExpressionText = expression.getText() + ".stream()"; } else { newExpressionText = "java.util.stream.StreamSupport.stream(" + expression.getText() + ".spliterator(), false)"; } - return Pair.create((PsiMethodCallExpression)methodCall.replace(elementFactory.createExpressionFromText(newExpressionText, null)), true); - } - else { - final FluentIterableMethodTransformer transformer = METHOD_INDEX.get(name); - LOG.assertTrue(transformer != null, name); - final PsiMethodCallExpression transformedExpression = transformer.transform(methodCall, elementFactory); - return Pair.create(transformedExpression, false); + return (PsiMethodCallExpression)methodCall.replace(myElementFactory.createExpressionFromText(newExpressionText, null)); } + return null; } - private static PsiMethodCallExpression convertToCollection(final PsiMethodCallExpression methodCall, - final String methodName, - final PsiElementFactory elementFactory) { + private PsiMethodCallExpression convertToCollection(final PsiMethodCallExpression methodCall, + final String methodName) { final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions(); - assert expressions.length < 2; + LOG.assertTrue(expressions.length < 2); String template = TO_OTHER_COLLECTION_METHODS.get(methodName); if (expressions.length == 1) { template = String.format(template, expressions[0].getText()); @@ -247,8 +240,7 @@ public class GuavaFluentIterableMethodConverters { if (qualifier == null) { return null; } - final String text = qualifier.getText() + "." + template; - final PsiExpression expression = elementFactory.createExpressionFromText(text, null); + final PsiExpression expression = myElementFactory.createExpressionFromText(qualifier.getText() + "." + template, null); return (PsiMethodCallExpression)methodCall.replace(expression); } } From 8205a83947eed4eb6660d634af0759e21e6d5376 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 27 Aug 2015 17:42:41 +0300 Subject: [PATCH 032/172] ensure replace with lambda without cast; otherwise cast would be to the wrong type as it won't be migrated and pipeline header is supposed to be qualified --- .../java18StreamApi/PseudoLambdaReplaceTemplate.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java index 838032b0638e..cff890eb515c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java @@ -489,7 +489,16 @@ class PseudoLambdaReplaceTemplate { LOG.assertTrue(method != null); return JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(expression.getText() + "::" + method.getName(), null); } - return AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true); + + final PsiType psiType = expression.getType(); + if (psiType != null) { + PsiNewExpression newArrayExpression = (PsiNewExpression)JavaPsiFacade.getElementFactory(expression.getProject()) + .createExpressionFromText("new " + psiType.getCanonicalText() + "[]{" + expression.getText() + "}", expression); + PsiArrayInitializerExpression initializer = newArrayExpression.getArrayInitializer(); + LOG.assertTrue(initializer != null); + return AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(initializer.getInitializers()[0], true); + } + return null; } @NotNull From f1d0e6732afa814f8ae6df182452b023f1692ed8 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 27 Aug 2015 18:32:22 +0300 Subject: [PATCH 033/172] don't insert whitespace during extracting inplace --- .../introduce/inplace/InplaceVariableIntroducer.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index ad90339189d4..b9c702925fb7 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -21,8 +21,8 @@ import com.intellij.codeInsight.template.ExpressionContext; import com.intellij.codeInsight.template.TextResult; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.lang.ASTNode; -import com.intellij.lang.LanguageTokenSeparatorGenerators; +import com.intellij.lang.*; +import com.intellij.lexer.Lexer; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.command.impl.StartMarkAction; @@ -76,9 +76,12 @@ public abstract class InplaceVariableIntroducer extends In myOccurrences = occurrences; if (expr != null) { final ASTNode node = expr.getNode(); + ASTNode prev = node.getTreePrev(); final ASTNode astNode = LanguageTokenSeparatorGenerators.INSTANCE.forLanguage(expr.getLanguage()) - .generateWhitespaceBetweenTokens(node.getTreePrev(), node); - if (astNode != null) { + .generateWhitespaceBetweenTokens(prev, node); + final Lexer lexer = LanguageParserDefinitions.INSTANCE.forLanguage(expr.getLanguage()).createLexer(project); + if (astNode != null && + LanguageUtil.canStickTokensTogetherByLexer(prev, prev, lexer) == ParserDefinition.SpaceRequirements.MUST) { PostprocessReformattingAspect.getInstance(project).disablePostprocessFormattingInside(new Runnable() { @Override public void run() { From 201d8c2422f33ee940668a44bb74425a6e8b81c9 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 27 Aug 2015 19:09:39 +0300 Subject: [PATCH 034/172] do not use ExtensionPointName.findExtension, it prevents breakpoint types inheritance --- .../xdebugger/impl/breakpoints/XBreakpointManagerImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index fed4cdc556c7..d9084ba4230a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -34,6 +34,7 @@ import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.annotations.AbstractCollection; import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.xdebugger.XDebuggerUtil; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.breakpoints.*; import com.intellij.xdebugger.impl.XDebuggerManagerImpl; @@ -262,7 +263,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta @NotNull @Override public > Collection getBreakpoints(@NotNull Class> typeClass) { - return getBreakpoints(XBreakpointType.EXTENSION_POINT_NAME.findExtension(typeClass)); + return getBreakpoints(XDebuggerUtil.getInstance().findBreakpointType(typeClass)); } @Override From c50f4ff5fffe8c400fd05a8d791bc72d869426a1 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 27 Aug 2015 19:49:47 +0300 Subject: [PATCH 035/172] [test framework] load and dump only last 100K of a test log to avoid OOME --- .../testFramework/TestLoggerFactory.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java b/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java index fa63dca8a260..1e9d324729c0 100644 --- a/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java +++ b/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.io.RandomAccessFile; import java.io.StringReader; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -95,11 +96,31 @@ public class TestLoggerFactory implements Logger.Factory { return PathManager.getSystemPath() + "/" + LOG_DIR; } + private static final long SEEK_WINDOW = 100 * 1024; + public static void dumpLogToStdout(@NotNull String testStartMarker) { File ideaLog = new File(getTestLogDir(), "idea.log"); if (ideaLog.exists()) { try { - String logText = FileUtil.loadFile(ideaLog); + long length = ideaLog.length(); + String logText; + + if (length > SEEK_WINDOW) { + RandomAccessFile file = new RandomAccessFile(ideaLog, "r"); + try { + file.seek(length - SEEK_WINDOW); + byte[] bytes = new byte[(int)SEEK_WINDOW]; + int read = file.read(bytes); + logText = new String(bytes, 0, read); + } + finally { + file.close(); + } + } + else { + logText = FileUtil.loadFile(ideaLog); + } + Pattern logStart = Pattern.compile("[0-9\\-, :\\[\\]]+(DEBUG|INFO|ERROR) - "); System.out.println("\n\nIdea Log:"); for (String line : StringUtil.splitByLines(logText.substring(Math.max(0, logText.lastIndexOf(testStartMarker))))) { From 91c8c91d3eb4729d7d76f98ed3dbb0fd7f872515 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 27 Aug 2015 19:50:07 +0300 Subject: [PATCH 036/172] Cleanup (formatting) --- .../util/testSrc/com/intellij/util/text/StringUtilTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index 6af19a615746..19f32835f23a 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -294,7 +294,7 @@ public class StringUtilTest { @Test public void testReplace() { - assertEquals(StringUtil.replace("$PROJECT_FILE$/filename", "$PROJECT_FILE$", "/tmp"), "/tmp/filename"); + assertEquals("/tmp/filename", StringUtil.replace("$PROJECT_FILE$/filename", "$PROJECT_FILE$", "/tmp")); } @Test From 21987458cbb4cc85d414d1b7b604d132af06ea0e Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 27 Aug 2015 20:04:40 +0300 Subject: [PATCH 037/172] [test framework] test log size control --- .../intellij/testFramework/TestLoggerFactory.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java b/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java index 1e9d324729c0..02269aecb88f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java +++ b/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java @@ -39,6 +39,8 @@ public class TestLoggerFactory implements Logger.Factory { private static final String APPLICATION_MACRO = "$APPLICATION_DIR$"; private static final String LOG_DIR_MACRO = "$LOG_DIR$"; private static final String LOG_DIR = "testlog"; + private static final long LOG_SIZE_LIMIT = 100 * 1024 * 1024; + private static final long LOG_SEEK_WINDOW = 100 * 1024; private boolean myInitialized = false; @@ -85,6 +87,11 @@ public class TestLoggerFactory implements Logger.Factory { throw e; } + File ideaLog = new File(getTestLogDir(), "idea.log"); + if (ideaLog.exists() && ideaLog.length() >= LOG_SIZE_LIMIT) { + FileUtil.writeToFile(ideaLog, ""); + } + myInitialized = true; } catch (Exception e) { @@ -96,8 +103,6 @@ public class TestLoggerFactory implements Logger.Factory { return PathManager.getSystemPath() + "/" + LOG_DIR; } - private static final long SEEK_WINDOW = 100 * 1024; - public static void dumpLogToStdout(@NotNull String testStartMarker) { File ideaLog = new File(getTestLogDir(), "idea.log"); if (ideaLog.exists()) { @@ -105,11 +110,11 @@ public class TestLoggerFactory implements Logger.Factory { long length = ideaLog.length(); String logText; - if (length > SEEK_WINDOW) { + if (length > LOG_SEEK_WINDOW) { RandomAccessFile file = new RandomAccessFile(ideaLog, "r"); try { - file.seek(length - SEEK_WINDOW); - byte[] bytes = new byte[(int)SEEK_WINDOW]; + file.seek(length - LOG_SEEK_WINDOW); + byte[] bytes = new byte[(int)LOG_SEEK_WINDOW]; int read = file.read(bytes); logText = new String(bytes, 0, read); } From 29b16b090fdd95c7b48b158837eae1b271a9b312 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 27 Aug 2015 19:56:09 +0300 Subject: [PATCH 038/172] diff: save document before opening external tool --- .../tools/external/ExternalDiffToolUtil.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java b/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java index 0d075f734268..f249351111e2 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java @@ -67,6 +67,12 @@ public class ExternalDiffToolUtil { } else if (content instanceof FileContent) { VirtualFile file = ((FileContent)content).getFile(); + + Document document = FileDocumentManager.getInstance().getCachedDocument(file); + if (document != null) { + FileDocumentManager.getInstance().saveDocument(document); + } + if (file.isInLocalFileSystem()) { return file.getPath(); } @@ -123,14 +129,20 @@ public class ExternalDiffToolUtil { @NotNull public static OutputFile createOutputFile(@NotNull DiffContent content, @Nullable String windowTitle) throws IOException { if (content instanceof FileContent) { - FileContent fileContent = (FileContent)content; - if (fileContent.getFile().isInLocalFileSystem()) { - return new LocalOutputFile(fileContent.getFile()); + VirtualFile file = ((FileContent)content).getFile(); + + Document document = FileDocumentManager.getInstance().getCachedDocument(file); + if (document != null) { + FileDocumentManager.getInstance().saveDocument(document); + } + + if (file.isInLocalFileSystem()) { + return new LocalOutputFile(file); } String tempFileName = getFileName(null, windowTitle, content.getContentType()); - File tempFile = createTempFile(fileContent.getFile(), tempFileName); - return new NonLocalOutputFile(fileContent.getFile(), tempFile); + File tempFile = createTempFile(file, tempFileName); + return new NonLocalOutputFile(file, tempFile); } else if (content instanceof DocumentContent) { String tempFileName = getFileName(null, windowTitle, content.getContentType()); From 314e6ef81377e4f33a87b7371d5b9ebc371b225c Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 27 Aug 2015 20:02:21 +0300 Subject: [PATCH 039/172] IDEA-144343 diff: fix shortcut under mac Ctrl converted into Meta during import from default keymap. Meta+Tab is system shortcut. --- platform/platform-resources/src/idea/Keymap_Mac.xml | 6 ++++++ platform/platform-resources/src/idea/Keymap_MacClassic.xml | 6 ++++++ .../com/intellij/openapi/keymap/KeymapsTestCase.java | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/platform/platform-resources/src/idea/Keymap_Mac.xml b/platform/platform-resources/src/idea/Keymap_Mac.xml index 20bc6853f4b8..c443858dd875 100644 --- a/platform/platform-resources/src/idea/Keymap_Mac.xml +++ b/platform/platform-resources/src/idea/Keymap_Mac.xml @@ -299,6 +299,12 @@ + + + + + + diff --git a/platform/platform-resources/src/idea/Keymap_MacClassic.xml b/platform/platform-resources/src/idea/Keymap_MacClassic.xml index 90bebb9b242c..101e6dfb4c37 100644 --- a/platform/platform-resources/src/idea/Keymap_MacClassic.xml +++ b/platform/platform-resources/src/idea/Keymap_MacClassic.xml @@ -320,6 +320,12 @@ + + + + + + diff --git a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java index 7e82afffdbc2..bd53a43138a4 100644 --- a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java @@ -141,6 +141,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "meta BACK_SPACE", "EditorDeleteLine", "$Delete"}, { "control DOWN", "ShowContent", "EditorLookupDown", "MethodDown"}, { "control UP", "EditorLookupUp", "MethodUp"}, + { "control TAB", "Switcher", "Diff.FocusOppositePane"}, + { "shift control TAB", "Switcher", "Diff.FocusOppositePaneAndScroll"}, { "meta R", "Refresh", "Rerun", "Replace", "org.jetbrains.plugins.ruby.rails.console.ReloadSources"}, { "control O", "ExportToTextFile", "OverrideMethods", }, { "control ENTER", "Generate", "NewElement"}, @@ -161,6 +163,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "control UP", "EditorLookupUp", "MethodUp"}, { "control ENTER", "Generate", "NewElement"}, { "control F5", "Refresh", "Rerun"}, + { "control TAB", "Switcher", "Diff.FocusOppositePane"}, + { "shift control TAB", "Switcher", "Diff.FocusOppositePaneAndScroll"}, { "meta 1", "ActivateProjectToolWindow", "FileChooser.GotoHome", "DuplicatesForm.SendToLeft"}, { "meta 2", "ActivateFavoritesToolWindow", "FileChooser.GotoProject", "DuplicatesForm.SendToRight"}, { "meta 3", "ActivateFindToolWindow", "FileChooser.GotoModule"}, From c8de83b90af5d68aa5cc9421b3ad770bd6c29295 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 27 Aug 2015 19:55:46 +0200 Subject: [PATCH 040/172] make API public for Kotlin --- .../com/intellij/find/findUsages/JavaFindUsagesHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java index e836d2584c13..38563a0d62da 100644 --- a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java +++ b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -51,7 +51,7 @@ public class JavaFindUsagesHelper { private static final Logger LOG = Logger.getInstance("#com.intellij.find.findUsages.JavaFindUsagesHelper"); @NotNull - static Set getElementNames(@NotNull final PsiElement element) { + public static Set getElementNames(@NotNull final PsiElement element) { if (element instanceof PsiDirectory) { // normalize a directory to a corresponding package PsiPackage aPackage = ApplicationManager.getApplication().runReadAction(new Computable() { @Override From 91814d25cff4c5b97c6186ad726f5ce32e6d7721 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 27 Aug 2015 20:03:02 +0200 Subject: [PATCH 041/172] GroovyCompilerTest: use TestLoggerFactory.dumpLogToStdout --- .../groovy/compiler/GroovyCompilerTest.groovy | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index 15cac8b9e450..9786b3dd48ba 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -32,6 +32,7 @@ import com.intellij.openapi.compiler.CompilerMessage import com.intellij.openapi.compiler.CompilerMessageCategory import com.intellij.openapi.compiler.options.ExcludeEntryDescription import com.intellij.openapi.compiler.options.ExcludesConfiguration +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.module.Module import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.util.Key @@ -51,6 +52,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { @Override protected void setUp() { super.setUp(); + Logger.getInstance("#org.jetbrains.plugins.groovy.compiler.GroovyCompilerTest").info(testStartMessage) addGroovyLibrary(myModule); } @@ -225,6 +227,8 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { super.runBare() } + String getTestStartMessage() { "Starting " + getClass().name + " " + getName() } + @Override void runTest() { try { @@ -236,14 +240,10 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { } } - private static void printLogs() { - def ideaLog = new File(TestLoggerFactory.testLogDir, "idea.log") - if (ideaLog.exists()) { - println "\n\nIdea Log:" - def limit = 20000 - def logText = ideaLog.text - println(logText.size() < limit ? logText : logText.substring(logText.size() - limit)) - } + private void printLogs() { + println "Idea log" + TestLoggerFactory.dumpLogToStdout(getTestStartMessage()) + def makeLog = new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log") if (makeLog.exists()) { println "\n\nServer Log:" From 8c2870bb73b6a5930c82951f15d8453cca778652 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 28 Aug 2015 00:49:45 +0200 Subject: [PATCH 042/172] redefine swing copy action for JList to support standard IntelliJ renderers --- .../com/intellij/ui/components/JBList.java | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBList.java b/platform/platform-api/src/com/intellij/ui/components/JBList.java index 45e4a489e738..9f514d3c551f 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBList.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBList.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -17,6 +17,7 @@ package com.intellij.ui.components; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; @@ -27,7 +28,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.plaf.UIResource; +import javax.swing.text.JTextComponent; import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.util.ArrayList; import java.util.Collection; /** @@ -158,6 +164,7 @@ public class JBList extends JList implements ComponentWithEmptyText, ComponentWi private void init() { setSelectionBackground(UIUtil.getListSelectionBackground()); setSelectionForeground(UIUtil.getListSelectionForeground()); + installDefaultCopyAction(); myEmptyText = new StatusText(this) { @Override @@ -170,6 +177,51 @@ public class JBList extends JList implements ComponentWithEmptyText, ComponentWi setCellRenderer(new DefaultListCellRenderer()); } + private void installDefaultCopyAction() { + final Action copy = getActionMap().get("copy"); + if (copy == null || copy instanceof UIResource) { + Action newCopy = new AbstractAction() { + @Override + public boolean isEnabled() { + return getSelectedIndex() != -1; + } + + @Override + public void actionPerformed(ActionEvent e) { + ArrayList selected = new ArrayList(); + JBList list = JBList.this; + ListCellRenderer renderer = list.getCellRenderer(); + if (renderer != null) { + for (int index : getSelectedIndices()) { + Object value = list.getModel().getElementAt(index); + //noinspection unchecked + Component c = renderer.getListCellRendererComponent(list, value, index, true, true); + SimpleColoredComponent coloredComponent = null; + if (c instanceof JComponent) { + coloredComponent = UIUtil.findComponentOfType((JComponent)c, SimpleColoredComponent.class); + } + if (coloredComponent != null) { + selected.add(coloredComponent.toString()); + } + else if (c instanceof JTextComponent) { + selected.add(((JTextComponent)c).getText()); + } + else if (value != null) { + selected.add(value.toString()); + } + } + } + + if (selected.size() > 0) { + String text = StringUtil.join(selected, " "); + CopyPasteManager.getInstance().setContents(new StringSelection(text)); + } + } + }; + getActionMap().put("copy", newCopy); + } + } + public boolean isEmpty() { return getItemsCount() == 0; } From a013714db162e05e47d7f43bb9fa71375559ecad Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 27 Aug 2015 00:25:23 +0300 Subject: [PATCH 043/172] GPUB: fix missing error when pin & recoverWhile are present --- .../src/com/intellij/lang/parser/GeneratedParserUtilBase.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java index 8ca50f506af1..fdb6c56c9da5 100644 --- a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java +++ b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java @@ -535,6 +535,9 @@ public class GeneratedParserUtilBase { else if (eatMoreFlagOnce || (!result && frame.position != builder.rawTokenIndex()) || frame.errorReportedAt > initialPos) { errorReported = reportError(builder, state, frame, null, true, false); } + else if (!result && pinned && frame.errorReportedAt < 0) { + errorReported = reportError(builder, state, frame, elementType, false, false); + } if (extensionMarker != null) { extensionMarker.done(extensionTokenType); } From ce2c10c10f7750cc726ca480923e50a58c04392d Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 27 Aug 2015 20:49:00 +0300 Subject: [PATCH 044/172] Traverser: introduce psiTraverser(root), astTraverser(root) --- .../core-api/src/com/intellij/psi/SyntaxTraverser.java | 10 ++++++++++ .../util/containers/FilteredTraverserBase.java | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java b/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java index 785de7e4b5ad..cff07563ccaa 100644 --- a/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java +++ b/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java @@ -47,6 +47,11 @@ public class SyntaxTraverser extends FilteredTraverserBase(psiApi(), null); } + @NotNull + public static SyntaxTraverser psiTraverser(@Nullable PsiElement root) { + return psiTraverser().withRoot(root); + } + @NotNull public static SyntaxTraverser revPsiTraverser() { return new SyntaxTraverser(psiApiReversed(), null); @@ -57,6 +62,11 @@ public class SyntaxTraverser extends FilteredTraverserBase(astApi(), null); } + @NotNull + public static SyntaxTraverser astTraverser(@Nullable ASTNode root) { + return astTraverser().withRoot(root); + } + @NotNull public static SyntaxTraverser lightTraverser(@NotNull PsiBuilder builder) { LighterASTApi api = new LighterASTApi(builder); diff --git a/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java b/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java index 86c31037247c..6b721e211ecb 100644 --- a/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java +++ b/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java @@ -22,7 +22,6 @@ import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -108,8 +107,8 @@ public abstract class FilteredTraverserBase Date: Thu, 27 Aug 2015 22:56:27 +0300 Subject: [PATCH 045/172] ParamInfo: support non-flat structures --- .../lang/parameterInfo/ParameterInfoUtils.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/platform/lang-api/src/com/intellij/lang/parameterInfo/ParameterInfoUtils.java b/platform/lang-api/src/com/intellij/lang/parameterInfo/ParameterInfoUtils.java index 92b6e2f55c1e..f8ed8d2ad4ed 100644 --- a/platform/lang-api/src/com/intellij/lang/parameterInfo/ParameterInfoUtils.java +++ b/platform/lang-api/src/com/intellij/lang/parameterInfo/ParameterInfoUtils.java @@ -17,10 +17,12 @@ package com.intellij.lang.parameterInfo; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.SyntaxTraverser; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.text.CharArrayUtil; @@ -53,16 +55,21 @@ public class ParameterInfoUtils { } public static int getCurrentParameterIndex(ASTNode argList, int offset, IElementType delimiterType) { - int curOffset = argList.getTextRange().getStartOffset(); + SyntaxTraverser s = SyntaxTraverser.astTraverser(argList).expandAndSkip(Conditions.is(argList)); + return getCurrentParameterIndex(s, offset, delimiterType); + } + + public static int getCurrentParameterIndex(SyntaxTraverser s, int offset, IElementType delimiterType) { + V root = s.getRoot(); + int curOffset = s.api.rangeOf(root).getStartOffset(); if (offset < curOffset) return -1; - ASTNode[] children = argList.getChildren(null); int index = 0; - for (ASTNode child : children) { - curOffset += child.getTextLength(); + for (V child : s) { + curOffset += s.api.rangeOf(child).getLength(); if (offset < curOffset) break; - IElementType type = child.getElementType(); + IElementType type = s.api.typeOf(child); if (type == delimiterType) index++; } From 742901a4975d4ea752c96c72b6887be58bdad468 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 27 Aug 2015 23:20:16 +0300 Subject: [PATCH 046/172] GPUB: sync with GK 1.3.x --- .../lang/parser/GeneratedParserUtilBase.java | 111 ++++++++++++------ 1 file changed, 72 insertions(+), 39 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java index fdb6c56c9da5..097429178772 100644 --- a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java +++ b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java @@ -14,8 +14,6 @@ * limitations under the License. */ -// This class is a runtime engine for parsers generated by Grammar-Kit. -// Do not modify or refactor without complete investigation and/or review. package com.intellij.lang.parser; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; @@ -50,13 +48,21 @@ import java.util.Collection; import java.util.LinkedList; /** + * This class is a runtime engine for parsers generated by Grammar-Kit. + *
+ * Here is the original + * GeneratedParserUtilBase code. + *
+ *
+ * CAUTION: Authorized personnel only. Do not modify or refactor. + * * @author gregsh */ public class GeneratedParserUtilBase { private static final Logger LOG = Logger.getInstance("org.intellij.grammar.parser.GeneratedParserUtilBase"); - private static final int MAX_RECURSION_LEVEL = 1000; + private static final int MAX_RECURSION_LEVEL = StringUtil.parseInt(System.getProperty("grammar.kit.gpub.max.level"), 1000); private static final int MAX_VARIANTS_SIZE = 10000; private static final int MAX_VARIANTS_TO_DISPLAY = 50; @@ -116,7 +122,7 @@ public class GeneratedParserUtilBase { if (!goodMarker) return false; ErrorState state = ErrorState.get(builder); - return !state.frameStack.isEmpty(); + return state.currentFrame != null; } public static TokenSet create_token_set_(IElementType... tokenTypes) { @@ -396,6 +402,7 @@ public class GeneratedParserUtilBase { public static final int _LEFT_INNER_ = 0x4; public static final int _AND_ = 0x8; public static final int _NOT_ = 0x10; + public static final int _UPPER_ = 0x20; // simple enter/exit methods pair that doesn't require frame object public static PsiBuilder.Marker enter_section_(PsiBuilder builder) { @@ -406,20 +413,28 @@ public class GeneratedParserUtilBase { PsiBuilder.Marker marker, @Nullable IElementType elementType, boolean result) { - close_marker_impl_(ErrorState.get(builder).frameStack.peekLast(), marker, elementType, result); + close_marker_impl_(ErrorState.get(builder).currentFrame, marker, elementType, result); } // complex enter/exit methods pair with frame object - public static PsiBuilder.Marker enter_section_(PsiBuilder builder, int level, int modifiers, @Nullable String frameName) { + public static PsiBuilder.Marker enter_section_(PsiBuilder builder, int level, int modifiers, String frameName) { + return enter_section_(builder, level, modifiers, null, frameName); + } + + public static PsiBuilder.Marker enter_section_(PsiBuilder builder, int level, int modifiers) { + return enter_section_(builder, level, modifiers, null, null); + } + + public static PsiBuilder.Marker enter_section_(PsiBuilder builder, int level, int modifiers, IElementType elementType, String frameName) { PsiBuilder.Marker marker = builder.mark(); - enter_section_impl_(builder, level, modifiers, frameName); + enter_section_impl_(builder, level, modifiers, elementType, frameName); return marker; } - private static void enter_section_impl_(PsiBuilder builder, int level, int modifiers, @Nullable String frameName) { + private static void enter_section_impl_(PsiBuilder builder, int level, int modifiers, IElementType elementType, String frameName) { ErrorState state = ErrorState.get(builder); - Frame frame = state.FRAMES.alloc().init(builder, state, level, modifiers, frameName); - Frame prevFrame = state.frameStack.peekLast(); + Frame frame = state.FRAMES.alloc().init(builder, state, level, modifiers, elementType, frameName); + Frame prevFrame = state.currentFrame; if (prevFrame != null && prevFrame.errorReportedAt > frame.position) { // report error for previous unsuccessful frame reportError(builder, state, frame, null, true, false); @@ -430,7 +445,7 @@ public class GeneratedParserUtilBase { frame.leftMarker = left; } } - state.frameStack.add(frame); + state.currentFrame = frame; if ((modifiers & _AND_) != 0) { if (state.predicateCount == 0 && !state.predicateSign) { throw new AssertionError("Incorrect false predicate sign"); @@ -448,6 +463,15 @@ public class GeneratedParserUtilBase { } } + public static void exit_section_(PsiBuilder builder, + int level, + PsiBuilder.Marker marker, + boolean result, + boolean pinned, + @Nullable Parser eatMore) { + exit_section_(builder, level, marker, null, result, pinned, eatMore); + } + public static void exit_section_(PsiBuilder builder, int level, PsiBuilder.Marker marker, @@ -457,7 +481,9 @@ public class GeneratedParserUtilBase { @Nullable Parser eatMore) { ErrorState state = ErrorState.get(builder); - Frame frame = state.frameStack.pollLast(); + Frame frame = state.currentFrame; + state.currentFrame = frame == null ? null : frame.parentFrame; + if (frame != null && frame.elementType != null) elementType = frame.elementType; if (frame == null || level != frame.level) { LOG.error("Unbalanced error section: got " + frame + ", expected level " + level); if (frame != null) state.FRAMES.recycle(frame); @@ -469,11 +495,11 @@ public class GeneratedParserUtilBase { close_marker_impl_(frame, marker, null, false); state.predicateCount--; if ((frame.modifiers & _NOT_) != 0) state.predicateSign = !state.predicateSign; - state.FRAMES.recycle(frame); - return; } - close_frame_impl_(state, frame, builder, marker, elementType, result, pinned); - exit_section_impl_(state, frame, builder, elementType, result, pinned, eatMore); + else { + close_frame_impl_(state, frame, builder, marker, elementType, result, pinned); + exit_section_impl_(state, frame, builder, elementType, result, pinned, eatMore); + } state.FRAMES.recycle(frame); } @@ -560,7 +586,7 @@ public class GeneratedParserUtilBase { } } // propagate errorReportedAt up the stack to avoid duplicate reporting - Frame prevFrame = willFail && eatMore == null ? null : state.frameStack.peekLast(); + Frame prevFrame = willFail && eatMore == null ? null : state.currentFrame; if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt) { prevFrame.errorReportedAt = frame.errorReportedAt; } @@ -585,7 +611,11 @@ public class GeneratedParserUtilBase { } } if (result || pinned) { - if ((frame.modifiers & _LEFT_INNER_) != 0 && frame.leftMarker != null) { + if ((frame.modifiers & _UPPER_) != 0) { + marker.drop(); + frame.parentFrame.elementType = elementType; + } + else if ((frame.modifiers & _LEFT_INNER_) != 0 && frame.leftMarker != null) { marker.done(elementType); frame.leftMarker.precede().done(((LighterASTNode)frame.leftMarker).getTokenType()); frame.leftMarker.drop(); @@ -628,8 +658,8 @@ public class GeneratedParserUtilBase { else { if (frame != null) { int position = ((PsiBuilderImpl.ProductionMarker)marker).getStartIndex(); - if (frame.errorReportedAt > position) { - frame.errorReportedAt = frame.errorReportedAtPrev; + if (frame.errorReportedAt > position && frame.parentFrame != null) { + frame.errorReportedAt = frame.parentFrame.errorReportedAt; } } marker.rollbackTo(); @@ -642,7 +672,7 @@ public class GeneratedParserUtilBase { } public static void report_error_(PsiBuilder builder, ErrorState state, boolean advance) { - Frame frame = state.frameStack.isEmpty()? null : state.frameStack.getLast(); + Frame frame = state.currentFrame; if (frame == null) { LOG.error("unbalanced enter/exit section call: got null"); return; @@ -765,7 +795,7 @@ public class GeneratedParserUtilBase { int predicateCount; boolean predicateSign = true; boolean suppressErrors; - public final LinkedList frameStack = new LinkedList(); + public Frame currentFrame; public CompletionState completionState; private boolean caseSensitive; @@ -784,7 +814,7 @@ public class GeneratedParserUtilBase { } @Override - public void cleanup(@NotNull final Variant o) { + public void cleanup(@NotNull Variant o) { } }); final LimitedPool FRAMES = new LimitedPool(FRAMES_POOL_SIZE, new LimitedPool.ObjectFactory() { @@ -795,7 +825,7 @@ public class GeneratedParserUtilBase { } @Override - public void cleanup(@NotNull final Frame o) { + public void cleanup(@NotNull Frame o) { } }); @@ -865,23 +895,17 @@ public class GeneratedParserUtilBase { return count > 0; } - public int getVariantsSize() { - return variants.size(); + public void clearVariants(Frame frame) { + clearVariants(true, frame == null ? 0 : frame.variantCount); } - public void clearVariants(boolean expected, int start) { + void clearVariants(boolean expected, int start) { MyList list = expected? variants : unexpected; if (start < 0 || start >= list.size()) return; for (int i = start, len = list.size(); i < len; i ++) { VARIANTS.recycle(list.get(i)); } list.setSize(start); - if (expected) { - lastExpectedVariantPos = -1; - for (Variant variant : list) { - if (lastExpectedVariantPos < variant.position) lastExpectedVariantPos = variant.position; - } - } } public boolean typeExtends(IElementType child, IElementType parent) { @@ -896,6 +920,9 @@ public class GeneratedParserUtilBase { } public static class Frame { + public Frame parentFrame; + public IElementType elementType; + public int offset; public int position; public int level; @@ -903,13 +930,20 @@ public class GeneratedParserUtilBase { public String name; public int variantCount; public int errorReportedAt; - public int errorReportedAtPrev; public PsiBuilder.Marker leftMarker; public Frame() { } - public Frame init(PsiBuilder builder, ErrorState state, int level_, int modifiers_, String name_) { + public Frame init(PsiBuilder builder, + ErrorState state, + int level_, + int modifiers_, + IElementType elementType_, + String name_) { + parentFrame = state.currentFrame; + elementType = elementType_; + offset = builder.getCurrentOffset(); position = builder.rawTokenIndex(); level = level_; @@ -918,8 +952,6 @@ public class GeneratedParserUtilBase { variantCount = state.variants.size(); errorReportedAt = -1; - Frame prev = state.frameStack.peekLast(); - errorReportedAtPrev = prev == null? -1 : prev.errorReportedAt; leftMarker = null; return this; } @@ -931,8 +963,9 @@ public class GeneratedParserUtilBase { ((modifiers & _LEFT_) != 0? "_LEFT_, ": "") + ((modifiers & _LEFT_INNER_) != 0? "_LEFT_INNER_, ": "") + ((modifiers & _AND_) != 0? "_AND_, ": "") + - ((modifiers & _NOT_) != 0? "_NOT_, ": ""); - return String.format("{%s:%s:%d, %d, %s%s}", offset, position, level, errorReportedAt, mod, name); + ((modifiers & _NOT_) != 0? "_NOT_, ": "") + + ((modifiers & _UPPER_) != 0 ? "_UPPER_, " : ""); + return String.format("{%s:%s:%d, %d, %s%s, %s}", offset, position, level, errorReportedAt, mod, elementType, name); } } From 7cd7e104f67dc0eb4d2d7cb459e7e63df2f91a72 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Fri, 28 Aug 2015 08:22:19 +0300 Subject: [PATCH 047/172] Return null if alignment condition is not satisfied --- .../java/ArrayInitializerBlocksBuilder.java | 4 ++-- .../formatter/java/ChildrenBlocksBuilder.java | 24 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java index 44b605b55600..3a04e012728d 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/ArrayInitializerBlocksBuilder.java @@ -59,12 +59,12 @@ public class ArrayInitializerBlocksBuilder { .setDefaultAlignment(alignment) .setNoAlignment(JavaTokenType.COMMA) .setNoAlignment(JavaTokenType.LBRACE) - .setAlignmentIf(JavaTokenType.RBRACE, alignment, new Condition() { + .setNoAlignmentIf(JavaTokenType.RBRACE, new Condition() { @Override public boolean value(ASTNode node) { PsiElement prev = PsiTreeUtil.skipSiblingsBackward(node.getPsi(), PsiWhiteSpace.class); if (prev == null) return false; - return prev.getNode().getElementType() == JavaTokenType.COMMA; + return prev.getNode().getElementType() != JavaTokenType.COMMA; } }); diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java index 0697a0b8098a..c76cf439dba4 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/ChildrenBlocksBuilder.java @@ -64,7 +64,7 @@ public class ChildrenBlocksBuilder { private Map myIndents = ContainerUtil.newHashMap(); private Map myWraps = ContainerUtil.newHashMap(); - private Map> myApplyAlignCondition = ContainerUtil.newHashMap(); + private Map> myNoneAlignmentCondition = ContainerUtil.newHashMap(); private Alignment myDefaultAlignment; private Indent myDefaultIndent; @@ -99,9 +99,8 @@ public class ChildrenBlocksBuilder { return this; } - public Config setAlignmentIf(IElementType elementType, Alignment alignment, Condition applyAlignCondition) { - myAlignments.put(elementType, alignment); - myApplyAlignCondition.put(elementType, applyAlignCondition); + public Config setNoAlignmentIf(IElementType elementType, Condition applyAlignCondition) { + myNoneAlignmentCondition.put(elementType, applyAlignCondition); return this; } @@ -117,14 +116,17 @@ public class ChildrenBlocksBuilder { private Alignment getAlignment(ASTNode node) { IElementType elementType = node.getElementType(); - Alignment alignment = myAlignments.get(elementType); - if (alignment != null) { - Condition applyAlignCondition = myApplyAlignCondition.get(elementType); - if (applyAlignCondition == null || applyAlignCondition.value(node)) { - return alignment == NO_ALIGNMENT ? null : alignment; - } + + Condition noneAlignmentCondition = myNoneAlignmentCondition.get(elementType); + if (noneAlignmentCondition != null && noneAlignmentCondition.value(node)) { + return null; } - return myDefaultAlignment; + + Alignment alignment = myAlignments.get(elementType); + if (alignment == null) { + return myDefaultAlignment; + } + return alignment == NO_ALIGNMENT ? null : alignment; } private Wrap getWrap(IElementType elementType) { From 075cf5282f0088ae94db6749144c7ee7118930be Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 28 Aug 2015 11:20:05 +0300 Subject: [PATCH 048/172] suggest 'test' scope for JUnit4 library by default --- .../junit/JUnitDependencyScopeSuggester.java | 25 ++++++-- .../JUnitDependencyScopeSuggesterTest.java | 63 +++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 plugins/junit/test/com/intellij/execution/junit/JUnitDependencyScopeSuggesterTest.java diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitDependencyScopeSuggester.java b/plugins/junit/src/com/intellij/execution/junit/JUnitDependencyScopeSuggester.java index addb0b6fbc5e..f398e5183a42 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitDependencyScopeSuggester.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitDependencyScopeSuggester.java @@ -24,18 +24,35 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; + /** * @author nik */ public class JUnitDependencyScopeSuggester extends LibraryDependencyScopeSuggester { + private static final String[] JUNIT_JAR_MARKERS = { + "org.junit.Test", "junit.framework.TestCase", "org.hamcrest.Matcher", "org.hamcrest.Matchers" + }; + @Nullable @Override public DependencyScope getDefaultDependencyScope(@NotNull Library library) { VirtualFile[] files = library.getFiles(OrderRootType.CLASSES); - if (files.length == 1 && (LibraryUtil.isClassAvailableInLibrary(files, "junit.framework.TestCase") - || LibraryUtil.isClassAvailableInLibrary(library, "org.junit.Test"))) { - return DependencyScope.TEST; + if (files.length == 0) return null; + for (VirtualFile file : files) { + if (!isTestJarRoot(file)) { + return null; + } } - return null; + return DependencyScope.TEST; + } + + private static boolean isTestJarRoot(VirtualFile file) { + for (String marker : JUNIT_JAR_MARKERS) { + if (LibraryUtil.isClassAvailableInLibrary(Collections.singletonList(file), marker)) { + return true; + } + } + return false; } } diff --git a/plugins/junit/test/com/intellij/execution/junit/JUnitDependencyScopeSuggesterTest.java b/plugins/junit/test/com/intellij/execution/junit/JUnitDependencyScopeSuggesterTest.java new file mode 100644 index 000000000000..9bcd6938db7c --- /dev/null +++ b/plugins/junit/test/com/intellij/execution/junit/JUnitDependencyScopeSuggesterTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2015 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.junit; + +import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; +import com.intellij.openapi.roots.DependencyScope; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.OrderEntryUtil; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import com.intellij.util.ArrayUtil; + +/** + * @author nik + */ +public class JUnitDependencyScopeSuggesterTest extends JavaCodeInsightFixtureTestCase { + @Override + protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception { + moduleBuilder.addLibrary("junit3", JavaSdkUtil.getJunit3JarPath()); + moduleBuilder.addLibrary("junit4", ArrayUtil.toStringArray(JavaSdkUtil.getJUnit4JarPaths())); + moduleBuilder.addLibrary("ideaRt", JavaSdkUtil.getIdeaRtJarPath()); + moduleBuilder.addLibrary("empty"); + } + + public void testJunit3() throws Exception { + assertSame(DependencyScope.TEST, getScope("junit3")); + } + + public void testJunit4() throws Exception { + assertSame(DependencyScope.TEST, getScope("junit4")); + } + + public void testOrdinaryLibrary() throws Exception { + assertNull(getScope("ideaRt")); + } + + public void testEmptyLibrary() throws Exception { + assertNull(getScope("empty")); + } + + private DependencyScope getScope(String name) { + LibraryOrderEntry entry = OrderEntryUtil.findLibraryOrderEntry(ModuleRootManager.getInstance(myModule), name); + assertNotNull(entry); + Library library = entry.getLibrary(); + assertNotNull(library); + return new JUnitDependencyScopeSuggester().getDefaultDependencyScope(library); + } +} \ No newline at end of file From 42cef133ad12be2d441e267cf9c52e5a7401bcf3 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 28 Aug 2015 11:24:13 +0300 Subject: [PATCH 049/172] choose JVM for build process in predictable way if there are several JDK of same version in the project --- .../impl/src/com/intellij/compiler/server/BuildManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 72391c13b2b4..a38b85ca186c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -913,7 +913,7 @@ public class BuildManager implements Disposable { int sdkMinorVersion = 0; JavaSdkVersion sdkVersion = null; - final Set candidates = new HashSet(); + final Set candidates = new LinkedHashSet(); final Sdk defaultSdk = ProjectRootManager.getInstance(project).getProjectSdk(); if (defaultSdk != null && defaultSdk.getSdkType() instanceof JavaSdkType) { candidates.add(defaultSdk); From 2d263550820940c37a98b5503ce106d37b699687 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 28 Aug 2015 09:30:54 +0200 Subject: [PATCH 050/172] cleanup unused java completion filters --- .../completion/JavaKeywordCompletion.java | 2 +- .../psi/filters/ElementExtractorFilter.java | 8 +-- .../classes/ClassAssignableFilter.java | 59 ------------------- .../classes/EnumOrAnnotationTypeFilter.java | 43 -------------- .../psi/filters/classes/InterfaceFilter.java | 44 -------------- .../psi/filters/getters/FilterGetter.java | 53 ----------------- .../psi/filters/getters/ThisGetter.java | 8 +-- .../filters/position/BeforeElementFilter.java | 52 ---------------- .../filters/position/InsideElementFilter.java | 45 -------------- .../psi/filters/position/TokenTypeFilter.java | 4 +- .../filters/types/AssignableFromFilter.java | 2 - .../filters/types/AssignableGroupFilter.java | 5 -- 12 files changed, 4 insertions(+), 321 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/psi/filters/classes/ClassAssignableFilter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/classes/EnumOrAnnotationTypeFilter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/classes/InterfaceFilter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/getters/FilterGetter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/position/BeforeElementFilter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/position/InsideElementFilter.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java index 92f3271c4e94..4dae444c5d99 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java @@ -643,7 +643,7 @@ public class JavaKeywordCompletion { br = TailTypeDecorator.withTail(br, tailType); cont = TailTypeDecorator.withTail(cont, tailType); - if (loop != null && new InsideElementFilter(new ClassFilter(PsiStatement.class)).isAcceptable(position, loop)) { + if (loop != null && PsiTreeUtil.isAncestor(loop.getBody(), position, false)) { result.consume(br); result.consume(cont); } diff --git a/java/java-impl/src/com/intellij/psi/filters/ElementExtractorFilter.java b/java/java-impl/src/com/intellij/psi/filters/ElementExtractorFilter.java index 3e29bccb5394..2c930edaf3ba 100644 --- a/java/java-impl/src/com/intellij/psi/filters/ElementExtractorFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/ElementExtractorFilter.java @@ -26,18 +26,12 @@ import com.intellij.psi.infos.CandidateInfo; * To change this template use Options | File Templates. */ public class ElementExtractorFilter implements ElementFilter{ - ElementFilter myFilter; - - public ElementExtractorFilter(){} + private final ElementFilter myFilter; public ElementExtractorFilter(ElementFilter filter){ myFilter = filter; } - public void setFilter(ElementFilter filter){ - myFilter = filter; - } - public ElementFilter getFilter(){ return myFilter; } diff --git a/java/java-impl/src/com/intellij/psi/filters/classes/ClassAssignableFilter.java b/java/java-impl/src/com/intellij/psi/filters/classes/ClassAssignableFilter.java deleted file mode 100644 index 5034c48c0710..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/classes/ClassAssignableFilter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2000-2014 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.psi.filters.classes; - -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiManager; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.reference.SoftReference; -import com.intellij.util.ReflectionUtil; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 26.03.2003 - * Time: 21:01:47 - * To change this template use Options | File Templates. - */ -public abstract class ClassAssignableFilter implements ElementFilter{ - protected String myClassName = null; - protected PsiClass myClass = null; - private SoftReference myCachedClass = new SoftReference(null); - - @Override - public abstract boolean isAcceptable(Object aClass, PsiElement context); - public abstract String toString(); - - @Override - public boolean isClassAcceptable(Class hintClass){ - return ReflectionUtil.isAssignable(PsiClass.class, hintClass); - } - - protected PsiClass getPsiClass(PsiManager manager, GlobalSearchScope scope){ - if(myClass != null){ - return myClass; - } - - if(myCachedClass.get() == null && manager != null){ - myCachedClass = new SoftReference(JavaPsiFacade.getInstance(manager.getProject()).findClass(myClassName, scope)); - } - return (PsiClass) myCachedClass.get(); - } - -} diff --git a/java/java-impl/src/com/intellij/psi/filters/classes/EnumOrAnnotationTypeFilter.java b/java/java-impl/src/com/intellij/psi/filters/classes/EnumOrAnnotationTypeFilter.java deleted file mode 100644 index de48dfa83836..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/classes/EnumOrAnnotationTypeFilter.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2000-2014 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.psi.filters.classes; - -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.util.ReflectionUtil; -import org.jetbrains.annotations.NonNls; - -public class EnumOrAnnotationTypeFilter implements ElementFilter{ - - @Override - public boolean isClassAcceptable(Class hintClass){ - return ReflectionUtil.isAssignable(PsiClass.class, hintClass); - } - - @Override - public boolean isAcceptable(Object element, PsiElement context){ - if(element instanceof PsiClass){ - return ((PsiClass)element).isEnum() || ((PsiClass)element).isAnnotationType(); - } - return false; - } - - @NonNls - public String toString(){ - return "enum or annotation type"; - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/classes/InterfaceFilter.java b/java/java-impl/src/com/intellij/psi/filters/classes/InterfaceFilter.java deleted file mode 100644 index 702dced21a3a..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/classes/InterfaceFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2000-2014 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.psi.filters.classes; - -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.util.ReflectionUtil; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 28.01.2003 - * Time: 21:00:45 - * To change this template use Options | File Templates. - */ -public class InterfaceFilter implements ElementFilter{ - @Override - public boolean isClassAcceptable(Class hintClass){ - return ReflectionUtil.isAssignable(PsiClass.class, hintClass); - } - - @Override - public boolean isAcceptable(Object element, PsiElement context){ - return element instanceof PsiClass && ((PsiClass)element).isInterface(); - } - - public String toString(){ - return "interface"; - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/FilterGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/FilterGetter.java deleted file mode 100644 index adde94debdae..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/getters/FilterGetter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.filters.getters; - -import com.intellij.codeInsight.completion.CompletionContext; -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ContextGetter; -import com.intellij.psi.filters.ElementFilter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 15.04.2003 - * Time: 17:18:58 - * To change this template use Options | File Templates. - */ -public class FilterGetter implements ContextGetter{ - private final ContextGetter myBaseGetter; - private final ElementFilter myFilter; - - public FilterGetter(ContextGetter baseGetter, ElementFilter filter){ - myBaseGetter = baseGetter; - myFilter = filter; - } - - @Override - public Object[] get(PsiElement context, CompletionContext completionContext){ - final List results = new ArrayList(); - final Object[] elements = myBaseGetter.get(context, completionContext); - for (final Object element : elements) { - if (myFilter.isClassAcceptable(element.getClass()) && myFilter.isAcceptable(element, context)) { - results.add(element); - } - } - return results.toArray(); - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/ThisGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/ThisGetter.java index bf8c1766d1ec..6780e2adcb7c 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/ThisGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/ThisGetter.java @@ -15,9 +15,7 @@ */ package com.intellij.psi.filters.getters; -import com.intellij.codeInsight.completion.CompletionContext; import com.intellij.psi.*; -import com.intellij.psi.filters.ContextGetter; import com.intellij.util.IncorrectOperationException; import java.util.ArrayList; @@ -30,11 +28,7 @@ import java.util.List; * Time: 14:02:59 * To change this template use Options | File Templates. */ -public class ThisGetter implements ContextGetter{ - @Override - public Object[] get(PsiElement context, CompletionContext completionContext) { - return getThisExpressionVariants(context).toArray(); - } +public class ThisGetter { public static List getThisExpressionVariants(PsiElement context) { boolean first = true; diff --git a/java/java-impl/src/com/intellij/psi/filters/position/BeforeElementFilter.java b/java/java-impl/src/com/intellij/psi/filters/position/BeforeElementFilter.java deleted file mode 100644 index 5c10e2249808..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/position/BeforeElementFilter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.filters.position; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 03.02.2003 - * Time: 18:29:13 - * To change this template use Options | File Templates. - */ -public class BeforeElementFilter extends PositionElementFilter{ - public BeforeElementFilter(ElementFilter filter){ - setFilter(filter); - } - - public BeforeElementFilter(){} - @Override - public boolean isAcceptable(Object element, PsiElement scope){ - if (!(element instanceof PsiElement)) return false; - final PsiElement ownerChild = getOwnerChild(scope, (PsiElement) element); - if(ownerChild == null) return false; - PsiElement currentChild = ownerChild.getNextSibling(); - while(currentChild != null){ - if(getFilter().isAcceptable(currentChild, scope)){ - return true; - } - currentChild = currentChild.getNextSibling(); - } - return false; - } - - public String toString(){ - return "before(" + getFilter().toString() + ")"; - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/position/InsideElementFilter.java b/java/java-impl/src/com/intellij/psi/filters/position/InsideElementFilter.java deleted file mode 100644 index 74dde269e34c..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/position/InsideElementFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.filters.position; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 25.03.2003 - * Time: 12:11:40 - * To change this template use Options | File Templates. - */ -public class InsideElementFilter extends PositionElementFilter{ - public InsideElementFilter(ElementFilter filter){ - setFilter(filter); - } - - public InsideElementFilter(){} - - @Override - public boolean isAcceptable(Object element, PsiElement scope){ - if (!(element instanceof PsiElement)) return false; - PsiElement currentChild = getOwnerChild(scope, (PsiElement) element); - return getFilter().isAcceptable(currentChild, scope); - } - - public String toString(){ - return "in(" + getFilter().toString() + ")"; - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java b/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java index 58d878840248..9232f1a4c254 100644 --- a/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java @@ -31,9 +31,7 @@ import com.intellij.util.ReflectionUtil; * To change this template use Options | File Templates. */ public class TokenTypeFilter implements ElementFilter{ - private IElementType myType = null; - - public TokenTypeFilter(){} + private final IElementType myType; public TokenTypeFilter(IElementType type){ myType = type; diff --git a/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java b/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java index b2f7611ff673..e791c926fd58 100644 --- a/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java @@ -42,8 +42,6 @@ public class AssignableFromFilter implements ElementFilter{ myClassName = className; } - public AssignableFromFilter(){} - @Override public boolean isClassAcceptable(Class hintClass){ return true; diff --git a/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java b/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java index 56fa73fb599c..ffbef70e7c50 100644 --- a/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java @@ -31,11 +31,6 @@ import com.intellij.psi.filters.OrFilter; * To change this template use Options | File Templates. */ public class AssignableGroupFilter extends OrFilter implements InitializableFilter{ - public AssignableGroupFilter(){} - - public AssignableGroupFilter(PsiClass[] classes){ - init(classes); - } @Override public void init(Object[] classes){ From 6c89d908ae8171015e35bade01907748f5976fcc Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 28 Aug 2015 10:44:41 +0200 Subject: [PATCH 051/172] remove LookupItem usages from ExpressionLookupItem --- ...erenceExpressionCompletionContributor.java | 100 ++++-------------- .../lookup/ExpressionLookupItem.java | 69 ++++++++++-- .../impl/JavaElementLookupRenderer.java | 24 +---- .../SecondSmartTypeCompletionTest.java | 6 +- 4 files changed, 89 insertions(+), 110 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index da917f1116fc..515f2b16ec6f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -17,11 +17,8 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.ExpressionLookupItem; import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; @@ -34,7 +31,6 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.*; import com.intellij.psi.filters.element.ModifierFilter; import com.intellij.psi.filters.types.AssignableFromFilter; -import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -254,10 +250,7 @@ public class ReferenceExpressionCompletionContributor { final PsiExpression[] dimensions = newExpression.getArrayDimensions(); if (dimensions.length == 1 && "1".equals(dimensions[0].getText()) && newExpression.getArrayInitializer() == null) { final String text = variable.getName() + "[0]"; - final PsiExpression conversion = createExpression(text, element); - ExpressionLookupItem result = new ExpressionLookupItem(conversion); - result.setIcon(variable.getIcon(Iconable.ICON_FLAG_VISIBILITY)); - return result; + return new ExpressionLookupItem(createExpression(text, element), variable.getIcon(Iconable.ICON_FLAG_VISIBILITY), text, text); } } } @@ -311,29 +304,17 @@ public class ReferenceExpressionCompletionContributor { throws IncorrectOperationException { if (itemType instanceof PsiArrayType && expectedType.isAssignableFrom(((PsiArrayType)itemType).getComponentType())) { final PsiExpression conversion = createExpression(getQualifierText(qualifier) + prefix + "[0]", element); - final LookupItem item = new ExpressionLookupItem(conversion); - - @NonNls final String presentable = prefix + "[...]"; - item.setLookupString(prefix); - item.setPresentableText(presentable); - item.addLookupStrings(prefix); - item.setIcon(object.getIcon(Iconable.ICON_FLAG_VISIBILITY)); - item.setInsertHandler(new InsertHandler() { + result.consume(new ExpressionLookupItem(conversion, object.getIcon(Iconable.ICON_FLAG_VISIBILITY), prefix + "[...]", prefix) { @Override - public void handleInsert(InsertionContext context, LookupElement item) { + public void handleInsert(InsertionContext context) { FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.SECOND_SMART_COMPLETION_ARRAY_MEMBER); - final Editor editor = context.getEditor(); - final int startOffset = context.getStartOffset(); - final Document document = editor.getDocument(); - final int tailOffset = startOffset + item.getLookupString().length(); + final int tailOffset = context.getTailOffset(); final String callSpace = getSpace(CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_WITHIN_BRACKETS); - final String access = "[" + callSpace + callSpace + "]"; - document.insertString(tailOffset, access); - editor.getCaretModel().moveToOffset(tailOffset + 1 + callSpace.length()); + context.getDocument().insertString(tailOffset, "[" + callSpace + callSpace + "]"); + context.getEditor().getCaretModel().moveToOffset(tailOffset + 1 + callSpace.length()); } }); - result.consume(item); } } @@ -358,41 +339,23 @@ public class ReferenceExpressionCompletionContributor { final String qualifierText = getQualifierText(qualifier); final PsiExpression conversion = createExpression("java.util.Arrays." + methodName + "(" + qualifierText + prefix + ")", element); - final LookupItem item = new ExpressionLookupItem(conversion); - - @NonNls final String presentable = "Arrays." + methodName + "(" + qualifierText + prefix + ")"; - item.setLookupString(StringUtil.isEmpty(qualifierText) ? presentable : prefix); - item.setPresentableText(presentable); - item.addLookupStrings(prefix, presentable, methodName + "(" + prefix + ")"); - item.setIcon(PlatformIcons.METHOD_ICON); - item.setInsertHandler(new InsertHandler() { + final String presentable = "Arrays." + methodName + "(" + qualifierText + prefix + ")"; + String[] lookupStrings = {StringUtil.isEmpty(qualifierText) ? presentable : prefix, prefix, presentable, methodName + "(" + prefix + ")"}; + result.consume(new ExpressionLookupItem(conversion, PlatformIcons.METHOD_ICON, presentable, lookupStrings) { @Override - public void handleInsert(InsertionContext context, LookupElement item) { + public void handleInsert(InsertionContext context) { FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.SECOND_SMART_COMPLETION_ASLIST); - final Editor editor = context.getEditor(); - int startOffset = context.getStartOffset(); - final Document document = editor.getDocument(); - final int tailOffset = startOffset + item.getLookupString().length(); - startOffset -= qualifierText.length(); + int startOffset = context.getStartOffset() - qualifierText.length(); final Project project = element.getProject(); final String callSpace = getSpace(CodeStyleSettingsManager.getSettings(project).SPACE_WITHIN_METHOD_CALL_PARENTHESES); - @NonNls final String newText = "java.util.Arrays." + methodName + "(" + callSpace + qualifierText + prefix + callSpace + ")"; - document.replaceString(startOffset, tailOffset, newText); + final String newText = "java.util.Arrays." + methodName + "(" + callSpace + qualifierText + prefix + callSpace + ")"; + context.getDocument().replaceString(startOffset, context.getTailOffset(), newText); - PsiDocumentManager.getInstance(project).commitDocument(document); - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); - try { - JavaCodeStyleManager.getInstance(project) - .shortenClassReferences(file, startOffset, startOffset + CommonClassNames.JAVA_UTIL_ARRAYS.length()); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); + context.commitDocument(); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(context.getFile(), startOffset, startOffset + CommonClassNames.JAVA_UTIL_ARRAYS.length()); } }); - result.consume(item); } @Nullable @@ -585,33 +548,16 @@ public class ReferenceExpressionCompletionContributor { return; } - final LookupItem item = new ExpressionLookupItem(conversion); - item.setLookupString(prefix + ".toArray(" + getSpace(callSpace) + expressionString + getSpace(callSpace) + ")"); - item.setPresentableText(prefix + ".toArray(" + presentableString + ")"); - item.addLookupStrings(presentableString); - item.setIcon(PlatformIcons.METHOD_ICON); - item.setInsertHandler(new InsertHandler(){ - @Override - public void handleInsert(InsertionContext context, LookupItem item) { - FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.SECOND_SMART_COMPLETION_TOAR); + String[] lookupStrings = {prefix + ".toArray(" + getSpace(callSpace) + expressionString + getSpace(callSpace) + ")", presentableString}; + result.consume(new ExpressionLookupItem(conversion, PlatformIcons.METHOD_ICON, prefix + ".toArray(" + presentableString + ")", lookupStrings) { + @Override + public void handleInsert(InsertionContext context) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.SECOND_SMART_COMPLETION_TOAR); - final Editor editor = context.getEditor(); - final int startOffset = context.getStartOffset(); - final Document document = editor.getDocument(); - final int tailOffset = startOffset + item.getLookupString().length(); - final Project project = editor.getProject(); - context.commitDocument(); - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); - try { - JavaCodeStyleManager.getInstance(project).shortenClassReferences(file, startOffset, tailOffset); + context.commitDocument(); + JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(context.getFile(), context.getStartOffset(), context.getTailOffset()); } - catch (IncorrectOperationException e) { - LOG.error(e); - } - PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); - } - }); - result.consume(item); + }); } private static boolean isEmptyArrayInitializer(@Nullable PsiElement element) { diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/ExpressionLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/ExpressionLookupItem.java index 2482e9fb74d5..16ba1a83aba5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/ExpressionLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/ExpressionLookupItem.java @@ -17,38 +17,87 @@ package com.intellij.codeInsight.lookup; import com.intellij.psi.*; import com.intellij.util.PlatformIcons; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.Collections; +import java.util.Set; /** * @author peter */ -public class ExpressionLookupItem extends LookupItem implements TypedLookupItem { - public ExpressionLookupItem(final PsiExpression expression) { - super(expression, expression.getText()); +public class ExpressionLookupItem extends LookupElement implements TypedLookupItem { + private final PsiExpression myExpression; + private final Icon myIcon; + private final String myPresentableText; + private final String myLookupString; + private final Set myAllLookupStrings; + public ExpressionLookupItem(final PsiExpression expression) { + this(expression, getExpressionIcon(expression), expression.getText(), expression.getText()); + } + + public ExpressionLookupItem(final PsiExpression expression, @Nullable Icon icon, String presentableText, String... lookupStrings) { + myExpression = expression; + myPresentableText = presentableText; + myIcon = icon; + myLookupString = lookupStrings[0]; + myAllLookupStrings = Collections.unmodifiableSet(ContainerUtil.newHashSet(lookupStrings)); + } + + @Nullable + private static Icon getExpressionIcon(@NotNull PsiExpression expression) { if (expression instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; - final PsiElement element = referenceExpression.resolve(); + final PsiElement element = ((PsiReferenceExpression)expression).resolve(); if (element != null) { - setIcon(element.getIcon(0)); + return element.getIcon(0); } } if (expression instanceof PsiMethodCallExpression) { - setIcon(PlatformIcons.METHOD_ICON); + return PlatformIcons.METHOD_ICON; } + return null; + } + + @NotNull + @Override + public PsiExpression getObject() { + return myExpression; + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + presentation.setIcon(myIcon); + presentation.setItemText(myPresentableText); + PsiType type = getType(); + presentation.setTypeText(type == null ? null : type.getPresentableText()); } @Override public PsiType getType() { - return getObject().getType(); + return myExpression.getType(); } @Override public boolean equals(final Object o) { - return o instanceof ExpressionLookupItem && getLookupString().equals(((ExpressionLookupItem)o).getLookupString()); + return o instanceof ExpressionLookupItem && myLookupString.equals(((ExpressionLookupItem)o).myLookupString); } @Override public int hashCode() { - return getLookupString().hashCode(); + return myLookupString.hashCode(); + } + + @NotNull + @Override + public String getLookupString() { + return myLookupString; + } + + @Override + public Set getAllLookupStrings() { + return myAllLookupStrings; } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java b/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java index 3d7e0ffcefae..e608658057a1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/impl/JavaElementLookupRenderer.java @@ -33,7 +33,7 @@ import java.util.List; public class JavaElementLookupRenderer implements ElementLookupRenderer { @Override public boolean handlesItem(final Object element) { - return element instanceof PsiKeyword || element instanceof PsiExpression || + return element instanceof PsiKeyword || element instanceof PsiTypeElement || element instanceof BeanPropertyElement; } @@ -59,7 +59,7 @@ public class JavaElementLookupRenderer implements ElementLookupRenderer { if (o instanceof PsiElement) { final PsiElement element = (PsiElement)o; if (element.isValid()) { - if (element instanceof PsiKeyword || element instanceof PsiExpression || element instanceof PsiTypeElement) { + if (element instanceof PsiKeyword || element instanceof PsiTypeElement) { name = element.getText(); } else { name = PsiUtilCore.getName(element); @@ -72,24 +72,10 @@ public class JavaElementLookupRenderer implements ElementLookupRenderer { @Nullable private static String getTypeText(final Object o, final LookupItem item) { - String text = null; - if (o instanceof PsiElement) { - final PsiElement element = (PsiElement)o; - if (element.isValid()) { - if (element instanceof PsiExpression){ - PsiExpression expression = (PsiExpression)element; - PsiType type = expression.getType(); - if (type != null){ - text = type.getPresentableText(); - } - } - else if (element instanceof BeanPropertyElement) { - return getTypeText(item, ((BeanPropertyElement)element).getPropertyType()); - } - } + if (o instanceof BeanPropertyElement) { + return getTypeText(item, ((BeanPropertyElement)o).getPropertyType()); } - - return text; + return null; } @Nullable diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java index 5708b69d4bfb..8ee7fb6cb635 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java @@ -1,9 +1,7 @@ package com.intellij.codeInsight.completion; import com.intellij.JavaTestUtil; -import com.intellij.codeInsight.lookup.LookupElementDecorator; import com.intellij.codeInsight.lookup.LookupElementPresentation; -import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.ThrowableRunnable; @@ -115,8 +113,8 @@ public class SecondSmartTypeCompletionTest extends LightFixtureCompletionTestCas configure(); checkResultByFile(getTestName(false) + ".java"); assertStringItems("bar()", "foo()"); - assertEquals("Arrays.asList(f.bar())", ((LookupItem)((LookupElementDecorator)myItems[0]).getDelegate()).getPresentableText()); - assertEquals("Arrays.asList(f.foo())", ((LookupItem)((LookupElementDecorator)myItems[1]).getDelegate()).getPresentableText()); + assertEquals("Arrays.asList(f.bar())", LookupElementPresentation.renderElement(myItems[0]).getItemText()); + assertEquals("Arrays.asList(f.foo())", LookupElementPresentation.renderElement(myItems[1]).getItemText()); selectItem(myItems[1]); checkResult(); } From a397a000068051d4c4158c738b11c3efa2144edf Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 28 Aug 2015 11:01:17 +0200 Subject: [PATCH 052/172] deprecate LookupItem.fromString --- .../src/com/intellij/codeInsight/lookup/LookupItem.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java index d1dc8be21110..50a7de4f16cf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupItem.java @@ -76,6 +76,9 @@ public class LookupItem extends MutableLookupElement implements Comparable setLookupString(lookupString); } + /** + * @deprecated use {@link LookupElementBuilder} + */ public static LookupItem fromString(String s) { return new LookupItem(s, s); } From 3e62b1aee597694df204c23971c91c13924afa75 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Fri, 28 Aug 2015 12:22:30 +0300 Subject: [PATCH 053/172] Yet another updates and optimizations from PyDev.Debugger --- python/helpers/pydev/pydevd.py | 50 ++++++++++------------ python/helpers/pydev/pydevd_breakpoints.py | 8 ++-- python/helpers/pydev/pydevd_signature.py | 10 +---- python/helpers/pydev/pydevd_utils.py | 35 +++++++++++++-- 4 files changed, 59 insertions(+), 44 deletions(-) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index c149a45f197f..7dbb6d8cde9f 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -3,6 +3,7 @@ from __future__ import nested_scopes # Jython 2.1 support import pydev_monkey_qt from pydevd_utils import save_main_module +import pydevd_utils pydev_monkey_qt.patch_qt() @@ -28,7 +29,7 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \ CMD_STEP_OVER, \ CMD_STEP_RETURN, \ CMD_STEP_INTO_MY_CODE, \ - CMD_THREAD_KILL, \ + CMD_THREAD_KILL, \ CMD_THREAD_RUN, \ CMD_THREAD_SUSPEND, \ CMD_RUN_TO_LINE, \ @@ -51,7 +52,7 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \ InternalTerminateThread, \ InternalRunThread, \ InternalStepThread, \ - NetCommandFactory, \ + NetCommandFactory, \ PyDBDaemonThread, \ _queue, \ ReaderThread, \ @@ -63,15 +64,18 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \ StartServer, \ InternalSetNextStatementThread, \ ReloadCodeCommand, \ - CMD_SET_PY_EXCEPTION, \ + CMD_SET_PY_EXCEPTION, \ CMD_IGNORE_THROWN_EXCEPTION_AT,\ InternalGetBreakpointException, \ InternalSendCurrExceptionTrace,\ InternalSendCurrExceptionTraceProceeded,\ CMD_ENABLE_DONT_TRACE, \ CMD_GET_FILE_CONTENTS,\ - CMD_SET_PROPERTY_TRACE, CMD_RUN_CUSTOM_OPERATION,\ - InternalRunCustomOperation, CMD_EVALUATE_CONSOLE_EXPRESSION, InternalEvaluateConsoleExpression,\ + CMD_SET_PROPERTY_TRACE, \ + CMD_RUN_CUSTOM_OPERATION,\ + InternalRunCustomOperation, \ + CMD_EVALUATE_CONSOLE_EXPRESSION, \ + InternalEvaluateConsoleExpression,\ InternalConsoleGetCompletions from pydevd_file_utils import NormFileToServer, GetFilenameAndBase @@ -194,14 +198,14 @@ if hasattr(_temp, '_is_stopped'): # Python 3.4 has this return not t._is_stopped except: return t.isAlive() - + elif hasattr(_temp, '_Thread__stopped'): # Python 2.7 has this def isThreadAlive(t): try: return not t._Thread__stopped except: return t.isAlive() - + else: # Haven't checked all other versions, so, let's use the regular isAlive call in this case. def isThreadAlive(t): return t.isAlive() @@ -378,26 +382,16 @@ class PyDB: self.mpl_in_use = False self.mpl_hooks_in_debug_console = False self.mpl_modules_for_patching = {} + + self._filename_to_not_in_scope = {} def get_plugin_lazy_init(self): if self.plugin is None and SUPPORT_PLUGINS: self.plugin = PluginManager(self) return self.plugin - def get_project_roots(self): - if self.project_roots is None: - roots = os.getenv('IDE_PROJECT_ROOTS', '').split(os.pathsep) - pydev_log.debug("IDE_PROJECT_ROOTS %s\n" % roots) - self.project_roots = roots - def not_in_scope(self, filename): - self.get_project_roots() - filename = os.path.normcase(filename) - for root in self.project_roots: - root = os.path.normcase(root) - if filename.startswith(root): - return False - return True + return pydevd_utils.is_in_project_roots(filename) def first_appearance_in_scope(self, trace): if trace is None or self.not_in_scope(trace.tb_frame.f_code.co_filename): @@ -1217,10 +1211,10 @@ class PyDB: update_exception_hook(self) else: supported_type = False - + # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). - plugin = self.plugin + plugin = self.plugin if plugin is not None: supported_type = plugin.remove_exception_breakpoint(self, type, exception) @@ -2078,15 +2072,15 @@ def stoptrace(): from pydev_monkey import undo_patch_thread_modules undo_patch_thread_modules() - + debugger = GetGlobalDebugger() - + if debugger: - + debugger.SetTraceForFrameAndParents( GetFrame(), also_add_to_passed_frame=True, overwrite_prev_trace=True, dispatch_func=lambda *args:None) debugger.exiting() - + killAllPydevThreads() connected = False @@ -2118,7 +2112,7 @@ class DispatchReader(ReaderThread): dummy_thread = threading.currentThread() dummy_thread.is_pydev_daemon_thread = False return ReaderThread.OnRun(self) - + def handleExcept(self): ReaderThread.handleExcept(self) @@ -2182,7 +2176,7 @@ class SetupHolder: # main #======================================================================================================================= if __name__ == '__main__': - + # parse the command line. --file is our last argument that is required try: sys.original_argv = sys.argv[:] diff --git a/python/helpers/pydev/pydevd_breakpoints.py b/python/helpers/pydev/pydevd_breakpoints.py index fdd069abcd1e..c349ccd1a70b 100644 --- a/python/helpers/pydev/pydevd_breakpoints.py +++ b/python/helpers/pydev/pydevd_breakpoints.py @@ -96,19 +96,19 @@ def _excepthook(exctype, value, tb): frames = [] debugger = GetGlobalDebugger() - user_frames = [] + user_frame = None while tb: frame = tb.tb_frame if exception_breakpoint.ignore_libraries and not debugger.not_in_scope(frame.f_code.co_filename): - user_frames.append(tb.tb_frame) + user_frame = tb.tb_frame frames.append(tb.tb_frame) tb = tb.tb_next thread = threadingCurrentThread() frames_byid = dict([(id(frame),frame) for frame in frames]) - if exception_breakpoint.ignore_libraries: - frame = user_frames[-1] + if exception_breakpoint.ignore_libraries and user_frame is not None: + frame = user_frame else: frame = frames[-1] thread.additionalInfo.exception = (exctype, value, tb) diff --git a/python/helpers/pydev/pydevd_signature.py b/python/helpers/pydev/pydevd_signature.py index 5967ab31786e..a37901214f23 100644 --- a/python/helpers/pydev/pydevd_signature.py +++ b/python/helpers/pydev/pydevd_signature.py @@ -31,17 +31,9 @@ class Signature(object): class SignatureFactory(object): def __init__(self): self._caller_cache = {} - self.project_roots = os.getenv('IDE_PROJECT_ROOTS', '').split(os.pathsep) def is_in_scope(self, filename): - filename = os.path.normcase(filename) - for root in self.project_roots: - root = os.path.normcase(root) - if filename.startswith(root): - return True - return False - - + return pydevd_utils.is_in_project_roots(filename) def create_signature(self, frame): try: diff --git a/python/helpers/pydev/pydevd_utils.py b/python/helpers/pydev/pydevd_utils.py index 054dd69327d5..34fc24cf37b0 100644 --- a/python/helpers/pydev/pydevd_utils.py +++ b/python/helpers/pydev/pydevd_utils.py @@ -5,9 +5,10 @@ try: except: from urllib.parse import quote +import os import pydevd_constants import sys - +import pydev_log def save_main_module(file, module_name): # patch provided by: Scott Schlesier - when script is run, it does not @@ -113,7 +114,35 @@ def quote_smart(s, safe='/'): s = s.encode('utf-8') return quote(s, safe) - - + + +def _get_project_roots(project_roots_cache=[]): + # Note: the project_roots_cache is the same instance among the many calls to the method + if not project_roots_cache: + roots = os.getenv('IDE_PROJECT_ROOTS', '').split(os.pathsep) + pydev_log.debug("IDE_PROJECT_ROOTS %s\n" % roots) + new_roots = [] + for root in roots: + new_roots.append(os.path.normcase(root)) + project_roots_cache.append(new_roots) + return project_roots_cache[-1] # returns the project roots with case normalized + + +def is_in_project_roots(filename, filename_to_not_in_scope_cache={}): + # Note: the filename_to_not_in_scope_cache is the same instance among the many calls to the method + try: + return filename_to_not_in_scope_cache[filename] + except: + project_roots = _get_project_roots() + filename = os.path.normcase(filename) + for root in project_roots: + if filename.startswith(root): + filename_to_not_in_scope_cache[filename] = False + break + else: # for else (only called if the break wasn't reached). + filename_to_not_in_scope_cache[filename] = True + + # at this point it must be loaded. + return filename_to_not_in_scope_cache[filename] From 006f344580589a8ca65aa940b92f206b99bd85db Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 28 Aug 2015 12:30:03 +0300 Subject: [PATCH 054/172] WI-28597 Bundle OracleJDK 7 on Linux RUBY-17053 RM 8.0 does not start on Ubuntu 14.04 x64 --- bin/scripts/unix/idea.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/scripts/unix/idea.sh b/bin/scripts/unix/idea.sh index f20ed48714d5..cfbb5880e9fd 100755 --- a/bin/scripts/unix/idea.sh +++ b/bin/scripts/unix/idea.sh @@ -107,13 +107,18 @@ else fi fi -if [ -z "$JDK" ]; then +JAVA_BIN="$JDK/bin/java" +if [ ! -x "$JAVA_BIN" ]; then + JAVA_BIN="$JDK/jre/bin/java" +fi + +if [ -z "$JDK" ] || [ ! -x "$JAVA_BIN" ]; then message "No JDK found. Please validate either @@product_uc@@_JDK, JDK_HOME or JAVA_HOME environment variable points to valid JDK installation." exit 1 fi VERSION_LOG=`"$MKTEMP" -t java.version.log.XXXXXX` -"$JDK/jre/bin/java" -version 2> "$VERSION_LOG" +"$JAVA_BIN" -version 2> "$VERSION_LOG" "$GREP" "64-Bit|x86_64|amd64" "$VERSION_LOG" > /dev/null BITS=$? "$RM" -f "$VERSION_LOG" @@ -175,7 +180,7 @@ fi # --------------------------------------------------------------------- # Run the IDE. # --------------------------------------------------------------------- -LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JDK/jre/bin/java" \ +LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JAVA_BIN" \ $AGENT \ "-Xbootclasspath/a:$IDE_HOME/lib/boot.jar" \ -classpath "$CLASSPATH" \ From 6d63715e1dd70a0704c8605130ba892c59f63cd0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 27 Aug 2015 20:02:23 +0300 Subject: [PATCH 055/172] small cleanup refactoring to stream inspection --- .../PseudoLambdaReplaceTemplate.java | 23 ++--- ...PseudoFunctionalStyleMethodInspection.java | 85 ++++++++++--------- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java index cff890eb515c..ca1ee7d2474b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java @@ -22,7 +22,6 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.PsiDiamondTypeUtil; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.*; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -156,16 +155,17 @@ class PseudoLambdaReplaceTemplate { return null; } - final PsiMethod method = expression.resolveMethod(); - if (method == null) { + final JavaResolveResult result = expression.getMethodExpression().advancedResolve(false); + final PsiElement element = result.getElement(); + if (!(element instanceof PsiMethod)) { return null; } - final PsiParameter[] expectedParameters = method.getParameterList().getParameters(); + final PsiParameter[] expectedParameters = ((PsiMethod)element).getParameterList().getParameters(); if (argumentTypes.length != expectedParameters.length) { return null; } - final JavaResolveResult result = expression.getMethodExpression().advancedResolve(false); + final PsiSubstitutor methodSubstitutor = result.getSubstitutor(); return validate(argumentTypes, methodReturnType, methodSubstitutor, expression); } @@ -357,8 +357,7 @@ class PseudoLambdaReplaceTemplate { } @NotNull - public PsiExpression convertToStream(final PsiMethodCallExpression expression, PsiMethod method, boolean force) { - LOG.assertTrue(expression != null); + public PsiExpression convertToStream(@NotNull final PsiMethodCallExpression expression, @Nullable PsiMethod method, boolean force) { if (method == null) { method = expression.resolveMethod(); if (method == null) { @@ -556,15 +555,9 @@ class PseudoLambdaReplaceTemplate { private static boolean isIterableOrArray(final PsiType type) { if (type instanceof PsiClassType) { - final PsiClass resolvedClass = ((PsiClassType)type).resolve(); - if (resolvedClass != null) { - return InheritanceUtil.isInheritor(resolvedClass, CommonClassNames.JAVA_LANG_ITERABLE); - } + return InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_ITERABLE); } - else if (type instanceof PsiArrayType) { - return true; - } - return false; + return type instanceof PsiArrayType; } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/StaticPseudoFunctionalStyleMethodInspection.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/StaticPseudoFunctionalStyleMethodInspection.java index 398aabc0ff20..58959f11cc3d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/StaticPseudoFunctionalStyleMethodInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/StaticPseudoFunctionalStyleMethodInspection.java @@ -61,47 +61,46 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) { return PsiElementVisitor.EMPTY_VISITOR; } - return new PsiElementVisitor() { + return new JavaElementVisitor() { @Override - public void visitElement(PsiElement element) { - if (element instanceof PsiMethodCallExpression) { - final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element; - String qName = methodCallExpression.getMethodExpression().getQualifiedName(); - if (qName == null) { - return; - } - qName = StringUtil.getShortName(qName); - final Collection handlerInfos = myOptions.findElementsByMethodName(qName); - if (handlerInfos.isEmpty()) { - return; - } - final PsiMethod method = methodCallExpression.resolveMethod(); - if (method == null) { - return; - } - final PsiClass aClass = method.getContainingClass(); - if (aClass == null) { - return; - } - final String classQualifiedName = aClass.getQualifiedName(); - if (classQualifiedName == null) { - return; - } - StaticPseudoFunctionalStyleMethodOptions.PipelineElement suitableHandler = null; - for (StaticPseudoFunctionalStyleMethodOptions.PipelineElement h : handlerInfos) { - if (h.getHandlerClass().equals(classQualifiedName)) { - suitableHandler = h; - break; - } - } - if (suitableHandler == null) { - return; - } - final PseudoLambdaReplaceTemplate.ValidationInfo validationInfo = suitableHandler.getTemplate().validate(methodCallExpression); - if (validationInfo != null) { - holder.registerProblem(methodCallExpression.getMethodExpression(), "Pseudo functional style code", new ReplacePseudoLambdaWithLambda(suitableHandler)); + public void visitMethodCallExpression(PsiMethodCallExpression methodCallExpression) { + String qName = methodCallExpression.getMethodExpression().getQualifiedName(); + if (qName == null) { + return; + } + qName = StringUtil.getShortName(qName); + final Collection handlerInfos = myOptions.findElementsByMethodName(qName); + if (handlerInfos.isEmpty()) { + return; + } + final PsiMethod method = methodCallExpression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final String classQualifiedName = aClass.getQualifiedName(); + if (classQualifiedName == null) { + return; + } + StaticPseudoFunctionalStyleMethodOptions.PipelineElement suitableHandler = null; + for (StaticPseudoFunctionalStyleMethodOptions.PipelineElement h : handlerInfos) { + if (h.getHandlerClass().equals(classQualifiedName)) { + suitableHandler = h; + break; } } + if (suitableHandler == null) { + return; + } + final PseudoLambdaReplaceTemplate.ValidationInfo validationInfo = suitableHandler.getTemplate().validate(methodCallExpression); + if (validationInfo != null) { + holder.registerProblem(methodCallExpression.getMethodExpression(), + "Pseudo functional style code", + new ReplacePseudoLambdaWithLambda(suitableHandler)); + } } }; } @@ -128,9 +127,13 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class); - LOG.assertTrue(expression != null); - myHandler.getTemplate().convertToStream(expression, null, false); + PsiElement psiElement = descriptor.getPsiElement(); + if (psiElement instanceof PsiReferenceExpression) { + PsiElement parent = psiElement.getParent(); + if (parent instanceof PsiMethodCallExpression) { + myHandler.getTemplate().convertToStream((PsiMethodCallExpression)parent, null, false); + } + } } } } \ No newline at end of file From cc3875a3caf10d7c8d5e536b254174b98f939786 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 28 Aug 2015 12:27:34 +0300 Subject: [PATCH 056/172] skip lexer part if whitespace is not applicable --- .../inplace/InplaceVariableIntroducer.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index b9c702925fb7..d5a5aa91a649 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -79,20 +79,21 @@ public abstract class InplaceVariableIntroducer extends In ASTNode prev = node.getTreePrev(); final ASTNode astNode = LanguageTokenSeparatorGenerators.INSTANCE.forLanguage(expr.getLanguage()) .generateWhitespaceBetweenTokens(prev, node); - final Lexer lexer = LanguageParserDefinitions.INSTANCE.forLanguage(expr.getLanguage()).createLexer(project); - if (astNode != null && - LanguageUtil.canStickTokensTogetherByLexer(prev, prev, lexer) == ParserDefinition.SpaceRequirements.MUST) { - PostprocessReformattingAspect.getInstance(project).disablePostprocessFormattingInside(new Runnable() { - @Override - public void run() { - new WriteCommandAction(project, "Normalize declaration") { - @Override - protected void run(@NotNull Result result) throws Throwable { - node.getTreeParent().addChild(astNode, node); - } - }.execute(); - } - }); + if (astNode != null) { + final Lexer lexer = LanguageParserDefinitions.INSTANCE.forLanguage(expr.getLanguage()).createLexer(project); + if (LanguageUtil.canStickTokensTogetherByLexer(prev, prev, lexer) == ParserDefinition.SpaceRequirements.MUST) { + PostprocessReformattingAspect.getInstance(project).disablePostprocessFormattingInside(new Runnable() { + @Override + public void run() { + new WriteCommandAction(project, "Normalize declaration") { + @Override + protected void run(@NotNull Result result) throws Throwable { + node.getTreeParent().addChild(astNode, node); + } + }.execute(); + } + }); + } } myExpr = expr; } From d114906c57a95f7245b52e82ff4daac5f720e511 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 28 Aug 2015 13:40:59 +0300 Subject: [PATCH 057/172] IDEA-144224 Yellow 'Find in file' highlighting is not readable when the same line is on the breakpoint. --- .../openapi/editor/impl/IterationState.java | 12 ++----- .../editor/impl/view/IterationState.java | 9 ++--- .../src/DefaultColorSchemesManager.xml | 2 +- ...ighlighterCanSetDefaultForegroundColor.png | Bin 0 -> 139 bytes .../openapi/editor/EditorPaintingTest.java | 33 ++++++++++++++---- 5 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 platform/platform-tests/testData/editor/painting/upperHighlighterCanSetDefaultForegroundColor.png diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java index 2621877a6c9c..a56f62af36c6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -28,7 +28,6 @@ import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.util.Comparing; import com.intellij.util.ArrayUtilRt; import com.intellij.util.CommonProcessors; import com.intellij.util.containers.ContainerUtil; @@ -504,14 +503,14 @@ public final class IterationState { TextAttributes attrs = cachedAttributes.get(i); if (fore == null) { - fore = ifDiffers(attrs.getForegroundColor(), myDefaultForeground); + fore = attrs.getForegroundColor(); } if (back == null) { if (isInSelection && i == selectionAttributesIndex || !isInSelection && i >= selectionAttributesIndex) { selectionBackgroundIsPotentiallyVisible = true; } - back = ifDiffers(attrs.getBackgroundColor(), myDefaultBackground); + back = attrs.getBackgroundColor(); } if (fontType == Font.PLAIN) { @@ -541,11 +540,6 @@ public final class IterationState { } } - @Nullable - private static Color ifDiffers(final Color c1, final Color c2) { - return Comparing.equal(c1, c2) ? null : c1; - } - public boolean atEnd() { return myStartOffset >= myEnd; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java index 97dd5150dfb6..bc74c684fb90 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java @@ -550,11 +550,11 @@ public class IterationState { TextAttributes attrs = cachedAttributes.get(i); if (fore == null) { - fore = ifDiffers(attrs.getForegroundColor(), myDefaultForeground); + fore = attrs.getForegroundColor(); } if (back == null) { - back = ifDiffers(attrs.getBackgroundColor(), myDefaultBackground); + back = attrs.getBackgroundColor(); } if (fontType == Font.PLAIN) { @@ -582,11 +582,6 @@ public class IterationState { includeLineStart && myStartOffset == myCaretRowStart || includeLineEnd && myStartOffset == myCaretRowEnd; } - @Nullable - private static Color ifDiffers(final Color c1, final Color c2) { - return Comparing.equal(c1, c2) ? null : c1; - } - public boolean atEnd() { return myReverseIteration ? myStartOffset <= myEnd : myStartOffset >= myEnd; } diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml index 87b8e5184523..c22759c23e7d 100644 --- a/platform/platform-resources/src/DefaultColorSchemesManager.xml +++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml @@ -644,7 +644,7 @@