Stacked gutter icons - set popup text

Answered

I am developing plugin where i generate multiple gutter icons with same icon picture but different functionality at one line. Such stacked gutter icons are displayed as a one icon (picture 1). When i click on these stacked gutter icons, popup menu is displayed, so i can choose which gutter icon i want to use (picture 2).





I would like to specify popup text for each gutter icon so i can differentiate them. It looks like default popup text value is text of PSI element which i put as a parameter to method 'createLineMarkerInfo' from class:
https://github.com/joewalnes/idea-community/blob/master/xml/dom-openapi/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java

I tought method 'setPopupTitle' in same class would do the trick, but i dont see any effect when i use it.

This is part of code from my plugin:

val navigationGutterIconBuilder = NavigationGutterIconBuilder
.create(arrowIcon)
.setPopupTitle("Expected POPUP text")


navigationGutterIconBuilder.createLineMarkerInfo(psiElement)

How could i specify my custom popup text for each gutter icon to be displayed in popup menu?

12 comments
Comment actions Permalink

com.intellij.codeInsight.navigation.NavigationGutterIconBuilder#setNamer

0
Comment actions Permalink

I tried to use setNamer function but it only affect tooltip (after mouse hover over) but not the popup menu (after click):

val navigationGutterIconBuilder = NavigationGutterIconBuilder
.create(arrowIcon)
.setNamer { "Gutter POPUP menu name" }

 

When i looked at the source code, i found out that myNamer attribute is used only in method #createGutterIconRenderer. And it is called only if i dont set tooltip text using #setTooltipText method. In this case setNamer is called and "Gutter name" will be in tooltip.

But i would like to set custom name in popup menu and #setNamer dont affect popup menu. Is this a bug? Or should i use it differently?

1
Comment actions Permalink

Sorry, you're right. Please extend com.intellij.ide.util.DefaultPsiElementCellRenderer and apply it using com.intellij.codeInsight.navigation.NavigationGutterIconBuilder#setCellRenderer

0
Comment actions Permalink


I extented DefaultPsiElementCellRenderer and override method 'getElementText', also tried 'getContainerText' but without success. I also put breakpoints into the bodies of method, but they didnt trigger. Did i use it correctly?

val navigationGutterIconBuilder = NavigationGutterIconBuilder
.create(arrowIcon)
.setCellRenderer(MyPsiElementCellRenderer())

class MyPsiElementCellRenderer: DefaultPsiElementCellRenderer() {
override fun getElementText(element: PsiElement): String {
return "Expected POPUP text"
}
override fun getContainerText(element: PsiElement, name: String): String {
return "Expected container POPUP text"
}
}
0
Comment actions Permalink

Your snippet looks correct. Could you please show whole method that builds gutter icons?

0
Comment actions Permalink

There is some preprocessing logic, where correct psi elements are selected, variables for tooltip are initialized etc. But i think this is only important part of the method which is related to gutters:

class GutterIconRelatedItemLineMarkerProvider : RelatedItemLineMarkerProvider() {
override fun collectNavigationMarkers(psiElement: PsiElement, resultCollection: MutableCollection<in RelatedItemLineMarkerInfo<PsiElement>>) {

// ... preprocessing

val navigationGutterIconBuilder = NavigationGutterIconBuilder
.create(arrowIcon)
.setTarget(targetPsiElement)
.setTooltipText("File ${targetVirtualFile.name}, Line ${fileMark.targetLine}")
.setCellRenderer(MyPsiElementCellRenderer())

resultCollection.add(navigationGutterIconBuilder.createLineMarkerInfo(leafPsiElement))
}
}

 

Do you think something else could important? Maybe if setCellRenderer work for you, could you provide simple example?

0
Comment actions Permalink

Why do you use setTarget instead of setTargets? No popup will be shown for single element.

1
Comment actions Permalink

That was the problem. NavigationGutterIconBuilder was created multiple times on same line, always with just 'setTarget'. Thank you for help :)

0
Comment actions Permalink

Hello,

I have a very similar problem, except that using com.intellij.codeInsight.navigation.NavigationGutterIconBuilder#setCellRenderer doesn`t help in my case. It looks like navigate() from MergeableLineMarkerInfo that creates a popup menu for each PsiElement is called whenever an icon is clicked. Is it possible to disable the popup menu at all? Apparently, setting NavigationHandler to null in createLineMarkerInfo is not enough.

0
Comment actions Permalink

Elena Richter Sorry for delay, could you please share in more detail what your use case is and ideally share code snippets? It seems you create two infos which get merged automatically due to same icon, and then it will show popup automatically. Thanks.

0
Comment actions Permalink

Thank you for your response. So basically what I’m doing is creating line marker info for each issue in the code. The problem is when there are 2 issues in one line with the same icon the pop up menu is created automatically (as you already mentioned) with the name of each PsiElement related to the line marker. I managed to create a FakePsiElement so there would be shown an issue descriptions instead, nevertheless my question is if there is any way to disable the Pop Menu or as an alternative to access the navigate method so the textRange of each issue could be highlighted onClick action.
Please see a snippet down bellow:

protected void collectNavigationMarkers(@NotNull final PsiElement element, @NotNull final Collection super RelatedItemLineMarkerInfo>> result) {

//find a leaf PsiElement
if (element.getChildren().length == 0 && (element instanceof PsiIdentifier || element instanceof PsiWhiteSpace || element instanceof PsiJavaToken)) {

//…preprocessing
final IssueFakePsiElement fakePsiElement = new IssueFakePsiElement(element, issue);
final NavigationGutterIconBuilder elementIconBuilder = NavigationGutterIconBuilder
.create(icon)
.setTargets(fakePsiElement)
.setTooltipText(tooltipText));

result.add(elementIconBuilder.createLineMarkerInfo(fakePsiElement, issueGutterIconNavigationHandler));
}
}

0
Comment actions Permalink

Elena Richter sorry for delay. it would be possible by subclassing com.intellij.codeInsight.navigation.NavigationGutterIconBuilder to override the default installed com.intellij.codeInsight.navigation.NavigationGutterIconBuilder.MyNavigationGutterIconRenderer to replace the "onclick" action.

 

Or you may use the "raw" API as e.g. in com.intellij.execution.lineMarker.RunLineMarkerProvider#createLineMarker

0

Please sign in to leave a comment.