From 94c9e93e59740f699ca59968fa045e6ad86e3d64 Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Wed, 31 Jan 2018 18:22:07 +0300 Subject: [PATCH 01/23] Allow specifying git executable from PATH --- .../src/git4idea/config/CachingFileTester.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/config/CachingFileTester.java b/plugins/git4idea/src/git4idea/config/CachingFileTester.java index 6be696454fde..1eb6a3c9cb7e 100644 --- a/plugins/git4idea/src/git4idea/config/CachingFileTester.java +++ b/plugins/git4idea/src/git4idea/config/CachingFileTester.java @@ -3,10 +3,12 @@ */ package git4idea.config; +import com.intellij.execution.configurations.PathEnvironmentVariableUtil; import com.intellij.openapi.progress.ProcessCanceledException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.util.concurrent.ConcurrentHashMap; @@ -24,7 +26,7 @@ abstract class CachingFileTester { long currentLastModificationDate = 0L; try { - currentLastModificationDate = Files.getLastModifiedTime(Paths.get(filePath)).toMillis(); + currentLastModificationDate = Files.getLastModifiedTime(Paths.get(resolveAgainstEnvPath(filePath))).toMillis(); if (result == null || result.getFileLastModifiedTimestamp() != currentLastModificationDate) { result = new TestResult(testFile(filePath), currentLastModificationDate); } @@ -40,6 +42,17 @@ abstract class CachingFileTester { return result; } + @NotNull + private static String resolveAgainstEnvPath(@NotNull String filePath) { + if (!filePath.contains(File.separator)) { + File exeFile = PathEnvironmentVariableUtil.findInPath(filePath); + if (exeFile != null) { + return exeFile.getPath(); + } + } + return filePath; + } + @Nullable public TestResult getCachedResultForFile(@NotNull String filePath) { return myFileTestMap.get(filePath); From bd6e8e07da63682d29bacb87a2f8f32f9032421b Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 31 Jan 2018 18:28:44 +0300 Subject: [PATCH 02/23] better popup positioning (IDEA-185833, IDEA-185745) ensure that at least half of the content will fit on bottom, or show on top trim to screen width/height --- .../documentation/DocumentationComponent.java | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index cda6d3d46593..5d89399a4fe4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -26,6 +26,7 @@ import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsUtil; @@ -63,6 +64,7 @@ import com.intellij.ui.popup.PopupPositionManager; import com.intellij.util.Url; import com.intellij.util.Urls; import com.intellij.util.ui.GraphicsUtil; +import com.intellij.util.ui.JBDimension; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.accessibility.ScreenReader; @@ -102,6 +104,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr @NonNls private static final String DOCUMENTATION_TOPIC_ID = "reference.toolWindows.Documentation"; private static final int PREFERRED_HEIGHT_MAX_EM = 10; + private static final JBDimension MAX_DEFAULT = new JBDimension(650, 500); + private static final JBDimension MIN_DEFAULT = new JBDimension(300, 59); private final ExternalDocAction myExternalDocAction; private DocumentationManager myManager; @@ -781,8 +785,9 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private void showHint() { - LookupEx lookup = LookupManager.getActiveLookup(myManager.getEditor()); - int maxWidth = JBUI.scale(lookup != null ? 435 : 650); + Editor editor = myManager.getEditor(); + LookupEx lookup = LookupManager.getActiveLookup(editor); + int maxWidth = lookup != null ? JBUI.scale(435) : MAX_DEFAULT.width; boolean lookupActive = lookup != null && lookup.getCurrentItem() != null && lookup.getComponent().isShowing(); if (myHint != null && myHint.getDimensionServiceKey() == null) { Dimension preferredSize = myEditorPane.getPreferredSize(); @@ -791,14 +796,43 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr myResizing = true; int height = preferredSize.height + (needsToolbar() ? myControlPanel.getPreferredSize().height : 0); Dimension hintSize = new Dimension(Math.min(maxWidth, Math.max(JBUI.scale(300), width)), - Math.min(JBUI.scale(500), Math.max(JBUI.scale(59), height))); - if (lookupActive && myHint.getLocationOnScreen().x < lookup.getComponent().getLocationOnScreen().x) { - myHint.setLocation(new RelativePoint(lookup.getComponent(), new Point(-hintSize.width - 5, 0))); + Math.min(MAX_DEFAULT.height, Math.max(MIN_DEFAULT.height, height))); + Point location = myHint.getLocationOnScreen(); + if (lookupActive && location.x < lookup.getComponent().getLocationOnScreen().x) { + // pin upper right corner (instead of default upper left) + location = new RelativePoint(lookup.getComponent(), new Point(-hintSize.width - 5, 0)).getScreenPoint(); + myHint.setLocation(location); + } else if (editor != null && editor.getComponent().isShowing()) { + // pin lower bound (instead of default upper) + Point preferredLocation = JBPopupFactory.getInstance().guessBestPopupLocation(editor).getScreenPoint(); + preferredLocation.y -= editor.getLineHeight(); + if (location.y < preferredLocation.y) { + location = new Point(location.x, preferredLocation.y - hintSize.height); + myHint.setLocation(location); + } + } + if (myIsShown) { + Rectangle screen = ScreenUtil.getScreenRectangle(myEditorPane); + int xOverdraft = location.x + hintSize.width - screen.x - screen.width; + if (xOverdraft > 0) { + myHint.setLocation(new Point(location.x - xOverdraft, location.y)); + } + int yUnderDraft = screen.y - location.y; + if (yUnderDraft > 0) { + location.y += yUnderDraft; + hintSize.height -= yUnderDraft; + } + int yOverdraft = location.y + hintSize.height - screen.y - screen.height; + if (yOverdraft > 0) { + hintSize.height -= yOverdraft; + } } myHint.setSize(hintSize); } if (!myIsShown && myHint != null && !ApplicationManager.getApplication().isUnitTestMode()) { + Dimension hintSize = myHint.getSize(); + myResizing = true; Component focusOwner = IdeFocusManager.getInstance(myManager.myProject).getFocusOwner(); DataContext dataContext = DataManager.getInstance().getDataContext(focusOwner); @@ -808,8 +842,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr Rectangle screenRectangle = ScreenUtil.getScreenRectangle(lookupComponent); int lookupWidthAndGap = lookupComponent.getWidth() + 5; int x = lookupPosition.x + lookupWidthAndGap; - Dimension hintSize = myHint.getSize(); RelativePoint point; + // if documentation doesn't fit into screen, put it on the left hand side if (x + Math.max(hintSize.width, maxWidth) > screenRectangle.width) { point = new RelativePoint(lookupComponent, new Point(-hintSize.width - 5, 0)); } else { @@ -825,8 +859,21 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } } }); - } else { - PopupPositionManager.positionPopupInBestPosition(myHint, myManager.getEditor(), dataContext); + } else if (editor != null && editor.getComponent().isShowing()) { + // let's try to fit at least of half of maximum size on the bottom + Point preferredLocation = JBPopupFactory.getInstance().guessBestPopupLocation(editor).getScreenPoint(); + Rectangle preferred = new Rectangle(preferredLocation.x, preferredLocation.y, MAX_DEFAULT.width, MAX_DEFAULT.height / 2); + Rectangle adjusted = (Rectangle)preferred.clone(); + ScreenUtil.fitToScreen(adjusted); + // if we fail, show documentation on top + if (preferred.y != adjusted.y) { + preferredLocation.y -= editor.getLineHeight() + hintSize.height; + } + + myHint.show(new RelativePoint(preferredLocation)); + } + else { + PopupPositionManager.positionPopupInBestPosition(myHint, editor, dataContext); } myIsShown = true; if (myHint.getDimensionServiceKey() == null) { From b3d6ca427cfd1d3ba2a3d15365072427ee51df93 Mon Sep 17 00:00:00 2001 From: Ivan Semenov Date: Wed, 31 Jan 2018 19:15:37 +0300 Subject: [PATCH 03/23] Do not direct line endings git warning to output --- plugins/git4idea/src/git4idea/commands/GitImplBase.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/git4idea/src/git4idea/commands/GitImplBase.java b/plugins/git4idea/src/git4idea/commands/GitImplBase.java index 0a26892a89bf..69d2e081c61d 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImplBase.java +++ b/plugins/git4idea/src/git4idea/commands/GitImplBase.java @@ -277,6 +277,7 @@ abstract class GitImplBase implements Git { "cannot rebase:", "conflict", "unable", + "The file will have its original", "runnerw:" }; From 228cf697168c95d837e38fce2e5586934e16c158 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 31 Jan 2018 16:27:07 +0100 Subject: [PATCH 04/23] MinusculeMatcher: extract a couple of methods --- .../psi/codeStyle/MinusculeMatcher.java | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java index 3c9331df14a1..cdf615e2a801 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java +++ b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java @@ -315,30 +315,13 @@ public class MinusculeMatcher implements Matcher { int nameIndex, boolean allowSpecialChars, boolean isAsciiName) { - boolean star = isPatternChar(patternIndex - 1, '*'); - final char p = myPattern[patternIndex]; + boolean wordStartsOnly = !isPatternChar(patternIndex - 1, '*') && !isWordSeparator[patternIndex]; while (true) { - int nextOccurrence = star || isWordSeparator[patternIndex] ? - indexOfIgnoreCase(name, nameIndex + 1, p, patternIndex, isAsciiName) : - indexOfWordStart(name, patternIndex, nameIndex); + int nextOccurrence = findNextPatternCharOccurrence(name, nameIndex, patternIndex, isAsciiName, allowSpecialChars, wordStartsOnly); if (nextOccurrence < 0) { return null; } - // pattern humps are allowed to match in words separated by " ()", lowercase characters aren't - if (!allowSpecialChars && !myHasSeparators && !myHasHumps && StringUtil.containsAnyChar(name, myHardSeparators, nameIndex, nextOccurrence)) { - return null; - } - // if the user has typed a dot, don't skip other dots between humps - // but one pattern dot may match several name dots - if (!allowSpecialChars && myHasDots && !isPatternChar(patternIndex - 1, '.') && StringUtil.contains(name, nameIndex, nextOccurrence, '.')) { - return null; - } - // uppercase should match either uppercase or a word start - if (!isUpperCase[patternIndex] || - Character.isUpperCase(name.charAt(nextOccurrence)) || - NameUtil.isWordStart(name, nextOccurrence) || - // accept uppercase matching lowercase if the whole prefix is uppercase and case sensitivity allows that - !myHasHumps && myOptions != NameUtil.MatchingCaseSensitivity.ALL) { + if (seemsLikeFragmentStart(name, patternIndex, nextOccurrence)) { FList ranges = matchFragment(name, patternIndex, nextOccurrence, isAsciiName); if (ranges != null) { return ranges; @@ -348,6 +331,37 @@ public class MinusculeMatcher implements Matcher { } } + private int findNextPatternCharOccurrence(@NotNull String name, + int startAt, + int patternIndex, + boolean isAsciiName, + boolean allowSpecialChars, boolean wordStartsOnly) { + int next = wordStartsOnly + ? indexOfWordStart(name, patternIndex, startAt) + : indexOfIgnoreCase(name, startAt + 1, myPattern[patternIndex], patternIndex, isAsciiName); + + // pattern humps are allowed to match in words separated by " ()", lowercase characters aren't + if (!allowSpecialChars && !myHasSeparators && !myHasHumps && StringUtil.containsAnyChar(name, myHardSeparators, startAt, next)) { + return -1; + } + // if the user has typed a dot, don't skip other dots between humps + // but one pattern dot may match several name dots + if (!allowSpecialChars && myHasDots && !isPatternChar(patternIndex - 1, '.') && StringUtil.contains(name, startAt, next, '.')) { + return -1; + } + + return next; + } + + private boolean seemsLikeFragmentStart(@NotNull String name, int patternIndex, int nextOccurrence) { + // uppercase should match either uppercase or a word start + return !isUpperCase[patternIndex] || + Character.isUpperCase(name.charAt(nextOccurrence)) || + NameUtil.isWordStart(name, nextOccurrence) || + // accept uppercase matching lowercase if the whole prefix is uppercase and case sensitivity allows that + !myHasHumps && myOptions != NameUtil.MatchingCaseSensitivity.ALL; + } + private boolean charEquals(char patternChar, int patternIndex, char c, boolean isIgnoreCase) { return patternChar == c || isIgnoreCase && (toLowerCase[patternIndex] == c || toUpperCase[patternIndex] == c); From 0dce4d44e7ab32165392ae911098d9707eb8f6ae Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 31 Jan 2018 17:28:03 +0100 Subject: [PATCH 05/23] java mad tests: skip completion in some injections --- .../java/propertyBased/JavaCompletionPolicy.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java index 3208edec05e6..b55c92f64c52 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaCompletionPolicy.java @@ -16,6 +16,7 @@ package com.intellij.java.propertyBased; import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Editor; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; import com.intellij.psi.util.PsiTreeUtil; @@ -23,6 +24,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.testFramework.propertyBased.CompletionPolicy; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -30,6 +32,18 @@ import java.util.Arrays; * @author peter */ class JavaCompletionPolicy extends CompletionPolicy { + @Nullable + @Override + protected String getExpectedVariant(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement leaf, @Nullable PsiReference ref) { + if (isBuggyInjection(file)) return null; + + return super.getExpectedVariant(editor, file, leaf, ref); + } + + // a language where there are bugs in completion which maintainers of this Java-specific tests can't or don't want to fix + private static boolean isBuggyInjection(@NotNull PsiFile file) { + return Arrays.asList("XML", "HTML").contains(file.getLanguage().getID()); + } @Override protected boolean isAfterError(@NotNull PsiFile file, @NotNull PsiElement leaf) { From ad7f857d43d8fef73f2ec406c2212ad86a9574d5 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 31 Jan 2018 18:37:54 +0300 Subject: [PATCH 06/23] git: use Hash instead of plain String * produce meaningful error message if stdout was polluted with a record from stderr --- .../src/git4idea/index/GitIndexUtil.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/plugins/git4idea/src/git4idea/index/GitIndexUtil.java b/plugins/git4idea/src/git4idea/index/GitIndexUtil.java index bd37418c8ebc..6e6c2ab7c515 100644 --- a/plugins/git4idea/src/git4idea/index/GitIndexUtil.java +++ b/plugins/git4idea/src/git4idea/index/GitIndexUtil.java @@ -23,6 +23,8 @@ import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; +import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.impl.HashImpl; import com.intellij.vcsUtil.VcsFileUtil; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitUtil; @@ -95,27 +97,27 @@ public class GitIndexUtil { } @NotNull - public static String write(@NotNull GitRepository repository, - @NotNull FilePath filePath, - @NotNull byte[] bytes, - boolean executable) throws VcsException { + public static Hash write(@NotNull GitRepository repository, + @NotNull FilePath filePath, + @NotNull byte[] bytes, + boolean executable) throws VcsException { return write(repository, filePath, new ByteArrayInputStream(bytes), executable); } @NotNull - public static String write(@NotNull GitRepository repository, - @NotNull FilePath filePath, - @NotNull InputStream content, - boolean executable) throws VcsException { - String hash = hashObject(repository, filePath, content); + public static Hash write(@NotNull GitRepository repository, + @NotNull FilePath filePath, + @NotNull InputStream content, + boolean executable) throws VcsException { + Hash hash = hashObject(repository, filePath, content); updateIndex(repository, filePath, hash, executable); return hash; } @NotNull - private static String hashObject(@NotNull GitRepository repository, - @NotNull FilePath filePath, - @NotNull InputStream content) throws VcsException { + private static Hash hashObject(@NotNull GitRepository repository, + @NotNull FilePath filePath, + @NotNull InputStream content) throws VcsException { GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.HASH_OBJECT); h.setSilent(true); h.addParameters("-w", "--stdin"); @@ -135,19 +137,19 @@ public class GitIndexUtil { notNull(GitVcs.getInstance(repository.getProject())).showErrors(h.errors(), "Applying index modifications"); throw h.errors().get(0); } - return output.trim(); + return HashImpl.build(output.trim()); } private static void updateIndex(@NotNull GitRepository repository, @NotNull FilePath filePath, - @NotNull String blobHash, + @NotNull Hash blobHash, boolean isExecutable) throws VcsException { String mode = isExecutable ? EXECUTABLE_MODE : DEFAULT_MODE; String path = VcsFileUtil.relativePath(repository.getRoot(), filePath); GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.UPDATE_INDEX); h.setSilent(true); - h.addParameters("--cacheinfo", mode + "," + blobHash + "," + path); + h.addParameters("--cacheinfo", mode + "," + blobHash.asString() + "," + path); h.endOptions(); Git.getInstance().runCommandWithoutCollectingOutput(h).getOutputOrThrow(); } From 67c6bac477b1878c6f14796df483a9c52e6b16be Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Wed, 31 Jan 2018 19:51:32 +0300 Subject: [PATCH 07/23] javadoc for id property --- .../intellij/openapi/options/SearchableConfigurable.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java b/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java index 821643ca705a..1a2e194226dd 100644 --- a/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java +++ b/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java @@ -31,6 +31,12 @@ import javax.swing.*; * @see SearchableOptionContributor */ public interface SearchableConfigurable extends Configurable { + + /** + * Unique configurable id. + * Note this id should be THE SAME as the one specified in XML. + * @see ConfigurableEP#id + */ @NotNull @NonNls String getId(); From b6d0a58e2872566aae4776bc73e745ef397daf94 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Wed, 31 Jan 2018 19:54:22 +0300 Subject: [PATCH 08/23] IDEA-185567 Server types not searchable in Settings --- .../tasks/tasks-core/src/META-INF/plugin.xml | 1 + .../config/TaskRepositoriesConfigurable.java | 19 ++++++++++++++++++- .../TaskSearchableOptionContributor.java | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskSearchableOptionContributor.java diff --git a/plugins/tasks/tasks-core/src/META-INF/plugin.xml b/plugins/tasks/tasks-core/src/META-INF/plugin.xml index d98076e1c6aa..8bce7dacb317 100644 --- a/plugins/tasks/tasks-core/src/META-INF/plugin.xml +++ b/plugins/tasks/tasks-core/src/META-INF/plugin.xml @@ -112,6 +112,7 @@ + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java index e9ec6be7b39b..7a0e829b068e 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java @@ -8,6 +8,7 @@ import com.intellij.openapi.actionSystem.Separator; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.actions.IconWithTextAction; @@ -40,9 +41,11 @@ import java.util.List; * @author Dmitry Avdeev */ @SuppressWarnings("unchecked") -public class TaskRepositoriesConfigurable extends BaseConfigurable implements Configurable.NoScroll { +public class TaskRepositoriesConfigurable extends BaseConfigurable implements Configurable.NoScroll, SearchableConfigurable { + public static final String ID = "tasks.servers"; private static final String EMPTY_PANEL = "empty.panel"; + private JPanel myPanel; private JPanel myServersPanel; private final JBList myRepositoriesList; @@ -257,6 +260,20 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co } } + @NotNull + @Override + public String getId() { + return ID; + } + + @Nullable + @Override + public Runnable enableSearch(String option) { + TaskRepository matched = + myRepositories.stream().filter(repository -> repository.getRepositoryType().getName().contains(option)).findFirst().orElse(null); + return matched == null ? null : () -> myRepositoriesList.setSelectedValue(matched, true); + } + private abstract class AddServerAction extends IconWithTextAction implements DumbAware { public AddServerAction(TaskRepositorySubtype subtype) { diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskSearchableOptionContributor.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskSearchableOptionContributor.java new file mode 100644 index 000000000000..ce4e8d216852 --- /dev/null +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskSearchableOptionContributor.java @@ -0,0 +1,17 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.tasks.config; + +import com.intellij.ide.ui.search.SearchableOptionContributor; +import com.intellij.ide.ui.search.SearchableOptionProcessor; +import com.intellij.tasks.TaskRepositoryType; +import org.jetbrains.annotations.NotNull; + +public class TaskSearchableOptionContributor extends SearchableOptionContributor { + @Override + public void processOptions(@NotNull SearchableOptionProcessor processor) { + TaskRepositoryType[] types = TaskRepositoryType.getRepositoryTypes(); + for (TaskRepositoryType type : types) { + processor.addOptions(type.getName(), null, null, TaskRepositoriesConfigurable.ID, null, true); + } + } +} From c978a2f0539e3f3c8ebeb553cbb1e842842de463 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Wed, 31 Jan 2018 16:32:42 +0300 Subject: [PATCH 09/23] capture agent: suppress code warnings --- .../src/com/intellij/rt/debugger/agent/CaptureStorage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/debugger/debugger-agent-storage/src/com/intellij/rt/debugger/agent/CaptureStorage.java b/java/debugger/debugger-agent-storage/src/com/intellij/rt/debugger/agent/CaptureStorage.java index 631fd3bab284..343d35985ae8 100644 --- a/java/debugger/debugger-agent-storage/src/com/intellij/rt/debugger/agent/CaptureStorage.java +++ b/java/debugger/debugger-agent-storage/src/com/intellij/rt/debugger/agent/CaptureStorage.java @@ -57,6 +57,7 @@ public class CaptureStorage { return; } try { + //noinspection SuspiciousMethodCalls CapturedStack stack = STORAGE.get(new HardKey(key)); Deque currentStacks = CURRENT_STACKS.get(); if (stack != null) { @@ -131,6 +132,7 @@ public class CaptureStorage { private final CapturedStack myValue; public WeakKey(Object key, CapturedStack value, ReferenceQueue q) { + //noinspection unchecked super(key, q); myHash = System.identityHashCode(key); myValue = value; @@ -247,6 +249,7 @@ public class CaptureStorage { // to be run from the debugger @SuppressWarnings("unused") public static Object[][] getRelatedStack(Object key, int limit) { + //noinspection SuspiciousMethodCalls CapturedStack stack = STORAGE.get(new HardKey(key)); if (stack == null) { return null; From adc4d91f33d13281a462628dd27dbaf70c6fb9fa Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Wed, 31 Jan 2018 20:17:12 +0300 Subject: [PATCH 10/23] IDEA-185970 Non-java evaluation tooltips do not work --- .../com/intellij/debugger/engine/JavaDebuggerEvaluator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java index 7d1018f3f039..a359d1cd8667 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java @@ -18,6 +18,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiFile; import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.XSourcePosition; @@ -151,7 +152,8 @@ public class JavaDebuggerEvaluator extends XDebuggerEvaluator implements XDebugg } Pair pair = findExpression(elementAtCursor, sideEffectsAllowed); if (pair != null) { - return new ExpressionInfo(pair.getSecond(), null, null, pair.getFirst()); + PsiElement element = pair.getFirst(); + return new ExpressionInfo(pair.getSecond(), null, null, element instanceof PsiExpression ? element : null); } } catch (IndexNotReadyException ignored) {} return null; From d43b75dd69663ec733fcc660ca9c0c5a03a77523 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 31 Jan 2018 20:33:58 +0300 Subject: [PATCH 11/23] use user-set size for positioning (IDEA-185945) --- .../documentation/DocumentationComponent.java | 114 +++++++++--------- 1 file changed, 60 insertions(+), 54 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index 5d89399a4fe4..0d97f7bc34b5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -41,6 +41,7 @@ import com.intellij.openapi.options.FontSize; import com.intellij.openapi.roots.*; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.DimensionService; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.InvalidDataException; @@ -789,14 +790,21 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr LookupEx lookup = LookupManager.getActiveLookup(editor); int maxWidth = lookup != null ? JBUI.scale(435) : MAX_DEFAULT.width; boolean lookupActive = lookup != null && lookup.getCurrentItem() != null && lookup.getComponent().isShowing(); - if (myHint != null && myHint.getDimensionServiceKey() == null) { - Dimension preferredSize = myEditorPane.getPreferredSize(); - int width = definitionPreferredWidth(); - width = width < 0 ? preferredSize.width : width; - myResizing = true; - int height = preferredSize.height + (needsToolbar() ? myControlPanel.getPreferredSize().height : 0); - Dimension hintSize = new Dimension(Math.min(maxWidth, Math.max(JBUI.scale(300), width)), - Math.min(MAX_DEFAULT.height, Math.max(MIN_DEFAULT.height, height))); + if (myHint != null) { + Dimension hintSize; + if (myHint.getDimensionServiceKey() == null) { + Dimension preferredSize = myEditorPane.getPreferredSize(); + int width = definitionPreferredWidth(); + width = width < 0 ? preferredSize.width : width; + myResizing = true; + int height = preferredSize.height + (needsToolbar() ? myControlPanel.getPreferredSize().height : 0); + hintSize = new Dimension(Math.min(maxWidth, Math.max(JBUI.scale(300), width)), + Math.min(MAX_DEFAULT.height, Math.max(MIN_DEFAULT.height, height))); + } else { + hintSize = DimensionService.getInstance().getSize(DocumentationManager.NEW_JAVADOC_LOCATION_AND_SIZE, myManager.myProject); + hintSize = hintSize != null ? hintSize : MIN_DEFAULT; + } + Point location = myHint.getLocationOnScreen(); if (lookupActive && location.x < lookup.getComponent().getLocationOnScreen().x) { // pin upper right corner (instead of default upper left) @@ -828,56 +836,54 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } } myHint.setSize(hintSize); - } - if (!myIsShown && myHint != null && !ApplicationManager.getApplication().isUnitTestMode()) { - Dimension hintSize = myHint.getSize(); - - myResizing = true; - Component focusOwner = IdeFocusManager.getInstance(myManager.myProject).getFocusOwner(); - DataContext dataContext = DataManager.getInstance().getDataContext(focusOwner); - if (lookupActive) { - Component lookupComponent = lookup.getComponent(); - Point lookupPosition = lookupComponent.getLocationOnScreen(); - Rectangle screenRectangle = ScreenUtil.getScreenRectangle(lookupComponent); - int lookupWidthAndGap = lookupComponent.getWidth() + 5; - int x = lookupPosition.x + lookupWidthAndGap; - RelativePoint point; - // if documentation doesn't fit into screen, put it on the left hand side - if (x + Math.max(hintSize.width, maxWidth) > screenRectangle.width) { - point = new RelativePoint(lookupComponent, new Point(-hintSize.width - 5, 0)); - } else { - point = new RelativePoint(lookupComponent, new Point(lookupWidthAndGap, 0)); - } - myHint.show(point); - lookup.addLookupListener(new LookupAdapter() { - @Override - public void lookupCanceled(LookupEvent event) { - final AbstractPopup hint = myHint; - if (hint != null && hint.canClose() && hint.isVisible()) { - hint.cancel(); + if (!myIsShown && !ApplicationManager.getApplication().isUnitTestMode()) { + myResizing = true; + Component focusOwner = IdeFocusManager.getInstance(myManager.myProject).getFocusOwner(); + DataContext dataContext = DataManager.getInstance().getDataContext(focusOwner); + if (lookupActive) { + Component lookupComponent = lookup.getComponent(); + Point lookupPosition = lookupComponent.getLocationOnScreen(); + Rectangle screenRectangle = ScreenUtil.getScreenRectangle(lookupComponent); + int lookupWidthAndGap = lookupComponent.getWidth() + 5; + int x = lookupPosition.x + lookupWidthAndGap; + RelativePoint point; + // if documentation doesn't fit into screen, put it on the left hand side + if (x + Math.max(hintSize.width, maxWidth) > screenRectangle.width) { + point = new RelativePoint(lookupComponent, new Point(-hintSize.width - 5, 0)); + } else { + point = new RelativePoint(lookupComponent, new Point(lookupWidthAndGap, 0)); + } + myHint.show(point); + lookup.addLookupListener(new LookupAdapter() { + @Override + public void lookupCanceled(LookupEvent event) { + final AbstractPopup hint = myHint; + if (hint != null && hint.canClose() && hint.isVisible()) { + hint.cancel(); + } } + }); + } else if (editor != null && editor.getComponent().isShowing()) { + // let's try to fit at least of half of maximum size on the bottom + Point preferredLocation = JBPopupFactory.getInstance().guessBestPopupLocation(editor).getScreenPoint(); + Rectangle preferred = new Rectangle(preferredLocation.x, preferredLocation.y, MAX_DEFAULT.width, MAX_DEFAULT.height / 2); + Rectangle adjusted = (Rectangle)preferred.clone(); + ScreenUtil.fitToScreen(adjusted); + // if we fail, show documentation on top + if (preferred.y != adjusted.y) { + preferredLocation.y -= editor.getLineHeight() + hintSize.height; } - }); - } else if (editor != null && editor.getComponent().isShowing()) { - // let's try to fit at least of half of maximum size on the bottom - Point preferredLocation = JBPopupFactory.getInstance().guessBestPopupLocation(editor).getScreenPoint(); - Rectangle preferred = new Rectangle(preferredLocation.x, preferredLocation.y, MAX_DEFAULT.width, MAX_DEFAULT.height / 2); - Rectangle adjusted = (Rectangle)preferred.clone(); - ScreenUtil.fitToScreen(adjusted); - // if we fail, show documentation on top - if (preferred.y != adjusted.y) { - preferredLocation.y -= editor.getLineHeight() + hintSize.height; - } - myHint.show(new RelativePoint(preferredLocation)); - } - else { - PopupPositionManager.positionPopupInBestPosition(myHint, editor, dataContext); - } - myIsShown = true; - if (myHint.getDimensionServiceKey() == null) { - SwingUtilities.invokeLater(() -> registerSizeTracker()); + myHint.show(new RelativePoint(preferredLocation)); + } + else { + PopupPositionManager.positionPopupInBestPosition(myHint, editor, dataContext); + } + myIsShown = true; + if (myHint.getDimensionServiceKey() == null) { + SwingUtilities.invokeLater(() -> registerSizeTracker()); + } } } } From 619bce734c656a3e20249c8f1a3d2ec04a523496 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Wed, 31 Jan 2018 20:32:38 +0300 Subject: [PATCH 12/23] Minor: fix borders in color scheme export dialog --- .../colors/pluginExport/PluginInfoForm.form | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/pluginExport/PluginInfoForm.form b/platform/lang-impl/src/com/intellij/application/options/colors/pluginExport/PluginInfoForm.form index dbe1591c3d2e..c924f1cda417 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/pluginExport/PluginInfoForm.form +++ b/platform/lang-impl/src/com/intellij/application/options/colors/pluginExport/PluginInfoForm.form @@ -32,19 +32,12 @@ - + - - - - - - - - + @@ -53,19 +46,12 @@ - + - - - - - - - - + From d9a7b648770630eb9f4042dee603a7495cc4939e Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 31 Jan 2018 19:52:00 +0300 Subject: [PATCH 13/23] IDEA-185959 lst: do not update inner ranges while frozen IOOBE at com.intellij.diff.util.DiffUtil.getLines --- .../src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt index 61eb15a9e488..429875ed66c9 100644 --- a/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt +++ b/platform/diff-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerBase.kt @@ -184,6 +184,7 @@ abstract class LineStatusTrackerBase { } override fun onUnfreeze(side: Side) { + calcInnerRanges() installMissingHighlighters() } @@ -194,7 +195,8 @@ abstract class LineStatusTrackerBase { } private fun calcInnerRanges() { - if (isDetectWhitespaceChangedLines()) { + if (isDetectWhitespaceChangedLines() && + !documentTracker.isFrozen()) { for (block in blocks) { if (block.ourData.innerRanges == null) { block.ourData.innerRanges = calcInnerRanges(block) From 82047350f906f1986faf50020a35a8638377318a Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 31 Jan 2018 20:33:53 +0300 Subject: [PATCH 14/23] IDEA-185954 vcs: fix MoveChangesToAnotherListAction for partial changes --- .../vcs/changes/actions/MoveChangesToAnotherListAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java index c2756579f6df..34622a6c8626 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/MoveChangesToAnotherListAction.java @@ -137,7 +137,7 @@ public class MoveChangesToAnotherListAction extends AnAction implements DumbAwar List unversionedFiles = ContainerUtil.newArrayList(); final List changedFiles = ContainerUtil.newArrayList(); VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); - if (files != null) { + if (files != null && changesList.isEmpty()) { changesList.addAll(getChangesForSelectedFiles(project, files, unversionedFiles, changedFiles)); } From 18519d5b7dc9c120f9f23fae2a1bfb7ff137b403 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 31 Jan 2018 20:50:02 +0300 Subject: [PATCH 15/23] lst: preselect changelist that affects current file on "Move To Changelist" --- .../vcs/ex/MoveChangesLineStatusAction.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java index f12de6cf6bd4..fc6a64366184 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java @@ -24,15 +24,18 @@ import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.changes.actions.MoveChangesToAnotherListAction; import com.intellij.openapi.vcs.changes.ui.ChangeListChooser; +import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker.LocalRange; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.BitSet; -import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; +import static java.util.Collections.singletonList; + public class MoveChangesLineStatusAction extends LineStatusActionBase { @Override protected boolean isEnabled(@NotNull LineStatusTrackerBase tracker, @NotNull Editor editor) { @@ -51,36 +54,46 @@ public class MoveChangesLineStatusAction extends LineStatusActionBase { public static void moveToAnotherChangelist(@NotNull PartialLocalLineStatusTracker tracker, @NotNull BitSet selectedLines) { Project project = tracker.getProject(); - List ranges = tracker.getRangesForLines(selectedLines); + List ranges = tracker.getRangesForLines(selectedLines); if (ranges == null || ranges.isEmpty()) return; - Set selectedListIds = ContainerUtil.map2Set(ranges, range -> range.getChangelistId()); - LocalChangeList targetList = askTargetChangelist(project, selectedListIds); + LocalChangeList targetList = askTargetChangelist(project, ranges, tracker); if (targetList == null) return; tracker.moveToChangelist(selectedLines, targetList); } - public static void moveToAnotherChangelist(@NotNull PartialLocalLineStatusTracker tracker, @NotNull PartialLocalLineStatusTracker.LocalRange range) { + public static void moveToAnotherChangelist(@NotNull PartialLocalLineStatusTracker tracker, @NotNull LocalRange range) { Project project = tracker.getProject(); - Set selectedListIds = Collections.singleton(range.getChangelistId()); - LocalChangeList targetList = askTargetChangelist(project, selectedListIds); + LocalChangeList targetList = askTargetChangelist(project, singletonList(range), tracker); if (targetList == null) return; tracker.moveToChangelist(range, targetList); } @Nullable - private static LocalChangeList askTargetChangelist(Project project, @NotNull Set selectedListIds) { + private static LocalChangeList askTargetChangelist(Project project, + @NotNull List selectedRanges, + @NotNull PartialLocalLineStatusTracker tracker) { + Set selectedListIds = ContainerUtil.map2Set(selectedRanges, range -> range.getChangelistId()); + + Set remainingTrackerListIds = new HashSet<>(tracker.getAffectedChangeListsIds()); + remainingTrackerListIds.removeAll(selectedListIds); + ChangeListManager clm = ChangeListManager.getInstance(project); List allChangelists = clm.getChangeListsCopy(); List nonAffectedLists = ContainerUtil.filter(allChangelists, list -> !selectedListIds.contains(list.getId())); + List remainingTrackerLists = ContainerUtil.filter(allChangelists, list -> remainingTrackerListIds.contains(list.getId())); + List suggestedLists = nonAffectedLists.isEmpty() - ? Collections.singletonList(clm.getDefaultChangeList()) + ? singletonList(clm.getDefaultChangeList()) : nonAffectedLists; - ChangeList defaultSelection = MoveChangesToAnotherListAction.guessPreferredList(nonAffectedLists); + + List preferedLists = remainingTrackerLists.isEmpty() ? nonAffectedLists : remainingTrackerLists; + ChangeList defaultSelection = MoveChangesToAnotherListAction.guessPreferredList(preferedLists); + ChangeListChooser chooser = new ChangeListChooser(project, suggestedLists, defaultSelection, From 4f1852e7055abd6085dbd4777aef3edd7749571b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 31 Jan 2018 18:42:47 +0100 Subject: [PATCH 16/23] Revert https://github.com/JetBrains/intellij-community/commit/f44256ecc562b7e54e9e49483464ca6306fba3f8 Once calculated, myDuplicatesCache was never cleared, so it kept returning the same result regardless of parameters. Also, getProjectName() also has caching now, so it never performs I/O in EDT --- .../ide/RecentProjectsManagerBase.java | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java index 2e1b7aa7fe92..33e2c1057051 100644 --- a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java +++ b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java @@ -154,8 +154,6 @@ public abstract class RecentProjectsManagerBase extends RecentProjectsManager im private State myState = new State(); private final Map myNameCache = Collections.synchronizedMap(new THashMap()); - private Set myDuplicatesCache = null; - private boolean isDuplicatesCacheUpdating = false; private boolean myBatchOpening; protected RecentProjectsManagerBase(@NotNull MessageBus messageBus) { @@ -410,26 +408,14 @@ public abstract class RecentProjectsManagerBase extends RecentProjectsManager im } private Set getDuplicateProjectNames(Set openedPaths, Set recentPaths) { - if (myDuplicatesCache != null) { - return myDuplicatesCache; + Set names = ContainerUtil.newHashSet(); + Set duplicates = ContainerUtil.newHashSet(); + for (String path : ContainerUtil.concat(openedPaths, recentPaths)) { + if (!names.add(getProjectName(path))) { + duplicates.add(path); + } } - - if (!isDuplicatesCacheUpdating) { - isDuplicatesCacheUpdating = true; //assuming that this check happens only on EDT. So, no synchronised block or double-checked locking needed - Set names = ContainerUtil.newHashSet(); - final HashSet duplicates = ContainerUtil.newHashSet(); - ArrayList list = ContainerUtil.newArrayList(ContainerUtil.concat(openedPaths, recentPaths)); - ApplicationManager.getApplication().executeOnPooledThread(() -> { - for (String path : list) { - if (!names.add(getProjectName(path))) { - duplicates.add(path); - } - } - myDuplicatesCache = duplicates; - isDuplicatesCacheUpdating = false; - }); - } - return ContainerUtil.newHashSet(); + return duplicates; } @Override From 1b91b854fd9be9493e2b65f0595da9a1da2bdd47 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 31 Jan 2018 22:31:10 +0300 Subject: [PATCH 17/23] show toolbar when needed in embedded mode (IDEA-185930) --- .../codeInsight/documentation/DocumentationComponent.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index 0d97f7bc34b5..bc1ba525a878 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -490,7 +490,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr if (myHint == null && myManager.myToolWindow == null) { int em = myEditorPane.getFont().getSize(); int prefHeightMax = PREFERRED_HEIGHT_MAX_EM * em; - return new Dimension(size.width, Math.min(prefHeightMax, size.height)); + return new Dimension(size.width, Math.min(prefHeightMax, + size.height + (needsToolbar() ? myControlPanel.getPreferredSize().height : 0))); } return size; } @@ -1128,7 +1129,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private boolean needsToolbar() { - return myHint != null && Registry.is("documentation.show.toolbar"); + return myManager.myToolWindow == null && Registry.is("documentation.show.toolbar"); } private static class MyGearActionGroup extends DefaultActionGroup implements HintManagerImpl.ActionToIgnore { From 72241b3d795bfbfd54cb4d228c1eedb8247eb366 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 31 Jan 2018 22:41:36 +0300 Subject: [PATCH 18/23] Revert "Do not update toolbar if it is hidden" (WEB-30755) This reverts commit f4472a78a3bf188134876daeca055329b07d32d7. --- .../src/com/intellij/openapi/editor/impl/ContextMenuImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java index 8d0063cd691b..16a01e641d46 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java @@ -113,10 +113,10 @@ public class ContextMenuImpl extends JPanel implements Disposable { } private void toggleContextToolbar(final boolean show) { + myActionToolbar.updateActionsImmediately(); if (((Container)myActionToolbar).getComponentCount() == 0) { return; } - myActionToolbar.updateActionsImmediately(); if (myShow != show) { myShow = show; From b523663a5efdc50e1d4ef5afa2289f137683f5a9 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Wed, 31 Jan 2018 19:19:37 +0300 Subject: [PATCH 19/23] [jvm-lang] extract base interface for requests --- .../lang/jvm/actions/ActionRequest.kt | 13 ++++++++++ .../jvm/actions/CreateExecutableRequest.kt | 6 ++--- .../lang/jvm/actions/CreateFieldRequest.kt | 26 ++----------------- 3 files changed, 17 insertions(+), 28 deletions(-) create mode 100644 java/java-analysis-api/src/com/intellij/lang/jvm/actions/ActionRequest.kt diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ActionRequest.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ActionRequest.kt new file mode 100644 index 000000000000..1cd3eedbcd9c --- /dev/null +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/ActionRequest.kt @@ -0,0 +1,13 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.lang.jvm.actions + +interface ActionRequest { + + /** + * Request may be bound to the PSI-element in call-site language, + * which means request will become invalid if element is invalidated. + * + * @return `true` if it is safe to call other methods of this request, `false` otherwise + */ + val isValid: Boolean +} diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateExecutableRequest.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateExecutableRequest.kt index 847a7a4b0354..2a3d27aed619 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateExecutableRequest.kt +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateExecutableRequest.kt @@ -1,12 +1,10 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.lang.jvm.actions import com.intellij.lang.jvm.JvmModifier import com.intellij.lang.jvm.types.JvmSubstitutor -interface CreateExecutableRequest { - - val isValid: Boolean +interface CreateExecutableRequest : ActionRequest { val modifiers: Collection diff --git a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateFieldRequest.kt b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateFieldRequest.kt index b118bc0f2866..04cb605751b2 100644 --- a/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateFieldRequest.kt +++ b/java/java-analysis-api/src/com/intellij/lang/jvm/actions/CreateFieldRequest.kt @@ -1,32 +1,10 @@ -/* - * Copyright 2000-2017 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.lang.jvm.actions import com.intellij.lang.jvm.JvmModifier import com.intellij.lang.jvm.types.JvmSubstitutor -interface CreateFieldRequest { - - /** - * Request may be bound to the PSI-element in call-site language, - * which means request will become invalid if element is invalidated. - * - * @return `true` if it is safe to call other methods of this object, `false` otherwise - */ - val isValid: Boolean +interface CreateFieldRequest : ActionRequest { /** * @return name of the field to be created From 5d4d75abc578372d8bae4f02a5d9b94070d596be Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 31 Jan 2018 16:34:04 +0300 Subject: [PATCH 20/23] IDEA-185543: remove old hack and use shared code to align lists --- .../util/gotoByName/ChooseByNamePopup.java | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java index db5057d2b674..6476b0c730a1 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNamePopup.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.util.gotoByName; import com.intellij.featureStatistics.FeatureUsageTracker; @@ -148,10 +134,6 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP bounds.y += layeredPane.getHeight(); final Dimension preferredScrollPaneSize = myListScrollPane.getPreferredSize(); - int lastVisibleRow = Math.min(myList.getVisibleRowCount(), myList.getModel().getSize()) - 1; - Rectangle visibleBounds = lastVisibleRow < 0 ? null : myList.getCellBounds(0, lastVisibleRow); - preferredScrollPaneSize.height = visibleBounds != null ? visibleBounds.height : UIManager.getFont("Label.font").getSize(); - preferredScrollPaneSize.width = Math.max(myTextFieldPanel.getWidth(), preferredScrollPaneSize.width); // in 'focus follows mouse' mode, to avoid focus escaping to editor, don't reduce popup size when list size is reduced From d810a2aa2db201bded595bacc6d35ad055daedf9 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 31 Jan 2018 20:25:53 +0300 Subject: [PATCH 21/23] IDEA-185543: getPreferredScrollableViewportSize for lists and trees --- .../intellij/ide/util/FileStructurePopup.java | 19 +--- .../openapi/ui/MasterDetailsComponent.java | 11 +- .../com/intellij/ui/components/JBList.java | 48 -------- .../intellij/ui/components/JBViewport.java | 103 +++++++++++++++++- .../intellij/ui/treeStructure/SimpleTree.java | 20 +--- 5 files changed, 104 insertions(+), 97 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 3634740c2ca0..a4c3b047add3 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.util; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; @@ -623,9 +609,6 @@ public class FileStructurePopup implements Disposable, TreeActionsOwner { panel.add(topPanel, BorderLayout.NORTH); JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTree); scrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.TOP | SideBorder.BOTTOM)); - Dimension preferredSize = scrollPane.getPreferredSize(); - preferredSize.width = Math.max(chkPanel.getPreferredSize().width, JBUI.scale(350)); - scrollPane.setPreferredSize(preferredSize); panel.add(scrollPane, BorderLayout.CENTER); //panel.add(createSouthPanel(), BorderLayout.SOUTH); DataManager.registerDataProvider(panel, new DataProvider() { diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index e3df0c41b2f2..d707fbe3e1f5 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.ui; import com.intellij.CommonBundle; @@ -499,13 +497,6 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom private void createUIComponents() { myTree = new Tree() { - @Override - public Dimension getPreferredScrollableViewportSize() { - Dimension size = super.getPreferredScrollableViewportSize(); - size = new Dimension(size.width + 20, size.height); - return size; - } - @Override @SuppressWarnings("NonStaticInitializer") public JToolTip createToolTip() { 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 c9d5c1ce01cd..a95c1fb5cf1e 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBList.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBList.java @@ -381,52 +381,4 @@ public class JBList extends JList implements ComponentWithEmptyText, Compo } } } - - @Override - public Dimension getPreferredScrollableViewportSize() { - return getPreferredScrollableViewportSize(this); - } - - @NotNull - static Dimension getPreferredScrollableViewportSize(@NotNull JList list) { - Dimension size = list.getPreferredSize(); - if (size == null) return new Dimension(); - if (JList.VERTICAL != list.getLayoutOrientation()) return size; - - int fixedWidth = list.getFixedCellWidth(); - int fixedHeight = list.getFixedCellHeight(); - - ListModel model = list.getModel(); - int modelRows = model == null ? 0 : model.getSize(); - if (modelRows <= 0) { - if (fixedWidth <= 0) fixedWidth = Registry.intValue("ide.preferred.scrollable.viewport.fixed.width"); - if (fixedWidth <= 0) fixedWidth = JBUI.scale(256); // scaled value from JDK - if (fixedHeight <= 0) fixedHeight = Registry.intValue("ide.preferred.scrollable.viewport.fixed.height"); - if (fixedHeight <= 0) fixedHeight = JBUI.scale(16); // scaled value from JDK - } - int visibleRows = list.getVisibleRowCount(); - if (visibleRows <= 0) visibleRows = Registry.intValue("ide.preferred.scrollable.viewport.visible.rows"); - - boolean addExtraSpace = 0 < visibleRows && visibleRows < modelRows && Registry.is("ide.preferred.scrollable.viewport.extra.space"); - Insets insets = list.getInsets(); - size.height = insets != null ? insets.top + insets.bottom : 0; - if (0 < fixedWidth && 0 < fixedHeight) { - size.width = insets != null ? insets.left + insets.right + fixedWidth : fixedWidth; - size.height += fixedHeight * visibleRows; - if (addExtraSpace) size.height += fixedHeight / 2; - } - else if (addExtraSpace) { - Rectangle bounds = list.getCellBounds(visibleRows, visibleRows); - if (bounds != null) size.height = bounds.y + bounds.height / 2; - } - else if (visibleRows > 0) { - int lastRow = Math.min(visibleRows, modelRows) - 1; - Rectangle bounds = list.getCellBounds(lastRow, lastRow); - if (bounds != null) { - size.height = bounds.y + bounds.height; - if (insets != null) size.height += insets.bottom; - } - } - return size; - } } diff --git a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java index 6e92b6e9eee0..d5950e5b5573 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java @@ -6,10 +6,12 @@ import com.intellij.notification.NotificationGroup; import com.intellij.notification.NotificationType; import com.intellij.openapi.ui.TypingTarget; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.components.JBScrollPane.Alignment; import com.intellij.ui.table.JBTable; import com.intellij.util.MethodInvocator; import com.intellij.util.ui.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -61,8 +63,8 @@ public class JBViewport extends JViewport implements ZoomableViewport { Component view = viewport.getView(); if (view instanceof Scrollable) { Scrollable scrollable = (Scrollable)view; - if (view instanceof JBList) return scrollable.getPreferredScrollableViewportSize(); - if (view instanceof JList) return JBList.getPreferredScrollableViewportSize((JList)view); + if (view instanceof JList) return getPreferredScrollableViewportSize((JList)view); + if (view instanceof JTree) return getPreferredScrollableViewportSize((JTree)view); return scrollable.getPreferredScrollableViewportSize(); } if (view != null) { @@ -322,6 +324,7 @@ public class JBViewport extends JViewport implements ZoomableViewport { } static Insets getViewInsets(JComponent view) { + Border border = view.getBorder(); if (border instanceof ViewBorder) { ViewBorder vb = (ViewBorder)border; @@ -513,4 +516,100 @@ public class JBViewport extends JViewport implements ZoomableViewport { } } } + + private static Class getPreferredScrollableViewportSizeDeclaringClass(@NotNull Scrollable scrollable) { + try { + return scrollable.getClass().getMethod("getPreferredScrollableViewportSize").getDeclaringClass(); + } + catch (Exception exception) { + return null; + } + } + + @NotNull + private static Dimension getPreferredScrollableViewportSize(@NotNull JList list) { + if (JList.class != getPreferredScrollableViewportSizeDeclaringClass(list)) { + return list.getPreferredScrollableViewportSize(); + } + Dimension size = list.getPreferredSize(); + if (size == null) return new Dimension(); + if (JList.VERTICAL != list.getLayoutOrientation()) return size; + + int fixedWidth = list.getFixedCellWidth(); + int fixedHeight = list.getFixedCellHeight(); + + ListModel model = list.getModel(); + int modelRows = model == null ? 0 : model.getSize(); + if (modelRows <= 0) { + if (fixedWidth <= 0) fixedWidth = Registry.intValue("ide.preferred.scrollable.viewport.fixed.width"); + if (fixedWidth <= 0) fixedWidth = JBUI.scale(256); // scaled value from JDK + if (fixedHeight <= 0) fixedHeight = Registry.intValue("ide.preferred.scrollable.viewport.fixed.height"); + if (fixedHeight <= 0) fixedHeight = JBUI.scale(16); // scaled value from JDK + } + int visibleRows = list.getVisibleRowCount(); + if (visibleRows <= 0) visibleRows = Registry.intValue("ide.preferred.scrollable.viewport.visible.rows"); + + boolean addExtraSpace = 0 < visibleRows && visibleRows < modelRows && Registry.is("ide.preferred.scrollable.viewport.extra.space"); + Insets insets = list.getInsets(); + size.height = insets != null ? insets.top + insets.bottom : 0; + if (0 < fixedWidth && 0 < fixedHeight) { + size.width = insets != null ? insets.left + insets.right + fixedWidth : fixedWidth; + size.height += fixedHeight * visibleRows; + if (addExtraSpace) size.height += fixedHeight / 2; + } + else if (addExtraSpace) { + Rectangle bounds = list.getCellBounds(visibleRows, visibleRows); + if (bounds != null) size.height = bounds.y + bounds.height / 2; + } + else if (visibleRows > 0) { + int lastRow = Math.min(visibleRows, modelRows) - 1; + Rectangle bounds = list.getCellBounds(lastRow, lastRow); + if (bounds != null) { + size.height = bounds.y + bounds.height; + if (insets != null) size.height += insets.bottom; + } + } + return size; + } + + @NotNull + private static Dimension getPreferredScrollableViewportSize(@NotNull JTree tree) { + if (JTree.class != getPreferredScrollableViewportSizeDeclaringClass(tree)) { + return tree.getPreferredScrollableViewportSize(); + } + Dimension size = tree.getPreferredSize(); + if (size == null) return new Dimension(); + + int fixedHeight = tree.getRowHeight(); + + int modelRows = tree.getRowCount(); + if (modelRows <= 0) { + if (fixedHeight <= 0) fixedHeight = Registry.intValue("ide.preferred.scrollable.viewport.fixed.height"); + if (fixedHeight <= 0) fixedHeight = JBUI.scale(16); + } + int visibleRows = tree.getVisibleRowCount(); + if (visibleRows <= 0) visibleRows = Registry.intValue("ide.preferred.scrollable.viewport.visible.rows"); + + boolean addExtraSpace = Registry.is("ide.preferred.scrollable.viewport.extra.space"); + Insets insets = tree.getInsets(); + size.height = insets != null ? insets.top + insets.bottom : 0; + if (0 < fixedHeight) { + size.height += fixedHeight * visibleRows; + if (addExtraSpace) size.height += fixedHeight / 2; + } + else if (visibleRows > 0) { + int lastRow = Math.min(visibleRows, modelRows - 1); + Rectangle bounds = tree.getRowBounds(lastRow); + if (bounds != null) { + size.height = bounds.y + bounds.height * (visibleRows - lastRow); + if (addExtraSpace) { + size.height += bounds.height / 2; + } + else if (insets != null) { + size.height += insets.bottom; + } + } + } + return size; + } } diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/SimpleTree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/SimpleTree.java index b3c8efd16ca4..e6e01ea5f133 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/SimpleTree.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/SimpleTree.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ui.treeStructure; import com.intellij.ide.util.treeView.AbstractTreeBuilder; @@ -477,10 +463,6 @@ public class SimpleTree extends Tree implements CellEditorListener { return (DefaultTreeModel)getModel(); } - public Dimension getPreferredScrollableViewportSize() { - return super.getPreferredSize(); - } - public NodeRenderer getRenderer() { return (NodeRenderer)getCellRenderer(); } From 553fa9b128590014cc92e2577555ebe752a057a0 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 31 Jan 2018 23:13:41 +0300 Subject: [PATCH 22/23] IDEA-185543: fix table height for Usages popup --- .../find/actions/ShowUsagesAction.java | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index 8ee4b9677cdd..4f8ee2e04fd0 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.find.actions; import com.intellij.codeInsight.TargetElementUtil; @@ -1006,25 +1004,17 @@ public class ShowUsagesAction extends AnAction implements PopupAction { myWidth = newWidth; - int rowsToShow = Math.min(30, data.size()); - Dimension dimension = new Dimension(newWidth, table.getRowHeight() * rowsToShow); - Rectangle rectangle = fitToScreen(dimension, popupPosition, table); - if (!data.isEmpty()) { - ScrollingUtil.ensureSelectionExists(table); - } - table.setSize(rectangle.getSize()); - //table.setPreferredSize(dimension); - //table.setMaximumSize(dimension); - //table.setPreferredScrollableViewportSize(dimension); - - Dimension footerSize = ((AbstractPopup)popup).getFooterPreferredSize(); int footer = footerSize.height; int footerBorder = footer == 0 ? 0 : 1; Insets insets = ((AbstractPopup)popup).getPopupBorder().getBorderInsets(content); - rectangle.height += headerSize.height + footer + footerBorder + insets.top + insets.bottom; - ScreenUtil.fitToScreen(rectangle); + int minHeight = headerSize.height + footer + footerBorder + insets.top + insets.bottom; + + Rectangle rectangle = getPreferredBounds(table, popupPosition.getScreenPoint(), newWidth, minHeight, data.size()); + table.setSize(rectangle.width, rectangle.height - minHeight); + if (!data.isEmpty()) ScrollingUtil.ensureSelectionExists(table); + Dimension newDim = rectangle.getSize(); window.setBounds(rectangle); window.setMinimumSize(newDim); @@ -1034,16 +1024,19 @@ public class ShowUsagesAction extends AnAction implements PopupAction { window.repaint(); } - private static Rectangle fitToScreen(@NotNull Dimension newDim, @NotNull RelativePoint popupPosition, JTable table) { - Rectangle rectangle = new Rectangle(popupPosition.getScreenPoint(), newDim); - ScreenUtil.fitToScreen(rectangle); - if (rectangle.getHeight() != newDim.getHeight()) { - int newHeight = (int)rectangle.getHeight(); - int roundedHeight = newHeight - newHeight % table.getRowHeight(); - rectangle.setSize((int)rectangle.getWidth(), Math.max(roundedHeight, table.getRowHeight())); + private static Rectangle getPreferredBounds(@NotNull JTable table, @NotNull Point point, int width, int minHeight, int modelRows) { + boolean addExtraSpace = Registry.is("ide.preferred.scrollable.viewport.extra.space"); + int visibleRows = Math.min(30, modelRows); + int rowHeight = table.getRowHeight(); + int space = addExtraSpace && visibleRows < modelRows ? rowHeight / 2 : 0; + int height = visibleRows * rowHeight + minHeight + space; + Rectangle bounds = new Rectangle(point.x, point.y, width, height); + ScreenUtil.fitToScreen(bounds); + if (bounds.height != height) { + minHeight += addExtraSpace && space == 0 ? rowHeight / 2 : space; + bounds.height = Math.max(1, (bounds.height - minHeight) / rowHeight) * rowHeight + minHeight; } - return rectangle; - + return bounds; } private void appendMoreUsages(Editor editor, From 2b05f663077ae77d1f11ce36a71dbd5e400b90a9 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 31 Jan 2018 23:14:33 +0300 Subject: [PATCH 23/23] IDEA-185543: preferredLayoutSize for JBScrollPane --- .../intellij/ui/components/JBScrollPane.java | 154 +++++------------- 1 file changed, 41 insertions(+), 113 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index 9c71e972cbd5..82ca872e846c 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ui.components; import com.intellij.openapi.diagnostic.Logger; @@ -676,116 +662,58 @@ public class JBScrollPane extends JScrollPane { @Override public Dimension preferredLayoutSize(Container parent) { - /* Sync the (now obsolete) policy fields with the - * JScrollPane. - */ - JScrollPane scrollPane = (JScrollPane)parent; - vsbPolicy = scrollPane.getVerticalScrollBarPolicy(); - hsbPolicy = scrollPane.getHorizontalScrollBarPolicy(); + Dimension result = new Dimension(); - Insets insets = parent.getInsets(); - int prefWidth = insets.left + insets.right; - int prefHeight = insets.top + insets.bottom; + JScrollPane pane = (JScrollPane)parent; + JBInsets.addTo(result, pane.getInsets()); - /* Note that viewport.getViewSize() is equivalent to - * viewport.getView().getPreferredSize() modulo a null - * view or a view whose size was explicitly set. - */ - - Dimension extentSize = null; - Dimension viewSize = null; - Component view = null; + Border border = pane.getViewportBorder(); + if (border != null) JBInsets.addTo(result, border.getBorderInsets(parent)); + int vsbPolicy = pane.getVerticalScrollBarPolicy(); + int hsbPolicy = pane.getHorizontalScrollBarPolicy(); if (viewport != null) { - extentSize = viewport.getPreferredSize(); - view = viewport.getView(); + Component view = viewport.getView(); if (view != null) { - viewSize = view.getPreferredSize(); - } else { - viewSize = new Dimension(0, 0); - } - } - - /* If there's a viewport add its preferredSize. - */ - - if (extentSize != null) { - prefWidth += extentSize.width; - prefHeight += extentSize.height; - } - - /* If there's a JScrollPane.viewportBorder, add its insets. - */ - - Border viewportBorder = scrollPane.getViewportBorder(); - if (viewportBorder != null) { - Insets vpbInsets = viewportBorder.getBorderInsets(parent); - prefWidth += vpbInsets.left + vpbInsets.right; - prefHeight += vpbInsets.top + vpbInsets.bottom; - } - - /* If a header exists and it's visible, factor its - * preferred size in. - */ - - if ((rowHead != null) && rowHead.isVisible()) { - prefWidth += rowHead.getPreferredSize().width; - } - - if ((colHead != null) && colHead.isVisible()) { - prefHeight += colHead.getPreferredSize().height; - } - - /* If a scrollbar is going to appear, factor its preferred size in. - * If the scrollbars policy is AS_NEEDED, this can be a little - * tricky: - * - * - If the view is a Scrollable then scrollableTracksViewportWidth - * and scrollableTracksViewportHeight can be used to effectively - * disable scrolling (if they're true) in their respective dimensions. - * - * - Assuming that a scrollbar hasn't been disabled by the - * previous constraint, we need to decide if the scrollbar is going - * to appear to correctly compute the JScrollPanes preferred size. - * To do this we compare the preferredSize of the viewport (the - * extentSize) to the preferredSize of the view. Although we're - * not responsible for laying out the view we'll assume that the - * JViewport will always give it its preferredSize. - */ - - if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) { - boolean considerVsbWidth = vsb.isOpaque() || isAlwaysOpaque(view); - if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) { - if (considerVsbWidth) prefWidth += vsb.getPreferredSize().width; - } - else if ((viewSize != null) && (extentSize != null)) { - boolean canScroll = true; + // If the view is tracking the viewports width we don't bother with a horizontal scrollbar. + // If the view is tracking the viewports height we don't bother with a vertical scrollbar. + boolean viewTracksViewportWidth = false; + boolean viewTracksViewportHeight = false; + // Don't bother checking the Scrollable methods if there is no room for the viewport, + // we aren't going to show any scroll bars in this case anyway. if (view instanceof Scrollable) { - canScroll = !((Scrollable)view).getScrollableTracksViewportHeight(); + Scrollable scrollable = (Scrollable)view; + viewTracksViewportWidth = scrollable.getScrollableTracksViewportWidth(); + viewTracksViewportHeight = scrollable.getScrollableTracksViewportHeight(); } - if (canScroll && viewSize.height > extentSize.height && considerVsbWidth) { - prefWidth += vsb.getPreferredSize().width; + Dimension viewportExtentSize = viewport.getPreferredSize(); + Dimension viewPreferredSize = view.getPreferredSize(); + if (view instanceof JComponent && !view.isPreferredSizeSet()) { + Insets insets = JBViewport.getViewInsets((JComponent)view); + JBInsets.removeFrom(viewportExtentSize, insets); + JBInsets.removeFrom(viewPreferredSize, insets); + } + result.width += viewportExtentSize.width; + result.height += viewportExtentSize.height; + if (!viewTracksViewportHeight && vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) { + if (viewPreferredSize.height > viewportExtentSize.height || 0 != view.getY()) { + vsbPolicy = VERTICAL_SCROLLBAR_ALWAYS; + } + } + if (!viewTracksViewportWidth && vsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED) { + if (viewPreferredSize.width > viewportExtentSize.width || 0 != view.getX()) { + vsbPolicy = HORIZONTAL_SCROLLBAR_ALWAYS; + } } } } + if (vsb != null && vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) result.width += vsb.getPreferredSize().width; + if (hsb != null && hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) result.height += hsb.getPreferredSize().height; - if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) { - boolean considerHsbHeight = hsb.isOpaque() || isAlwaysOpaque(view); - if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS && considerHsbHeight) { - prefHeight += hsb.getPreferredSize().height; - } - else if ((viewSize != null) && (extentSize != null)) { - boolean canScroll = true; - if (view instanceof Scrollable) { - canScroll = !((Scrollable)view).getScrollableTracksViewportWidth(); - } - if (canScroll && (viewSize.width > extentSize.width) && considerHsbHeight) { - prefHeight += hsb.getPreferredSize().height; - } - } - } + if (rowHead != null && rowHead.isVisible()) result.width += rowHead.getPreferredSize().width; + if (colHead != null && colHead.isVisible()) result.height += colHead.getPreferredSize().height; - return new Dimension(prefWidth, prefHeight); + return result; } private static boolean isAlwaysOpaque(Component view) {