All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.semantictools.uml.graphics.ClassDiagram Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright 2012 Pearson Education
 * 
 * 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.semantictools.uml.graphics;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.List;

import org.semantictools.frame.model.Encapsulation;
import org.semantictools.frame.model.Field;
import org.semantictools.graphics.Arc;
import org.semantictools.graphics.ArcEnd;
import org.semantictools.graphics.GraphicsUtil;
import org.semantictools.graphics.HorizontalPanel;
import org.semantictools.graphics.Label;
import org.semantictools.graphics.Rect;
import org.semantictools.graphics.Style;
import org.semantictools.graphics.VerticalPanel;
import org.semantictools.graphics.Widget;
import org.semantictools.graphics.WidgetTransformer;
import org.semantictools.uml.model.UmlAssociation;
import org.semantictools.uml.model.UmlAssociationEnd;
import org.semantictools.uml.model.UmlClass;

public class ClassDiagram {
  
  private Style classStyle;
  private Style arcStyle;
  private Style classNameStyle;
  private Style fieldStyle;
  private Style classBodyStyle;
  private Style imageStyle;
  
  private UmlClass umlClass;
  private ClassWidget classWidget;
  private VerticalPanel childrenPanel;
  private VerticalPanel parentPanel;
  private HorizontalPanel superTypePanel;
  private HorizontalPanel subtypePanel;
  private BufferedImage image;
  private int width;
  private int height;
  private int dx;
  private int dy;
  
  private int maxChildArcWidth;
  private int maxParentArcWidth;
  private int generalizationArrowLength = 50;
  
  
  
