public static JBPopup createPopup( final List<? extends GotoRelatedItem> items, final String title) { Object[] elements = new Object[items.size()]; // todo[nik] move presentation logic to GotoRelatedItem class final Map<PsiElement, GotoRelatedItem> itemsMap = new HashMap<PsiElement, GotoRelatedItem>(); for (int i = 0; i < items.size(); i++) { GotoRelatedItem item = items.get(i); elements[i] = item.getElement() != null ? item.getElement() : item; itemsMap.put(item.getElement(), item); } return getPsiElementPopup( elements, itemsMap, title, new Processor<Object>() { @Override public boolean process(Object element) { if (element instanceof PsiElement) { //noinspection SuspiciousMethodCalls itemsMap.get(element).navigate(); } else { ((GotoRelatedItem) element).navigate(); } return true; } }); }
/** * Returns navigation popup that shows list of related items from {@code items} list * * @param items * @param title * @param showContainingModules Whether the popup should show additional information that aligned * at the right side of the dialog.<br> * It's usually a module name or library name of corresponding navigation item.<br> * {@code false} by default * @return */ @NotNull public static JBPopup getRelatedItemsPopup( final List<? extends GotoRelatedItem> items, String title, boolean showContainingModules) { Object[] elements = new Object[items.size()]; // todo[nik] move presentation logic to GotoRelatedItem class final Map<PsiElement, GotoRelatedItem> itemsMap = new HashMap<PsiElement, GotoRelatedItem>(); for (int i = 0; i < items.size(); i++) { GotoRelatedItem item = items.get(i); elements[i] = item.getElement() != null ? item.getElement() : item; itemsMap.put(item.getElement(), item); } return getPsiElementPopup( elements, itemsMap, title, showContainingModules, element -> { if (element instanceof PsiElement) { //noinspection SuspiciousMethodCalls itemsMap.get(element).navigate(); } else { ((GotoRelatedItem) element).navigate(); } return true; }); }
@Override protected void collectNavigationMarkers( @NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) { final PsiElement pythonStub = getPythonStub(element); if (pythonStub != null) { final List<GotoRelatedItem> relatedItems = GotoRelatedItem.createItems(Collections.singletonList(pythonStub)); result.add( new RelatedItemLineMarkerInfo<PsiElement>( element, element.getTextRange(), ICON, Pass.LINE_MARKERS, element1 -> "Has stub item in " + pythonStub.getContainingFile().getName(), new GutterIconNavigationHandler<PsiElement>() { @Override public void navigate(MouseEvent e, PsiElement elt) { final PsiElement pythonStub = getPythonStub(elt); if (pythonStub != null) { PsiNavigateUtil.navigate(pythonStub); } } }, GutterIconRenderer.Alignment.RIGHT, relatedItems)); } }
@NotNull private static Collection<PsiClass> findRelatedActivities( @NotNull XmlFile file, @NotNull AndroidFacet facet, @NotNull DomFileDescription<?> description) { if (description instanceof LayoutDomFileDescription) { final Computable<List<GotoRelatedItem>> computable = AndroidGotoRelatedProvider.getLazyItemsForXmlFile(file, facet); if (computable == null) { return Collections.emptyList(); } final List<GotoRelatedItem> items = computable.compute(); if (items.isEmpty()) { return Collections.emptyList(); } final PsiClass activityClass = findActivityClass(facet.getModule()); if (activityClass == null) { return Collections.emptyList(); } final List<PsiClass> result = new ArrayList<PsiClass>(); for (GotoRelatedItem item : items) { final PsiElement element = item.getElement(); if (element instanceof PsiClass) { final PsiClass aClass = (PsiClass) element; if (aClass.isInheritor(activityClass, true)) { result.add(aClass); } } } return result; } else { return findRelatedActivitiesForMenu(file, facet); } }
public class ExtensionPointDeclarationRelatedItemLineMarkerProvider extends DevkitRelatedLineMarkerProviderBase { private static final NotNullFunction<ExtensionPointCandidate, Collection<? extends PsiElement>> CONVERTER = candidate -> Collections.singleton(candidate.pointer.getElement()); private static final NotNullFunction< ExtensionPointCandidate, Collection<? extends GotoRelatedItem>> RELATED_ITEM_PROVIDER = candidate -> GotoRelatedItem.createItems( Collections.singleton(candidate.pointer.getElement()), "DevKit"); @Override protected void collectNavigationMarkers( @NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) { if (element instanceof PsiField) { process((PsiField) element, result); } } private static void process( PsiField psiField, Collection<? super RelatedItemLineMarkerInfo> result) { if (!isExtensionPointNameDeclarationField(psiField)) return; final PsiClass epClass = resolveExtensionPointClass(psiField); if (epClass == null) return; final String epName = resolveEpName(psiField); if (epName == null) return; ExtensionPointLocator locator = new ExtensionPointLocator(epClass); List<ExtensionPointCandidate> targets = ContainerUtil.filter( locator.findDirectCandidates(), new Condition<ExtensionPointCandidate>() { @Override public boolean value(ExtensionPointCandidate candidate) { return epName.equals(candidate.epName); } }); final RelatedItemLineMarkerInfo<PsiElement> info = NavigationGutterIconBuilder.create(AllIcons.Nodes.Plugin, CONVERTER, RELATED_ITEM_PROVIDER) .setTargets(targets) .setPopupTitle("Choose Extension Point") .setTooltipText("Extension Point Declaration") .setAlignment(GutterIconRenderer.Alignment.RIGHT) .createLineMarkerInfo(psiField.getNameIdentifier()); result.add(info); } @Nullable private static PsiClass resolveExtensionPointClass(PsiField psiField) { final PsiType typeParameter = PsiUtil.substituteTypeParameter( psiField.getType(), ExtensionPointName.class.getName(), 0, false); return PsiUtil.resolveClassInClassTypeOnly(typeParameter); } private static String resolveEpName(PsiField psiField) { final PsiExpression initializer = psiField.getInitializer(); PsiExpressionList expressionList = null; if (initializer instanceof PsiMethodCallExpression) { expressionList = ((PsiMethodCallExpression) initializer).getArgumentList(); } else if (initializer instanceof PsiNewExpression) { expressionList = ((PsiNewExpression) initializer).getArgumentList(); } if (expressionList == null) return null; final PsiExpression[] expressions = expressionList.getExpressions(); if (expressions.length != 1) return null; final PsiExpression epNameExpression = expressions[0]; final PsiConstantEvaluationHelper helper = JavaPsiFacade.getInstance(psiField.getProject()).getConstantEvaluationHelper(); final Object o = helper.computeConstantExpression(epNameExpression); return o instanceof String ? (String) o : null; } private static boolean isExtensionPointNameDeclarationField(PsiField psiField) { // *do* allow non-public if (!psiField.hasModifierProperty(PsiModifier.FINAL) || !psiField.hasModifierProperty(PsiModifier.STATIC) || psiField.hasModifierProperty(PsiModifier.ABSTRACT)) { return false; } if (!psiField.hasInitializer()) { return false; } final PsiExpression initializer = psiField.getInitializer(); if (!(initializer instanceof PsiMethodCallExpression) && !(initializer instanceof PsiNewExpression)) { return false; } final PsiClass fieldClass = PsiTypesUtil.getPsiClass(psiField.getType()); if (fieldClass == null) { return false; } return ExtensionPointName.class.getName().equals(fieldClass.getQualifiedName()); } }