From 21ff2883bc94358d40df4e5ec49f380eda4a2ab7 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 5 Feb 2019 16:24:51 +0300 Subject: [PATCH] [platform] add TargetPresentation and its renderers (IDEA-198180) --- .../navigation/TargetPresentation.java | 59 +++++++++++++++++++ .../ide/ui/TargetPresentationMainRenderer.kt | 59 +++++++++++++++++++ .../ide/ui/TargetPresentationRightRenderer.kt | 52 ++++++++++++++++ .../src/com/intellij/ide/ui/renderers.kt | 32 ++++++++++ 4 files changed, 202 insertions(+) create mode 100644 platform/core-api/src/com/intellij/navigation/TargetPresentation.java create mode 100644 platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationMainRenderer.kt create mode 100644 platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationRightRenderer.kt create mode 100644 platform/lang-impl/src/com/intellij/ide/ui/renderers.kt diff --git a/platform/core-api/src/com/intellij/navigation/TargetPresentation.java b/platform/core-api/src/com/intellij/navigation/TargetPresentation.java new file mode 100644 index 000000000000..e653face7cb6 --- /dev/null +++ b/platform/core-api/src/com/intellij/navigation/TargetPresentation.java @@ -0,0 +1,59 @@ +// Copyright 2000-2019 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.navigation; + +import com.intellij.openapi.editor.markup.TextAttributes; +import org.jetbrains.annotations.ApiStatus.Experimental; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * Represents presentation in target popup as follows:
+ * | $icon $presentable_text (in $location_text) spacer $right_text $right_icon |
+ * Elements before spacer are aligned to the left, right text and right icon are aligned to the right. + */ +@Experimental +public interface TargetPresentation { + + @Nullable + default Icon getIcon() { + return null; + } + + @NotNull + String getPresentableText(); + + /** + * Note that returned instance's {@link TextAttributes#getBackgroundColor()} is used for the whole item background. + * + * @return attributes to highlight {@link #getPresentableText()} + */ + @Nullable + default TextAttributes getPresentableAttributes() { + return null; + } + + @Nullable + default String getLocationText() { + return null; + } + + /** + * @return attributes to highlight {@link #getLocationText()} + */ + @Nullable + default TextAttributes getLocationAttributes() { + return null; + } + + @Nullable + default String getRightText() { + return null; + } + + @Nullable + default Icon getRightIcon() { + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationMainRenderer.kt b/platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationMainRenderer.kt new file mode 100644 index 000000000000..dce9ebe7d574 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationMainRenderer.kt @@ -0,0 +1,59 @@ +// Copyright 2000-2019 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.ui + +import com.intellij.navigation.LocationPresentation.DEFAULT_LOCATION_PREFIX +import com.intellij.navigation.LocationPresentation.DEFAULT_LOCATION_SUFFIX +import com.intellij.navigation.TargetPresentation +import com.intellij.openapi.project.Project +import com.intellij.ui.ColoredListCellRenderer +import com.intellij.ui.JBColor +import com.intellij.ui.SimpleTextAttributes +import com.intellij.ui.SimpleTextAttributes.* +import com.intellij.ui.speedSearch.SearchAwareRenderer +import com.intellij.ui.speedSearch.SpeedSearchUtil.appendColoredFragmentForMatcher +import com.intellij.util.text.MatcherHolder +import com.intellij.util.ui.UIUtil +import org.jetbrains.annotations.ApiStatus.Experimental +import javax.swing.JList + +@Experimental +abstract class TargetPresentationMainRenderer( + private val project: Project +) : ColoredListCellRenderer(), + SearchAwareRenderer { + + protected abstract fun getPresentation(value: T): TargetPresentation? + + final override fun getItemSearchString(item: T): String? = getPresentation(item)?.presentableText + + final override fun customizeCellRenderer(list: JList, value: T, index: Int, selected: Boolean, hasFocus: Boolean) { + val presentation = getPresentation(value) ?: run { + append("Invalid", ERROR_ATTRIBUTES) + return + } + val attributes = presentation.presentableAttributes + val bgColor = attributes?.backgroundColor ?: UIUtil.getListBackground() + + icon = presentation.icon + background = if (selected) UIUtil.getListSelectionBackground(hasFocus) else bgColor + + val nameAttributes = attributes?.let(::fromTextAttributes) + ?: SimpleTextAttributes(STYLE_PLAIN, list.foreground) + val matcher = MatcherHolder.getAssociatedMatcher(list) + appendColoredFragmentForMatcher(presentation.presentableText, this, nameAttributes, matcher, bgColor, selected) + + presentation.locationText?.let { locationText -> + val locationAttributes = presentation.locationAttributes?.let { + merge(defaultLocationAttributes, fromTextAttributes(it)) + } ?: defaultLocationAttributes + append(DEFAULT_LOCATION_PREFIX, defaultLocationAttributes) + append("in ", defaultLocationAttributes) + append(locationText, locationAttributes) + append(DEFAULT_LOCATION_SUFFIX, defaultLocationAttributes) + } + } + + companion object { + private val defaultLocationAttributes = SimpleTextAttributes(STYLE_PLAIN, JBColor.GRAY) + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationRightRenderer.kt b/platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationRightRenderer.kt new file mode 100644 index 000000000000..ca7c3898e6b5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/ui/TargetPresentationRightRenderer.kt @@ -0,0 +1,52 @@ +// Copyright 2000-2019 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.ui + +import com.intellij.navigation.TargetPresentation +import com.intellij.ui.components.JBLabel +import com.intellij.ui.speedSearch.SearchAwareRenderer +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil +import org.jetbrains.annotations.ApiStatus.Experimental +import java.awt.Component +import javax.swing.JList +import javax.swing.ListCellRenderer +import javax.swing.SwingConstants + +@Experimental +internal abstract class TargetPresentationRightRenderer : ListCellRenderer, SearchAwareRenderer { + + companion object { + private val ourBorder = JBUI.Borders.emptyRight(UIUtil.getListCellHPadding()) + } + + protected abstract fun getPresentation(value: T): TargetPresentation? + + private val component = JBLabel().apply { + border = ourBorder + horizontalTextPosition = SwingConstants.LEFT + horizontalAlignment = SwingConstants.RIGHT // align icon to the right + } + + final override fun getItemSearchString(item: T): String? = getPresentation(item)?.locationText + + final override fun getListCellRendererComponent(list: JList, + value: T, + index: Int, + isSelected: Boolean, + cellHasFocus: Boolean): Component { + component.apply { + text = "" + icon = null + background = UIUtil.getListBackground(isSelected) + foreground = if (isSelected) UIUtil.getListSelectionForeground() else UIUtil.getInactiveTextColor() + font = list.font + } + getPresentation(value)?.let { presentation -> + presentation.rightText?.let { rightText -> + component.text = rightText + component.icon = presentation.rightIcon + } + } + return component + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/ui/renderers.kt b/platform/lang-impl/src/com/intellij/ide/ui/renderers.kt new file mode 100644 index 000000000000..59a45b600920 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/ui/renderers.kt @@ -0,0 +1,32 @@ +// Copyright 2000-2019 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.ui + +import com.intellij.navigation.TargetPresentation +import com.intellij.openapi.project.Project +import com.intellij.ui.list.LeftRightSearchAwareRenderer +import com.intellij.ui.speedSearch.SearchAwareRenderer +import org.jetbrains.annotations.ApiStatus.Experimental + +@Experimental +fun createTargetPresentationRenderer(project: Project, presentation: (T) -> TargetPresentation?): SearchAwareRenderer { + val mainRenderer = createMainRenderer(project, presentation) + if (UISettings.instance.showIconInQuickNavigation) { + val rightRenderer = createRightRenderer(presentation) + return LeftRightSearchAwareRenderer(mainRenderer, rightRenderer) + } + else { + return mainRenderer + } +} + +private fun createMainRenderer(project: Project, presentation: (T) -> TargetPresentation?): SearchAwareRenderer { + return object : TargetPresentationMainRenderer(project) { + override fun getPresentation(value: T): TargetPresentation? = presentation(value) + } +} + +private fun createRightRenderer(presentation: (T) -> TargetPresentation?): SearchAwareRenderer { + return object : TargetPresentationRightRenderer() { + override fun getPresentation(value: T): TargetPresentation? = presentation(value) + } +}