Package org.intellij.grammar.diagram

Source Code of org.intellij.grammar.diagram.BnfDiagramProvider$MyDataModel

/*
* Copyright 2011-2014 Gregory Shrago
*
* 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 org.intellij.grammar.diagram;

import com.intellij.diagram.*;
import com.intellij.diagram.extras.DiagramExtras;
import com.intellij.diagram.presentation.DiagramLineType;
import com.intellij.diagram.presentation.DiagramState;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiNamedElement;
import com.intellij.ui.SimpleColoredText;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.intellij.grammar.KnownAttribute;
import org.intellij.grammar.generator.RuleGraphHelper;
import org.intellij.grammar.psi.BnfFile;
import org.intellij.grammar.psi.BnfRule;
import org.intellij.lang.annotations.Pattern;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;

import static org.intellij.grammar.generator.ParserGeneratorUtil.getAttribute;

/**
* @author gregsh
*/
public class BnfDiagramProvider extends DiagramProvider<PsiNamedElement> {
  public static final String ID = "GRAMMAR";
  private final DiagramVisibilityManager myVisibilityManager = new EmptyDiagramVisibilityManager();

  private static final DiagramCategory[] CATEGORIES = new DiagramCategory[]{new DiagramCategory("Properties", PlatformIcons.PROPERTY_ICON, true)};
  private final DiagramNodeContentManager myNodeContentManager = new AbstractDiagramNodeContentManager() {

    @Override
    public boolean isInCategory(Object o, DiagramCategory diagramCategory, DiagramState diagramState) {
      return true;
    }

    @Override
    public DiagramCategory[] getContentCategories() {
      return CATEGORIES;
    }
  };
  private final DiagramElementManager myElementManager = new AbstractDiagramElementManager<PsiNamedElement>() {
    @Override
    public PsiNamedElement findInDataContext(DataContext context) {
      PsiFile file = LangDataKeys.PSI_FILE.getData(context);
      return file instanceof BnfFile ? file : null;
    }

    @Override
    public boolean isAcceptableAsNode(Object o) {
      return o instanceof PsiNamedElement;
    }

    @Override
    public String getElementTitle(PsiNamedElement bnfFile) {
      return bnfFile.getName();
    }

    @Override
    public SimpleColoredText getItemName(Object o, DiagramState diagramState) {
      if (o instanceof Map.Entry) o = ((Map.Entry)o).getKey();
      if (o instanceof PsiNamedElement) {
        return new SimpleColoredText(StringUtil.notNullize(((PsiNamedElement)o).getName()), DEFAULT_TITLE_ATTR);
      }
      return null;
    }

    @Override
    public Object[] getNodeItems(PsiNamedElement parent) {
      if (parent instanceof BnfRule) {
        Map<PsiElement, RuleGraphHelper.Cardinality> map = myGraphHelper.getFor((BnfRule)parent);
        Object[] objects = ContainerUtil.findAll(map.entrySet(), new Condition<Map.Entry<PsiElement, RuleGraphHelper.Cardinality>>() {
          @Override
          public boolean value(Map.Entry<PsiElement, RuleGraphHelper.Cardinality> p) {
            return p.getKey() instanceof BnfRule;
          }
        }).toArray();
        Arrays.sort(objects, new Comparator<Object>() {
          @Override
          public int compare(Object o, Object o1) {
            return Comparing.compare(((Map.Entry<BnfRule, ?>)o).getKey().getName(), ((Map.Entry<BnfRule, ?>)o1).getKey().getName());
          }
        });
        return objects;
      }
      return super.getNodeItems(parent);
    }

    @Override
    public SimpleColoredText getItemType(Object element) {
      if (element instanceof Map.Entry) {
        RuleGraphHelper.Cardinality cardinality = (RuleGraphHelper.Cardinality)((Map.Entry)element).getValue();
        String text = RuleGraphHelper.getCardinalityText(cardinality);
        if (StringUtil.isNotEmpty(text)) {
          return new SimpleColoredText(" "+text+" ", SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES);
        }
      }
      return super.getItemType(element);
    }

    @Override
    public Icon getItemIcon(Object element, DiagramState presentation) {
      if (element instanceof Map.Entry) element = ((Map.Entry)element).getKey();
      return super.getItemIcon(element, presentation);
    }

    @Override
    public String getNodeTooltip(PsiNamedElement bnfFile) {
      return null;
    }
  };

  private final DiagramVfsResolver myVfsResolver = new DiagramVfsResolver<PsiNamedElement>() {
    @Override
    public String getQualifiedName(PsiNamedElement bnfFile) {
      VirtualFile virtualFile = bnfFile instanceof PsiFile ? ((PsiFile)bnfFile).getVirtualFile() : null;
      return virtualFile == null? null : virtualFile.getUrl();
    }

    @Override
    public PsiNamedElement resolveElementByFQN(String s, Project project) {
      VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(s);
      PsiFile psiFile = virtualFile == null? null : PsiManager.getInstance(project).findFile(virtualFile);
      return psiFile instanceof BnfFile? psiFile : null;
    }
   
  };
  private final DiagramRelationshipManager myRelationshipManager = new DiagramRelationshipManager<PsiNamedElement>() {
    @Override
    public DiagramRelationshipInfo getDependencyInfo(PsiNamedElement e1, PsiNamedElement e2, DiagramCategory diagramCategory) {
      return null;
    }

    @Override
    public DiagramCategory[] getContentCategories() {
      return CATEGORIES;
    }
  };
  private final DiagramExtras myExtras = new DiagramExtras();
  private RuleGraphHelper myGraphHelper;

  public BnfDiagramProvider() {
    myElementManager.setUmlProvider(this);
  }