  public ClassDiagram(UmlClass type) {
    umlClass = type;
    createStyles();
    
    Label classLabel = new Label(type.getLocalName(), classNameStyle);
    classWidget = new ClassWidget(classLabel, classStyle);
    childrenPanel = new VerticalPanel();
    
    dx = imageStyle.getMarginLeft();
    dy = imageStyle.getMarginTop();
    addFields();
    addChildren();
    addParents();
    addSupertypes();
    addSubtypes();
    layout();


    image = new BufferedImage(width+1, height+1, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    g.setRenderingHint(
        RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    paint(g);

  }
  
  private void addFields() {
    List list = umlClass.getFieldList();
    for (Field field : list) {
      String name = field.getLocalName();
      String type = field.getType().getLocalName();
      String multiplicity = field.getMultiplicity();
      String text = name + ": " + type + "[" + multiplicity + "]";
      Label label = new Label(text, fieldStyle);
      classWidget.addField(label);
    }
    
    if (!list.isEmpty()) {
      classWidget.getBody().setStyle(classBodyStyle);
    }
    
  }

  private void addSubtypes() {

    List list = umlClass.getSubtypeList();
    
    
    if (list.isEmpty()) return;
    
    subtypePanel = new HorizontalPanel();
    
    for (UmlClass subtype : list) {
      
      Label label = new Label(subtype.getLocalName(), classNameStyle);
      ClassWidget subWidget = new ClassWidget(label, classStyle);
      
      subtypePanel.add(subWidget);
      
      
      
      ArcEnd selfEnd = new ArcEnd(null, null, arcStyle);
      
      ArcEnd otherEnd = new ArcEnd(null, null, arcStyle);
      selfEnd.setShape(ArcEnd.TRIANGLE);
      
      new Arc(selfEnd, otherEnd);
      
      classWidget.addBottomArc(selfEnd);
      subWidget.addTopArc(otherEnd);
      
      
    }
  }
  
  
  private void addSupertypes() {

    List list = umlClass.getSupertypeList();
    
    
    if (list.isEmpty()) return;
    
    superTypePanel = new HorizontalPanel();
    
    for (UmlClass supertype : list) {
      
      Label label = new Label(supertype.getLocalName(), classNameStyle);
      ClassWidget superWidget = new ClassWidget(label, classStyle);
      
      superTypePanel.add(superWidget);
      
      
      
      ArcEnd selfEnd = new ArcEnd(null, null, arcStyle);
      
      ArcEnd otherEnd = new ArcEnd(null, null, arcStyle);
      otherEnd.setShape(ArcEnd.TRIANGLE);
      
      new Arc(selfEnd, otherEnd);
      
      classWidget.addTopArc(selfEnd);
      superWidget.addBottomArc(otherEnd);
      
      
    }
    
  }

  public BufferedImage getImage() {
    return image;
  }


  private void layout() {
    performInitialLayout();
    performFinalLayout();
    setEndWidths();
    performFinalLayout();
    setDimensions();
    
  }
  
  private void setDimensions() {
    
    width = 0;
    height = 0;
    
    updateDimensions(classWidget);
    updateDimensions(childrenPanel);
    updateDimensions(subtypePanel);
    updateDimensions(parentPanel);
    updateDimensions(superTypePanel);
    
    width = imageStyle.getMarginLeft() + width + imageStyle.getMarginRight() + 1;
    height = imageStyle.getMarginTop() + height + imageStyle.getMarginBottom() + 1;
    
  }

  private void updateDimensions(Widget widget) {
    if (widget == null) return;
    width = Math.max(width, widget.getBounds().getRight());
    height = Math.max(height, widget.getBounds().getBottom());
    
  }

  private void setEndWidths() {
    classWidget.setEndWidths(classWidget.listLeftArcs());
    classWidget.setEndWidths(classWidget.listRightArcs());
  }

  static class Bounds {
    int top=0;
    int left=0;
    int right=0;
    int bottom=0;
    
    void apply(Widget widget) {
      if (widget != null) {
        Rect r = widget.getBounds();
        top = Math.min(top, r.getTop());
        left = Math.min(left, r.getLeft());
        right = Math.max(right, r.getRight());
        bottom = Math.max(bottom, r.getBottom());
      }
    }
    
    
  }
  
  
  private void performFinalLayout() {
    
    dx = 0;
    dy = 0;

    maxChildArcWidth = 0;
    maxParentArcWidth = 0;
    
    placeClassWidget();
    placeChildrenPanel();
    placeParentPanel();
    placeSuperTypePanel();
    placeSubtypePanel();
    
    Bounds bounds = new Bounds();
    bounds.apply(classWidget);
    bounds.apply(superTypePanel);
    bounds.apply(childrenPanel);
    bounds.apply(parentPanel);
    bounds.apply(subtypePanel);
    
    width = imageStyle.getMarginLeft() + bounds.right - bounds.left + imageStyle.getMarginRight() + 1;
    height = imageStyle.getMarginTop() +  bounds.bottom - bounds.top + imageStyle.getMarginBottom() + 1;
    
    if (bounds.left<0) {
      dx = -bounds.left;
    }
    if (bounds.top<0) {
      dy = -bounds.top;
    }
    
    dx += imageStyle.getMarginLeft();
    dy += imageStyle.getMarginTop();
    
    maxChildArcWidth = 0;
    maxParentArcWidth = 0;
    
    placeClassWidget();
    placeChildrenPanel();
    placeParentPanel();
    placeSuperTypePanel();
    placeSubtypePanel();
    
    
  }

  private int getMaxChildArcWidth() {

    if (maxChildArcWidth == 0) {
      int leftWidth = 0;
      int rightWidth = 0;
      
      List childList = classWidget.listRightArcs();
      if (childList != null) {
        for (ArcEnd end : childList) {
          Arc arc = end.getArc();
          int a = arc.getEnds()[0].getBounds().getWidth();
          leftWidth = Math.max(leftWidth, a);
          
          int b = arc.getEnds()[1].getBounds().getWidth();
          rightWidth = Math.max(rightWidth, b);
          
        }
        maxChildArcWidth = leftWidth + rightWidth;
      }
    }
    
    return maxChildArcWidth;
    
  }

  private int getMaxParentArcWidth() {

    if (maxParentArcWidth == 0) {
      int leftWidth = 0;
      int rightWidth = 0;
      
      List parentList = classWidget.listLeftArcs();
      if (parentList != null) {
        for (ArcEnd end : parentList) {
          Arc arc = end.getArc();
          int a = arc.getEnds()[0].getBounds().getWidth();
          leftWidth = Math.max(leftWidth, a);
          
          int b = arc.getEnds()[1].getBounds().getWidth();
          rightWidth = Math.max(rightWidth, b);
          
        }
        maxParentArcWidth = leftWidth + rightWidth;
      }
    }
    
    return maxParentArcWidth;
    
  }

  private void performInitialLayout() {

    int marginLeft = imageStyle.getMarginLeft();
    int marginTop = imageStyle.getMarginTop();
    int marginRight = imageStyle.getMarginRight();
    int marginBottom = imageStyle.getMarginBottom();
    

    int dy=marginTop;
    classWidget.setPosition(marginLeft, marginTop);
    classWidget.layout();
    
    if (superTypePanel != null) {
      
      superTypePanel.setPosition(marginLeft, marginTop);
      superTypePanel.layout();
      
      WidgetTransformer t = new WidgetTransformer(superTypePanel);
      classWidget.setTop(dy = t.getBottom() + generalizationArrowLength);
      
    }
    
    if (parentPanel != null) {
      
      parentPanel.setPosition(marginLeft, dy);
      parentPanel.layout();
      classWidget.setLeft(600); 
      height = Math.max(height, parentPanel.getBottom());
    }
    
    
    width = classWidget.getRight();
    height = classWidget.getBottom();
    
    if (childrenPanel != null) {
      WidgetTransformer t = new WidgetTransformer(classWidget);
      
      childrenPanel.setPosition(t.getRight() + 100, marginTop);
      childrenPanel.layout();
      
      t.set(childrenPanel);
      
      
      width = t.getWidth();
      
      height = Math.max(height, t.getBottom());
    }
    
    if (subtypePanel != null) {
      int top = height + generalizationArrowLength;
      int left = classWidget.getLeft();
      
      subtypePanel.setPosition(left, top);
      subtypePanel.layout();
      height = subtypePanel.getBottom();
    }
    
    width += marginLeft + marginRight;
    height += marginTop + marginBottom;
    
  }

  private void paint(Graphics2D g) {
    
    GraphicsUtil.paint(g, classWidget);
    GraphicsUtil.paint(g, superTypePanel);
    GraphicsUtil.paint(g, childrenPanel);
    GraphicsUtil.paint(g, parentPanel);
    GraphicsUtil.paint(g,  subtypePanel);
    classWidget.paintArcs(g, classWidget.listRightArcs());
    classWidget.paintArcs(g, classWidget.listTopArcs());
    classWidget.paintArcs(g, classWidget.listLeftArcs());
    classWidget.paintArcs(g, classWidget.listBottomArcs());
    
  }

  private void addParents() {

    List list = umlClass.getParentList();
    
    if (list.isEmpty()) return;
    
    parentPanel = new VerticalPanel();
    
    UmlClass priorParent = null;
    ClassWidget priorWidget = null;
    
    for (UmlAssociation a : list) {
     
      UmlClass peer = a.getOtherEnd(umlClass).getParticipant();
      Label label = new Label(peer.getLocalName(), classNameStyle);
      
      ClassWidget otherWidget = (peer == priorParent) ? priorWidget : new ClassWidget(label, classStyle);
      
      if (otherWidget != priorWidget) {
        parentPanel.add(otherWidget);
      }
      priorParent = peer;
      priorWidget = otherWidget;
      
      UmlAssociationEnd myEnd = a.getSelfEnd(umlClass);
      UmlAssociationEnd parentEnd = a.getOtherEnd(umlClass);
      
      ArcEnd selfEnd = new ArcEnd(myEnd.getLocalName(), myEnd.getMultiplicity(), arcStyle);
      setEndShape(selfEnd, myEnd.getEncapsulation());
      
      ArcEnd otherEnd = new ArcEnd(parentEnd.getLocalName(), parentEnd.getMultiplicity(), arcStyle);
      setEndShape(otherEnd, parentEnd.getEncapsulation());
      new Arc(selfEnd, otherEnd);
      
      classWidget.addLeftArc(selfEnd);
      otherWidget.addRightArc(otherEnd);
      
      
    }
  }
  
  private void addChildren() {
   
    List list = umlClass.getChildren();
    
    if (list.isEmpty()) return;
    
    childrenPanel = new VerticalPanel();
    
    UmlClass priorClass = null;
    ClassWidget priorWidget = null;
    for (UmlAssociation a : list) {

      UmlAssociationEnd classEnd = a.getSelfEnd(umlClass);
      UmlAssociationEnd fieldEnd = a.getOtherEnd(umlClass);
      
      UmlClass fieldClass = a.getOtherEnd(umlClass).getParticipant();
      
      UmlClass peer = fieldEnd.getParticipant();
      Label label = new Label(peer.getLocalName(), classNameStyle);
      
      ClassWidget otherWidget = (priorClass == fieldClass) ? priorWidget :   new ClassWidget(label, classStyle);
      
      
      if (otherWidget != priorWidget) {
        childrenPanel.add(otherWidget);
      }

      priorClass = fieldClass;
      priorWidget = otherWidget;
      
      ArcEnd selfEnd = new ArcEnd(classEnd.getLocalName(), classEnd.getMultiplicity(), arcStyle);
      setEndShape(selfEnd, classEnd.getEncapsulation());
      
      ArcEnd otherEnd = new ArcEnd(fieldEnd.getLocalName(), fieldEnd.getMultiplicity(), arcStyle);
      setEndShape(otherEnd, fieldEnd.getEncapsulation());
      
      new Arc(selfEnd, otherEnd);
      
      classWidget.addRightArc(selfEnd);
      otherWidget.addLeftArc(otherEnd);
      
      
    }
    
    
    
  }


  private void setEndShape(ArcEnd end, Encapsulation e) {
    switch (e) {
    case AGGREGATION :
      end.setShape(ArcEnd.DIAMOND);
      break;
      
    case COMPOSITION :
      end.setShape(ArcEnd.DIAMOND);
      end.setFilled(true);
      break;
    }
    
  }

  private void createStyles() {
    
    if (imageStyle == null) {
      imageStyle = new Style();
      imageStyle.setMarginTop(5);
      imageStyle.setMarginBottom(5);
      imageStyle.setMarginLeft(5);
      imageStyle.setMarginRight(5);
    }
    if (classStyle == null) {
      
      classStyle = new Style();
      classStyle.setBgColor(new Color(1f, 1f, 0.7226562f));
      classStyle.setBorderColor(new Color(0.5f, 0.0f, 0.0f));
      classStyle.setMarginTop(15);
      classStyle.setMarginBottom(15);
      classStyle.setMarginLeft(15);
      classStyle.setMarginRight(15);
      
    }
    if (classBodyStyle == null) {
      classBodyStyle = new Style();
      classBodyStyle.setPadBottom(3);
    }
    
    if (fieldStyle == null) {
      fieldStyle = new Style();
      fieldStyle.setFont(new Font("Arial", Font.PLAIN, 11));
      fieldStyle.setPadBottom(1);
      fieldStyle.setPadTop(1);
      fieldStyle.setPadLeft(5);
      fieldStyle.setPadRight(5);
    }
    
    if (arcStyle == null) {
      arcStyle = new Style();
      arcStyle.setBorderColor(new Color(0.5f, 0.0f, 0.0f));
      arcStyle.setColor(Color.black);
      arcStyle.setFont(new Font("Arial", Font.PLAIN, 11));
      arcStyle.setPadBottom(3);
      arcStyle.setPadTop(3);
      arcStyle.setPadLeft(5);
      arcStyle.setPadRight(5);
      arcStyle.setMarginTop(10);
      arcStyle.setMarginBottom(10);
      
    }
    
    if (classNameStyle == null) {
      classNameStyle = new Style();
      classNameStyle.setColor(Color.black);
      classNameStyle.setFont(new Font("Arial", Font.BOLD, 12));
      classNameStyle.setPadTop(3);
      classNameStyle.setPadBottom(3);
      classNameStyle.setPadLeft(5);
      classNameStyle.setPadRight(5);
    }

    BufferedImage image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    setMetrics(arcStyle, g);
    setMetrics(classNameStyle, g);
    setMetrics(fieldStyle, g);
  }


  private void setMetrics(Style style, Graphics2D g) {
    if (style.getMetrics() != null || style.getFont()==null) return;
    
    
    Font font = style.getFont();
    FontMetrics metrics = g.getFontMetrics(font);
    style.setMetrics(metrics);
    
  }
  
  
  private void placeClassWidget() {
    classWidget.setPosition(dx, dy);
  }
  
  private void placeParentPanel() {
    if (parentPanel == null) return;
    
    int middle = classWidget.getTop() + classWidget.getHeight()/2;
    int left = classWidget.getLeft() - getMaxParentArcWidth() - parentPanel.getWidth();
    int top = middle - parentPanel.getHeight()/2;
    
    parentPanel.setPosition(left, top);
    
  }
  
  private void placeChildrenPanel() {
    if (childrenPanel == null) return;
    int dx = getMaxChildArcWidth();
    int middle = classWidget.getTop() + classWidget.getHeight()/2;
    int left = classWidget.getRight() + dx;
    int top = middle - childrenPanel.getHeight()/2;
    
    childrenPanel.setPosition(left, top);
    
  }
  
  private void placeSuperTypePanel() {
    if (superTypePanel == null) return;
    
    int center = classWidget.getLeft() + classWidget.getWidth()/2;
    
    int left = center - superTypePanel.getWidth()/2;
    int top = classWidget.getTop() - generalizationArrowLength - superTypePanel.getHeight();
    
    superTypePanel.setPosition(left, top);
  }
  



  private void placeSubtypePanel() {
    if (subtypePanel == null) return;
    
    int center = classWidget.getLeft() + classWidget.getWidth()/2;
    int left = center - subtypePanel.getWidth()/2;
    int top = classWidget.getBottom() + generalizationArrowLength;
    
    subtypePanel.setPosition(left, top);
    
  }
  

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy