/******************************************************************************* * Copyright (c) 2010-2015 Henshin developers. All rights reserved. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * TU Berlin, University of Luxembourg, SES S.A. *******************************************************************************/ package de.tub.tfs.henshin.tggeditor.editparts.graphical; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Vector; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.ConnectionLayer; import org.eclipse.draw2d.ConnectionRouter; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FreeformLayer; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.RectangleFigure; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.henshin.model.HenshinPackage; import org.eclipse.gef.EditPolicy; import org.eclipse.gef.LayerConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.TextLayout; import org.eclipse.swt.widgets.Display; import de.tub.tfs.henshin.tgg.TGG; import de.tub.tfs.henshin.tgg.TggPackage; import de.tub.tfs.henshin.tgg.TripleGraph; import de.tub.tfs.henshin.tggeditor.editpolicies.graphical.GraphXYLayoutEditPolicy; import de.tub.tfs.henshin.tggeditor.figures.EdgeConnectionRouter; import de.tub.tfs.henshin.tggeditor.ui.TGGEditorConstants; import de.tub.tfs.henshin.tggeditor.util.GraphUtil; import de.tub.tfs.henshin.tggeditor.util.GraphicalNodeUtil; import de.tub.tfs.muvitor.gef.editparts.AdapterGraphicalEditPart; /** * The Class GraphEditPart. */ public class GraphEditPart extends AdapterGraphicalEditPart<TripleGraph> { //private static Font f = new Font(null, java.awt.Font.MONOSPACED, 20, SWT.BOLD); /** The name label */ protected Label nameLabel; /** The Layout system */ protected TGG tgg; /** The triple graph with dividers */ protected TripleGraph tripleGraph; public TripleGraph getTripleGraph() { return tripleGraph; } public void setTripleGraph(TripleGraph tripleGraph) { this.tripleGraph = tripleGraph; } /** The edit parts of dividers */ protected Divider divSC, divCT; public DividerEditPart dividerSCpart, dividerCTpart; public DividerEditPart getDividerCTpart() { return dividerCTpart; } public void setDividerCTpart(DividerEditPart dividerCTpart) { this.dividerCTpart = dividerCTpart; } public DividerEditPart getDividerSCpart() { return dividerSCpart; } public void setDividerSCpart(DividerEditPart dividerSCpart) { this.dividerSCpart = dividerSCpart; } /** The current height of visual display of model */ protected int height; /** * Instantiates a new graph edit part. * * @param model the model */ public GraphEditPart(TripleGraph model) { super(model); tripleGraph=model; tgg = GraphicalNodeUtil.getLayoutSystem(getCastedModel()); divSC = new Divider(tripleGraph,true); divCT = new Divider(tripleGraph,false); initDividers(); } /** * Generates dividers graph layouts of this graph if not already created and saves them in * divSC and divCT. */ private void initDividers() { if(tripleGraph.getDividerSC_X()==0) tripleGraph.setDividerSC_X(GraphUtil.center - GraphUtil.correstpondenceWidth/2); if(tripleGraph.getDividerCT_X()==0) tripleGraph.setDividerCT_X(GraphUtil.center + GraphUtil.correstpondenceWidth/2); } public Rectangle getCorrectedBounds(Rectangle rect,List<Figure> figures,HashSet<Class<? extends Figure>> skip){ rect = new Rectangle(rect); int maxY = 0; int maxX = 0; //System.out.println(rect); for (Figure figure : figures) { if (skip.contains(figure.getClass())) continue; Rectangle r = figure.getBounds(); if (r.x + r.width > maxX) maxX = r.x + r.width; if (r.y + r.height > maxY) maxY = r.y + r.height; } rect.width = maxX; rect.height = maxY; return rect; } @Override protected IFigure createFigure() { FreeformLayer layer = new FreeformLayer(){ @Override protected void paintClientArea(Graphics graphics) { super.paintClientArea(graphics); Rectangle rect = getCorrectedBounds(this.getBounds(),this.getChildren(),new HashSet<Class<? extends Figure>>(Arrays.asList(RectangleFigure.class))); if (tripleGraph.getDividerSC_X() == 0) { tripleGraph.setDividerSC_X(rect.width/2 - rect.width/8); tripleGraph.setDividerMaxY(rect.height - rect.y); tripleGraph.setDividerCT_X(rect.width/2 + rect.width/8); tripleGraph.setDividerMaxY(rect.height - rect.y); } else if (height != rect.height) { height = rect.height; if (rect.height+20-rect.y != tripleGraph.getDividerMaxY()) tripleGraph.setDividerMaxY(rect.height+20-rect.y); } else if (tripleGraph.getDividerMaxY() + rect.y > rect.height + 20) { if (rect.height + 20 - rect.y != tripleGraph.getDividerMaxY()) tripleGraph.setDividerMaxY(rect.height - 20 - rect.y); } else { if (rect.height+20 - rect.y != tripleGraph.getDividerMaxY()) tripleGraph.setDividerMaxY(rect.height+20 - rect.y); } if (rect.y != tripleGraph.getDividerYOffset()) tripleGraph.setDividerYOffset(rect.y); } @Override public void paint(Graphics graphics) { graphics.pushState(); String text = nameLabel.getText(); graphics.setForegroundColor(TGGEditorConstants.FG_STANDARD_COLOR); TextLayout textLayout = new TextLayout(null); textLayout.setText(text); textLayout.setFont(TGGEditorConstants.TEXT_TITLE_FONT); graphics.drawTextLayout(textLayout, 5, 5); textLayout.dispose(); graphics.popState(); super.paint(graphics); } }; layer.setLayoutManager(new TGGLayoutManager()); nameLabel =new Label(); nameLabel.setFont(TGGEditorConstants.TEXT_TITLE_FONT_SMALL); nameLabel.setForegroundColor(TGGEditorConstants.FG_STANDARD_COLOR); setFigureNameLabel(); //layer.add(nameLabel, new Rectangle(10,10,-1,-1)); ConnectionLayer cLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER); cLayer.setAntialias(SWT.ON); EdgeConnectionRouter edgeRouter=new EdgeConnectionRouter(layer); if (this.getCastedModel().getEdges().size() > 1000){ edgeRouter.setNextRouter(ConnectionRouter.NULL); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { MessageDialog.open(MessageDialog.INFORMATION, Display.getDefault().getActiveShell(), "Information", "The graph has too many edges. Therefore the edges will not be drawn around nodes.", SWT.SHEET); } }); } cLayer.setConnectionRouter(edgeRouter); return layer; } /** * sets the name of corresponding model into name label */ protected void setFigureNameLabel(){ String name = getCastedModel().getName()+"\n"; nameLabel.setText(name); } @Override protected void createEditPolicies() { installEditPolicy(EditPolicy.LAYOUT_ROLE, new GraphXYLayoutEditPolicy()); } @Override protected void performOpen() { // TODO Auto-generated method stub super.performOpen(); } @Override protected List<Object> getModelChildren() { List<Object> list = new Vector<Object>(getCastedModel().getNodes().size()+2); list.add(this.divSC); list.add(this.divCT); // TGG shortest path connection router has problems, if dividers are not at the beginning list.addAll(getCastedModel().getNodes()); return list; } @Override protected void notifyChanged(final Notification msg) { final int featureId = msg.getFeatureID(HenshinPackage.class); switch (featureId) { case HenshinPackage.GRAPH__NAME: setFigureNameLabel(); refreshVisuals(); break; case HenshinPackage.GRAPH__NODES: case HenshinPackage.GRAPH__EDGES: //long s = System.nanoTime(); //System.out.println("enter " +this.getClass().getName()); refreshChildren(); refreshVisuals(); //System.out.println("graph graphical update time: " + ((System.nanoTime() - s)/1000000) + " ms"); } final int featureId2 = msg.getFeatureID(TggPackage.class); switch (featureId2) { case TggPackage.TRIPLE_GRAPH__DIVIDER_SC_X: if(dividerSCpart!=null) dividerSCpart.refreshLocation(); case TggPackage.TRIPLE_GRAPH__DIVIDER_CT_X: if(dividerCTpart!=null) dividerCTpart.refreshLocation(); case TggPackage.TRIPLE_GRAPH__DIVIDER_MAX_Y: // refreshChildren(); if (this.isActive()){ refreshVisuals(); getFigure().invalidate(); } // TODO - this should be handled with refreshChildren, but notification is currently not working if(dividerSCpart!=null && dividerCTpart!=null) { dividerSCpart.refreshLocation(); dividerCTpart.refreshLocation(); } } super.notifyChanged(msg); } /** * refresh the figure of this edit part */ protected void refreshVisuals() { getFigure().setBackgroundColor(ColorConstants.white); getFigure().repaint(); } }