  @Pattern("[a-zA-Z0-9_-]*")
  @Override
  public String getID() {
    return ID;
  }

  @Override
  public DiagramVisibilityManager createVisibilityManager() {
    return myVisibilityManager;
  }

  @Override
  public DiagramNodeContentManager getNodeContentManager() {
    return myNodeContentManager;
  }

  @Override
  public DiagramElementManager<PsiNamedElement> getElementManager() {
    return myElementManager;
  }

  @Override
  public DiagramVfsResolver<PsiNamedElement> getVfsResolver() {
    return myVfsResolver;
  }

  @Override
  public DiagramRelationshipManager<PsiNamedElement> getRelationshipManager() {
    return myRelationshipManager;
  }

  @Override
  public DiagramDataModel<PsiNamedElement> createDataModel(@NotNull final Project project,
                                                   @Nullable final PsiNamedElement element,
                                                   @Nullable final VirtualFile file,
                                                   DiagramPresentationModel presentationModel) {
    return new MyDataModel(project, (BnfFile)element, this);
  }

  @NotNull
  @Override
  public DiagramExtras getExtras() {
    return myExtras;
  }

  @Override
  public String getActionName(boolean isPopup) {
    return "Visualisation";
  }

  @Override
  public String getPresentableName() {
    return "Grammar Diagrams";
  }

  private static class MyDataModel extends DiagramDataModel<PsiNamedElement> implements ModificationTracker {

    private final BnfFile myFile;

    private final Collection<DiagramNode<PsiNamedElement>> myNodes = new HashSet<DiagramNode<PsiNamedElement>>();
    private final Collection<DiagramEdge<PsiNamedElement>> myEdges = new HashSet<DiagramEdge<PsiNamedElement>>();


    MyDataModel(Project project, BnfFile file, BnfDiagramProvider provider) {
      super(project, provider);
      myFile = file;
    }

    @NotNull
    @Override
    public Collection<DiagramNode<PsiNamedElement>> getNodes() {
      return myNodes;
    }

    @NotNull
    @Override
    public Collection<DiagramEdge<PsiNamedElement>> getEdges() {
      return myEdges;
    }

    @NotNull
    @Override
    public String getNodeName(DiagramNode<PsiNamedElement> node) {
      return StringUtil.notNullize(node.getTooltip());
    }

    @Override
    public DiagramNode<PsiNamedElement> addElement(PsiNamedElement psiElement) {
      return null;
    }

    @Override
    public void refreshDataModel() {
      myNodes.clear();
      myEdges.clear();

      RuleGraphHelper ruleGraphHelper = RuleGraphHelper.getCached(myFile);
      ((BnfDiagramProvider)getProvider()).myGraphHelper = ruleGraphHelper;

      Map<BnfRule, DiagramNode<PsiNamedElement>> nodeMap = new THashMap<BnfRule, DiagramNode<PsiNamedElement>>();
      List<BnfRule> rules = myFile.getRules();
      BnfRule root = ContainerUtil.getFirstItem(rules);
      for (BnfRule rule : rules) {
        if (rule != root && !RuleGraphHelper.shouldGeneratePsi(rule, true)) continue;
        DiagramNode<PsiNamedElement> diagramNode = new PsiDiagramNode<PsiNamedElement>(rule, getProvider()) {
          @Override
          public String getTooltip() {
            return getIdentifyingElement().getName();
          }
        };
        nodeMap.put(rule, diagramNode);
        myNodes.add(diagramNode);
      }
      for (BnfRule rule : rules) {
        if (rule != root && !RuleGraphHelper.shouldGeneratePsi(rule, true)) continue;
        Map<PsiElement, RuleGraphHelper.Cardinality> map = ruleGraphHelper.getFor(rule);

        BnfRule superRule = myFile.getRule(getAttribute(rule, KnownAttribute.EXTENDS));
        if (superRule != null) {
          DiagramNode<PsiNamedElement> source = nodeMap.get(rule);
          DiagramNode<PsiNamedElement> target = nodeMap.get(superRule);

          myEdges.add(new DiagramEdgeBase<PsiNamedElement>(source, target, new DiagramRelationshipInfoAdapter("EXTENDS", DiagramLineType.DASHED, "extends") {

              public Shape getStartArrow() {
                return DELTA;
              }
            }) {

              @Override
              public String getName() {
                return "";
              }
            });
        }
        for (final PsiElement element : map.keySet()) {
          if (!(element instanceof BnfRule)) continue;
          final RuleGraphHelper.Cardinality cardinality = map.get(element);
          assert cardinality != RuleGraphHelper.Cardinality.NONE;

          DiagramNode<PsiNamedElement> source = nodeMap.get(rule);
          DiagramNode<PsiNamedElement> target = nodeMap.get(element);
          myEdges.add(new DiagramEdgeBase<PsiNamedElement>(source, target, new DiagramRelationshipInfoAdapter("CONTAINS", DiagramLineType.SOLID, "") {
            @Override
            public String getLabel() {
              return cardinality.name().toLowerCase();
            }

            public Shape getStartArrow() {
              return DELTA;
            }
          } ) {

            @Override
            public Object getSourceAnchor() {
              return element;
            }

            @Override
            public Object getTargetAnchor() {
              return element;
            }

            @Override
            public Color getAnchorColor() {
              return Color.BLUE;
            }

            @Override
            public String getName() {
              return "";
            }
          });
        }
      }
    }

    @NotNull
    @Override
    public ModificationTracker getModificationTracker() {
      return this;
    }

    @Override
    public void dispose() {
    }

    @Override
    public long getModificationCount() {
      return myFile.getModificationStamp();
    }
  }
}
TOP

Related Classes of org.intellij.grammar.diagram.BnfDiagramProvider$MyDataModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.