/* * 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. */ package com.jetbrains.lang.dart.ide.marker; import com.google.common.collect.Lists; import com.intellij.codeHighlighting.Pass; import com.intellij.codeInsight.daemon.DaemonBundle; import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.codeInsight.daemon.LineMarkerProvider; import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; import com.intellij.icons.AllIcons; import com.intellij.ide.util.DefaultPsiElementCellRenderer; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.lang.dart.DartBundle; import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService; import com.jetbrains.lang.dart.analyzer.DartServerData; import com.jetbrains.lang.dart.ide.hierarchy.DartHierarchyUtil; import com.jetbrains.lang.dart.psi.DartClass; import com.jetbrains.lang.dart.psi.DartComponent; import com.jetbrains.lang.dart.psi.DartComponentName; import com.jetbrains.lang.dart.util.DartResolveUtil; import org.dartlang.analysis.server.protocol.OverriddenMember; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collection; import java.util.List; public class DartServerOverrideMarkerProvider implements LineMarkerProvider { @Override public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) { } @Override public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { if (!(element instanceof DartComponentName)) { return null; } final PsiElement parent = element.getParent(); if (parent instanceof DartComponent) { final DartClass dartClass = PsiTreeUtil.getParentOfType(element, DartClass.class); return dartClass == null ? null : createOverrideMarker((DartComponentName)element); } return null; } private static void addDartComponent(List<DartComponent> components, Project project, OverriddenMember member) { final DartComponent component = member == null ? null : DartHierarchyUtil.findDartComponent(project, member.getElement().getLocation()); if (component != null) { components.add(component); } } @Nullable private static LineMarkerInfo createOverrideMarker(DartComponentName componentName) { final VirtualFile virtualFile = componentName.getContainingFile().getVirtualFile(); if (virtualFile == null || !virtualFile.isInLocalFileSystem()) { return null; } final List<DartServerData.DartOverrideMember> overrideMembers = DartAnalysisServerService.getInstance(componentName.getProject()).getOverrideMembers(virtualFile); final Project project = componentName.getProject(); final int nameOffset = componentName.getTextRange().getStartOffset(); DartComponent superclassComponent = null; List<DartComponent> interfaceComponents = Lists.newArrayList(); for (DartServerData.DartOverrideMember overrideMember : overrideMembers) { if (overrideMember.getOffset() == nameOffset) { final OverriddenMember member = overrideMember.getSuperclassMember(); superclassComponent = member == null ? null : DartHierarchyUtil.findDartComponent(project, member.getElement().getLocation()); if (overrideMember.getInterfaceMembers() != null) { for (OverriddenMember overriddenMember : overrideMember.getInterfaceMembers()) { addDartComponent(interfaceComponents, project, overriddenMember); } } } } return tryCreateOverrideMarker(componentName, superclassComponent, interfaceComponents); } @Nullable private static LineMarkerInfo tryCreateOverrideMarker(@NotNull final DartComponentName componentName, @Nullable final DartComponent superclassComponent, @NotNull final List<DartComponent> interfaceComponents) { if (superclassComponent == null && interfaceComponents.isEmpty()) { return null; } final String name = componentName.getName(); final boolean overrides; final DartComponent superComponent; if (superclassComponent != null) { overrides = true; superComponent = superclassComponent; } else { overrides = false; superComponent = interfaceComponents.iterator().next(); } final Icon icon = overrides ? AllIcons.Gutter.OverridingMethod : AllIcons.Gutter.ImplementingMethod; return new LineMarkerInfo<>(componentName, componentName.getTextRange(), icon, Pass.LINE_MARKERS, element -> { final DartClass superClass = PsiTreeUtil.getParentOfType(superComponent, DartClass.class); if (superClass == null) return "null"; if (overrides) { return DartBundle.message(superclassComponent.isOperator() ? "overrides.operator.in" : "overrides.method.in", name, superClass.getName()); } return DartBundle.message("implements.method.in", name, superClass.getName()); }, (GutterIconNavigationHandler<PsiElement>)(e, elt) -> { List<DartComponent> superComponents = Lists.newArrayList(); if (superclassComponent != null) { superComponents.add(superclassComponent); } superComponents.addAll(interfaceComponents); PsiElementListNavigator.openTargets(e, DartResolveUtil.getComponentNameArray(superComponents), DaemonBundle.message("navigation.title.super.method", name), DaemonBundle.message("navigation.findUsages.title.super.method", name), new DefaultPsiElementCellRenderer()); }, GutterIconRenderer.Alignment.LEFT); } }