package com.siberika.idea.pascal.editor; import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.codeInsight.daemon.LineMarkerProvider; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; import com.intellij.psi.PsiElement; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.util.SmartList; import com.siberika.idea.pascal.PascalBundle; import com.siberika.idea.pascal.ide.actions.PascalDefinitionsSearch; import com.siberika.idea.pascal.lang.psi.PasEntityScope; import com.siberika.idea.pascal.lang.psi.PasExportedRoutine; import com.siberika.idea.pascal.lang.psi.PasInvalidScopeException; import com.siberika.idea.pascal.lang.psi.PasRoutineImplDecl; import com.siberika.idea.pascal.lang.psi.PascalNamedElement; import com.siberika.idea.pascal.lang.psi.PascalStructType; import com.siberika.idea.pascal.util.EditorUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.MouseEvent; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * Author: George Bakhtadze * Date: 01/08/2015 */ public class PascalHeavyLineMarkerProvider implements LineMarkerProvider { @Nullable @Override public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { return null; } @Override public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) { try { for (PsiElement element : elements) { if (element instanceof PascalStructType) { // Goto implementations Collection<PasEntityScope> impls = PascalDefinitionsSearch.findImplementations(((PascalNamedElement) element).getNameIdentifier(), 1, 0); if (!impls.isEmpty()) { result.add(PascalLineMarkerProvider.createLineMarkerInfo((PasEntityScope) element, AllIcons.Gutter.OverridenMethod, PascalBundle.message("navigate.title.goto.subclassed"), getHandler(PascalBundle.message("navigate.title.goto.subclassed")))); } } else if ((element instanceof PasExportedRoutine) || (element instanceof PasRoutineImplDecl)) { PasEntityScope scope = ((PasEntityScope) element).getContainingScope(); if (scope instanceof PascalStructType) { Collection<PasEntityScope> inheritedScopes = new SmartList<PasEntityScope>(); PascalDefinitionsSearch.findDescendingStructs(inheritedScopes, (PascalStructType) scope, 1, 0); if (!inheritedScopes.isEmpty()) { result.add(PascalLineMarkerProvider.createLineMarkerInfo((PasEntityScope) element, AllIcons.Gutter.OverridenMethod, PascalBundle.message("navigate.title.goto.subclassed"), getHandler(PascalBundle.message("navigate.title.goto.subclassed")))); } } } } } catch (PasInvalidScopeException e) { e.printStackTrace(); } } static <T extends PasEntityScope> GutterIconNavigationHandler<T> getHandler(final String title) { return new GutterIconNavigationHandler<T>() { @Override public void navigate(MouseEvent e, final PasEntityScope elt) { if (DumbService.isDumb(elt.getProject())) { DumbService.getInstance(elt.getProject()).showDumbModeNotification(PascalBundle.message("navigate.subclassed.impossible.reindex")); return; } final PsiElementProcessor.CollectElementsWithLimit<PasEntityScope> collectProcessor = new PsiElementProcessor.CollectElementsWithLimit<PasEntityScope>(100, new THashSet<PasEntityScope>()); if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { @Override public void run() { ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { Collection<PasEntityScope> impls = PascalDefinitionsSearch.findImplementations((elt).getNameIdentifier(), 100, 0); for (PasEntityScope impl : impls) { collectProcessor.execute(impl); } } }); } }, PascalBundle.message("navigate.title.goto.subclassed.search"), true, elt.getProject(), (JComponent)e.getComponent())) { return; } List<PasEntityScope> inheritors = Arrays.asList(collectProcessor.toArray(new PasEntityScope[0])); EditorUtil.navigateTo(e, title, PascalBundle.message("navigate.info.subclassed.noitems"), inheritors); } }; } /*private static class SubclassUpdater extends ListBackgroundUpdaterTask { private final PasEntityScope myClass; private final PsiElementListCellRenderer myRenderer; public SubclassUpdater(PasEntityScope aClass, PsiElementListCellRenderer renderer) { super(aClass.getProject(), "Searching..."); myClass = aClass; myRenderer = renderer; } @Override public String getCaption(int size) { return "---getCaption"; } @Override public void run(@NotNull final ProgressIndicator indicator) { super.run(indicator); ClassInheritorsSearch.search(myClass, ApplicationManager.getApplication().runReadAction(new Computable<SearchScope>() { @Override public SearchScope compute() { return myClass.getUseScope(); } }), true).forEach(new CommonProcessors.CollectProcessor<PsiClass>() { @Override public boolean process(final PsiClass o) { if (!updateComponent(o, myRenderer.getComparator())) { indicator.cancel(); } indicator.checkCanceled(); return super.process(o); } }); FunctionalExpressionSearch.search(myClass).forEach(new CommonProcessors.CollectProcessor<PsiFunctionalExpression>() { @Override public boolean process(final PsiFunctionalExpression expr) { if (!updateComponent(expr, myRenderer.getComparator())) { indicator.cancel(); } indicator.checkCanceled(); return super.process(expr); } }); } }*/ }