///******************************************************************************* // * Copyright (c) 2007, 2010 Association for Decentralized Information Management // * in Industry THTH ry. // * 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: // * VTT Technical Research Centre of Finland - initial API and implementation // *******************************************************************************/ //package org.simantics.g2d.elementclass; // //import java.awt.BasicStroke; //import java.awt.Color; //import java.awt.Font; //import java.awt.FontMetrics; //import java.awt.Graphics2D; //import java.awt.Rectangle; //import java.awt.Shape; //import java.awt.event.ActionEvent; //import java.awt.event.ActionListener; //import java.awt.geom.AffineTransform; //import java.awt.geom.Path2D; //import java.awt.geom.Point2D; //import java.awt.geom.Rectangle2D; //import java.util.EnumSet; //import java.util.Map; // //import javax.vecmath.Vector2d; // //import org.simantics.g2d.diagram.IDiagram; //import org.simantics.g2d.element.ElementClass; //import org.simantics.g2d.element.ElementHints; //import org.simantics.g2d.element.ElementUtils; //import org.simantics.g2d.element.IElement; //import org.simantics.g2d.element.SceneGraphNodeKey; //import org.simantics.g2d.element.handler.ElementHandler; //import org.simantics.g2d.element.handler.FillColor; //import org.simantics.g2d.element.handler.InternalSize; //import org.simantics.g2d.element.handler.LifeCycle; //import org.simantics.g2d.element.handler.Move; //import org.simantics.g2d.element.handler.Outline; //import org.simantics.g2d.element.handler.Rotate; //import org.simantics.g2d.element.handler.Scale; //import org.simantics.g2d.element.handler.SceneGraph; //import org.simantics.g2d.element.handler.StaticSymbol; //import org.simantics.g2d.element.handler.Text; //import org.simantics.g2d.element.handler.TextEditor; //import org.simantics.g2d.element.handler.Transform; //import org.simantics.g2d.element.handler.TextEditor.Modifier; //import org.simantics.g2d.element.handler.impl.BorderColorImpl; //import org.simantics.g2d.element.handler.impl.FillColorImpl; //import org.simantics.g2d.element.handler.impl.SimpleElementLayers; //import org.simantics.g2d.element.handler.impl.StaticSymbolImpl; //import org.simantics.g2d.element.handler.impl.TextColorImpl; //import org.simantics.g2d.element.handler.impl.TextEditorImpl; //import org.simantics.g2d.element.handler.impl.TextFontImpl; //import org.simantics.g2d.element.handler.impl.TextImpl; //import org.simantics.g2d.image.Image; //import org.simantics.g2d.image.ProviderUtils; //import org.simantics.g2d.image.impl.AbstractImage; //import org.simantics.g2d.utils.Alignment; //import org.simantics.scenegraph.Node; //import org.simantics.scenegraph.g2d.G2DParentNode; //import org.simantics.scenegraph.g2d.nodes.MonitorNode; //import org.simantics.utils.datastructures.cache.IFactory; //import org.simantics.utils.datastructures.cache.IProvider; //import org.simantics.utils.datastructures.cache.ProvisionException; //import org.simantics.utils.datastructures.hints.IHintContext.Key; //import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; //import org.simantics.utils.strings.format.MetricsFormat; //import org.simantics.utils.strings.format.MetricsFormatList; // ///** // * @author Tuukka Lehtonen // */ //public class MonitorClass { // // static final Font FONT = Font.decode("Helvetica 12"); // // /** // * Back-end specific object describing the monitored component. // */ // public static final Key KEY_MONITOR_COMPONENT = new KeyOf(Object.class, "MONITOR_COMPONENT"); // // /** // * The valuation suffix string describing the monitored variable of the // * component described by {@link #KEY_MONITOR_COMPONENT}. // */ // public static final Key KEY_MONITOR_SUFFIX = new KeyOf(String.class, "MONITOR_SUFFIX"); // // public static final Key KEY_MONITOR_SUBSTITUTIONS = new KeyOf(Map.class, "MONITOR_SUBSTITUTIONS"); // public static final Key KEY_MONITOR_GC = new KeyOf(Graphics2D.class, "MONITOR_GC"); // public static final Key KEY_MONITOR_HEIGHT = new KeyOf(Double.class, "MONITOR_HEIGHT"); // public static final Key KEY_NUMBER_FORMAT = new KeyOf(MetricsFormat.class, "NUMBER_FORMAT"); // public static final Key KEY_TOOLTIP_TEXT = new KeyOf(String.class, "TOOLTIP_TEXT"); // // /** // * If this hint is defined, the monitor will force its x-axis to match this // * angle. If this hint doesn't exist, the monitor will not force x-axis // * orientation. // */ // public static final Key KEY_DIRECTION = new KeyOf(Double.class, "MONITOR_DIRECTION"); // // public static final Key KEY_BORDER_WIDTH = new KeyOf(Double.class, "MONITOR_BORDER"); // // public static final Key KEY_SG_NODE = new SceneGraphNodeKey(Node.class, "MONITOR_SG_NODE"); // // final static BasicStroke STROKE = new BasicStroke(1.0f); // // public final static Alignment DEFAULT_HORIZONTAL_ALIGN = Alignment.CENTER; // public final static Alignment DEFAULT_VERTICAL_ALIGN = Alignment.CENTER; // public final static MetricsFormat DEFAULT_NUMBER_FORMAT = MetricsFormatList.METRICS_DECIMAL; // // public final static Color DEFAULT_FILL_COLOR = new Color(224, 224, 224); // public final static Color DEFAULT_BORDER_COLOR = Color.BLACK; // // public final static double DEFAULT_HORIZONTAL_MARGIN = 5.0; // public final static double DEFAULT_VERTICAL_MARGIN = 2.5; // // static Alignment getHorizontalAlignment(IElement e) { // return ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, DEFAULT_HORIZONTAL_ALIGN); // } // // static Alignment getVerticalAlignment(IElement e) { // return ElementUtils.getHintOrDefault(e, ElementHints.KEY_VERTICAL_ALIGN, DEFAULT_VERTICAL_ALIGN); // } // // static MetricsFormat getNumberFormat(IElement e) { // return ElementUtils.getHintOrDefault(e, KEY_NUMBER_FORMAT, DEFAULT_NUMBER_FORMAT); // } // // static void setNumberFormat(IElement e, MetricsFormat f) { // ElementUtils.setOrRemoveHint(e, KEY_NUMBER_FORMAT, f); // } // // static double getHorizontalMargin(IElement e) { // return DEFAULT_HORIZONTAL_MARGIN; // } // // static double getVerticalMargin(IElement e) { // return DEFAULT_VERTICAL_MARGIN; // } // // static Font getFont(IElement e) { // return ElementUtils.getHintOrDefault(e, ElementHints.KEY_FONT, FONT); // } // // public static class MonitorHandlerImpl implements MonitorHandler { // private static final long serialVersionUID = -4258875745321808416L; // public static final MonitorHandler INSTANCE = new MonitorHandlerImpl(); // } // // static class Initializer implements LifeCycle { // private static final long serialVersionUID = 4404942036933073584L; // // IElement parentElement; // Map substitutions; // Object component; // String suffix; // boolean hack; // // Initializer(IElement parentElement, Map substitutions, Object component, String suffix, boolean hack) { // this.parentElement = parentElement; // this.substitutions = substitutions; // this.component = component; // this.suffix = suffix; // this.hack = hack; // } // // @Override // public void onElementActivated(IDiagram d, IElement e) { // // if(!hack) { // // hack = true; // // Point2D parentPos = ElementUtils.getPos(parentElement); // Point2D thisPos = ElementUtils.getPos(e); // // Move move = e.getElementClass().getSingleItem(Move.class); // move.moveTo(e, thisPos.getX() - parentPos.getX(), thisPos.getY() - parentPos.getY()); // // } // // } // @Override // public void onElementCreated(IElement e) { // if(parentElement != null) e.setHint(ElementHints.KEY_PARENT_ELEMENT, parentElement); // if(substitutions != null) e.setHint(KEY_MONITOR_SUBSTITUTIONS, substitutions); // if(component != null) e.setHint(KEY_MONITOR_COMPONENT, component); // if(suffix != null) e.setHint(KEY_MONITOR_SUFFIX, suffix); // // e.setHint(KEY_DIRECTION, 0.0); // e.setHint(KEY_NUMBER_FORMAT, DEFAULT_NUMBER_FORMAT); // //e.setHint(KEY_HORIZONTAL_ALIGN, Alignment.LEADING); // //e.setHint(KEY_VERTICAL_ALIGN, Alignment.LEADING); // } // @Override // public void onElementDeactivated(IDiagram d, IElement e) { // } // @Override // public void onElementDestroyed(IElement e) { // } // }; // // static String finalText(IElement e) { // String text = e.getElementClass().getSingleItem(Text.class).getText(e); // if (text == null) // return null; // return substitute(text, e); // } // // public static String editText(IElement e) { // return substitute("#v1", e); // } // // private static String formValue(IElement e) { // // TODO: consider using substitute // Map substitutions = e.getHint(KEY_MONITOR_SUBSTITUTIONS); // if (substitutions != null) { // String value = substitutions.get("#v1"); // if (substitutions.containsKey("#u1") && substitutions.get("#u1").length() > 0) { // value += " " + substitutions.get("#u1"); // } // return value; // } // return null; // } // // static String substitute(String text, IElement e) { // Map substitutions = e.getHint(KEY_MONITOR_SUBSTITUTIONS); // return substitute(text, substitutions); // } // // static String substitute(String text, Map substitutions) { // if (substitutions != null) { // // TODO: slow as hell // for(Map.Entry entry : substitutions.entrySet()) { // if (entry.getValue() != null) { // text = text.replace(entry.getKey(), entry.getValue()); // } else { // text = text.replace(entry.getKey(), ""); // } // } // } // return text; // } // // public static void update(IElement e) { // MonitorSGNode node = e.getElementClass().getSingleItem(MonitorSGNode.class); // node.update(e); // } // // public static void cleanup(IElement e) { // MonitorSGNode node = e.getElementClass().getSingleItem(MonitorSGNode.class); // node.cleanup(e); // } // // static final Rectangle2D DEFAULT_BOX = new Rectangle2D.Double(0, 0, 0, 0); // // static Shape createMonitor(IElement e) { // Alignment hAlign = getHorizontalAlignment(e); // Alignment vAlign = getVerticalAlignment(e); // double hMargin = getHorizontalMargin(e); // double vMargin = getVerticalMargin(e); // // String text = finalText(e); // if(text == null) { // return align(hMargin, vMargin, hAlign, vAlign, DEFAULT_BOX); // } // // Graphics2D g = e.getHint(KEY_MONITOR_GC); // if(g == null) { // return align(hMargin, vMargin, hAlign, vAlign, DEFAULT_BOX); // } // // Font f = getFont(e); // FontMetrics fm = g.getFontMetrics(f); // Rectangle2D rect = fm.getStringBounds(text, g); // // return align(hMargin, vMargin, hAlign, vAlign, rect); // } // // static Shape align(double hMargin, double vMargin, Alignment hAlign, Alignment vAlign, Rectangle2D rect) { // //System.out.println("align: " + hMargin + ", " + vMargin + ", " + hAlign + ", " + vAlign + ": " + rect); // double tx = align(hMargin, hAlign, rect.getMinX(), rect.getMaxX()); // double ty = align(vMargin, vAlign, rect.getMinY(), rect.getMaxY()); // //System.out.println(" translate: " + tx + " " + ty); // double nw = rect.getWidth() + 2*hMargin; // double nh = rect.getHeight() + 2*vMargin; // return makePath(tx + rect.getMinX(), ty + rect.getMinY(), nw, nh); // } // // static double align(double margin, Alignment align, double min, double max) { // double s = max - min; // switch (align) { // case LEADING: // return -min; // case TRAILING: // return -s - 2 * margin - min; // case CENTER: // return -0.5 * s - margin - min; // default: // return 0; // } // } // // static Path2D makePath(double x, double y, double w, double h) { // Path2D path = new Path2D.Double(); // path.moveTo(x, y); // path.lineTo(x+w, y); // path.lineTo(x+w, y+h); // path.lineTo(x, y+h); // path.closePath(); // return path; // } // // public static final Shape BOX_SHAPE = new Rectangle(-1, -1, 2, 2); // // public static class MonitorSGNode implements SceneGraph, InternalSize, Outline { // private static final long serialVersionUID = -106278359626957687L; // // static final MonitorSGNode INSTANCE = new MonitorSGNode(); // // @Override // public void init(final IElement e, final G2DParentNode parent) { // // Create node if it doesn't exist yet // MonitorNode node = (MonitorNode)e.getHint(KEY_SG_NODE); // if(node == null || node.getBounds() == null || node.getParent() != parent) { // node = parent.addNode(ElementUtils.generateNodeId(e), MonitorNode.class); // e.setHint(KEY_SG_NODE, node); // // node.setActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent event) { // TextEditor editor = e.getElementClass().getAtMostOneItemOfClass(TextEditor.class); // if (editor != null) { // Modifier modifier = editor.getModifier(e); // if (modifier != null) { // String newValue = event.getActionCommand(); // String error = modifier.isValid(e, newValue); // // if (error == null) { // // Only modify if the modification was not // // cancelled and the value is valid. // modifier.modify(e, newValue); // } else { // // TODO: show error somehow, possibly through status bar // // // Make sure that the monitor content gets // // reset to its previous value. // MonitorNode node = e.getHint(KEY_SG_NODE); // if (node != null) // node.setText(formValue(e)); // } // } // } // //// final Text t = e.getElementClass().getAtMostOneItemOfClass(Text.class); //// t.setText(e, event.getActionCommand()); // FIXME // }}); // node.setSize(50, 22); // Double border_width = (Double)e.getHint(KEY_BORDER_WIDTH); // if(border_width == null) border_width = 0.1; // // node.setBorderWidth(border_width); // // Rectangle2D bounds = (Rectangle2D)e.getHint(ElementHints.KEY_BOUNDS); // if(bounds != null) node.setBounds(bounds); // } // update(e); // } // // public void update(IElement e) { // String value = null; // // final Text t = e.getElementClass().getAtMostOneItemOfClass(Text.class); // assert(t != null); // // value = formValue(e); // // MonitorNode node = (MonitorNode) e.getHint(KEY_SG_NODE); // if (node != null && value != null) { // node.setText(value); // Object component = e.getHint(KEY_MONITOR_COMPONENT); // if (component != null) { // node.setEditable(true); // } else { // node.setEditable(false); // } // // // FIXME: set only if changed .. (but quickfix is not to clone) // Font font = ElementUtils.getTextFont(e); // if (node.getFont() != font) { // Don't update if we have a same object // node.setFont(font); // } // Color color = ElementUtils.getTextColor(e); // node.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha())); // String tt = (String) e.getHint(KEY_TOOLTIP_TEXT); // if (tt != null) // node.setToolTipText(new String(tt)); // } // } // // @Override // public void cleanup(IElement e) { // MonitorNode node = (MonitorNode)e.removeHint(KEY_SG_NODE); // if (node != null) // node.remove(); // } // // @Override // public Rectangle2D getBounds(IElement e, Rectangle2D size) { // Rectangle2D shape = new Rectangle2D.Double(0, 0, 0, 0); // // MonitorNode node = (MonitorNode)e.getHint(KEY_SG_NODE); // if(node != null && node.getBounds() != null) { // shape = node.getBounds().getBounds2D(); // } // // if(size != null) size.setRect(shape); // return shape; // } // // @Override // public Shape getElementShape(IElement e) { // Shape shape = new Rectangle2D.Double(0, 0, 0, 0); // // MonitorNode node = (MonitorNode)e.getHint(KEY_SG_NODE); // if(node != null && node.getBounds() != null) { // shape = node.getBounds(); // } // // return shape; // } // // } // // public static class Transformer implements Transform, Move, Rotate, Scale, LifeCycle { // // private static final long serialVersionUID = -3704887325602085677L; // // public static final Transformer INSTANCE = new Transformer(null); // // Double aspectRatio; // // public Transformer() { // this(null); // } // // public Transformer(Double aspectRatio) { // this.aspectRatio = aspectRatio; // } // // @Override // public Double getFixedAspectRatio(IElement e) { // return aspectRatio; // } // // @Override // public Point2D getScale(IElement e) { // AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); // return _getScale(at); // } // // @Override // public void setScale(IElement e, Point2D newScale) { // // Doesn't work for monitors. // Point2D oldScale = getScale(e); // double sx = newScale.getX() / oldScale.getX(); // double sy = newScale.getY() / oldScale.getY(); // AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); // at = new AffineTransform(at); // at.scale(sx, sy); // e.setHint(ElementHints.KEY_TRANSFORM, at); // } // // @Override // public Point2D getMaximumScale(IElement e) { // return null; // } // // @Override // public Point2D getMinimumScale(IElement e) { // return null; // } // // private static Point2D _getScale(AffineTransform at) { // double m00 = at.getScaleX(); // double m11 = at.getScaleY(); // double m10 = at.getShearY(); // double m01 = at.getShearX(); // // Project unit vector to canvas // double sx = Math.sqrt(m00 * m00 + m10 * m10); // double sy = Math.sqrt(m01 * m01 + m11 * m11); // return new Point2D.Double(sx, sy); // } // // @Override // public void rotate(IElement e, double theta, Point2D origin) { // if (Double.isNaN(theta)) return; // theta = Math.toDegrees(theta); // Double angle = e.getHint(KEY_DIRECTION); // double newAngle = angle != null ? angle+theta : theta; // newAngle = Math.IEEEremainder(newAngle, 360.0); // e.setHint(KEY_DIRECTION, newAngle); // } // // @Override // public double getAngle(IElement e) { // Double angle = e.getHint(KEY_DIRECTION); // return angle != null ? Math.toRadians(angle) : 0; // } // // @Override // public Point2D getPosition(IElement e) { // AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); // Point2D p = new Point2D.Double(at.getTranslateX(), at.getTranslateY()); // return p; // } // // @Override // public void moveTo(IElement e, double x, double y) { // AffineTransform origAt = e.getHint(ElementHints.KEY_TRANSFORM); // double oldX = origAt.getTranslateX(); // double oldY = origAt.getTranslateY(); // AffineTransform move = AffineTransform.getTranslateInstance(x-oldX, y-oldY); // AffineTransform at2 = new AffineTransform(origAt); // at2.preConcatenate(move); // e.setHint(ElementHints.KEY_TRANSFORM, at2); // } // // @Override // public AffineTransform getTransform(IElement e) { // AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); // // IElement parentElement = e.getHint(ElementHints.KEY_PARENT_ELEMENT); // if (parentElement == null) // return at; // // Transform parentTransform = parentElement.getElementClass().getSingleItem(Transform.class); // assert(parentTransform!=null); // // AffineTransform result = (AffineTransform)at.clone(); // result.preConcatenate(parentTransform.getTransform(parentElement)); // // return result; // } // // @Override // public void setTransform(IElement e, AffineTransform at) { // e.setHint(ElementHints.KEY_TRANSFORM, at.clone()); // } // // @Override // public void onElementActivated(IDiagram d, IElement e) { // } // // @Override // public void onElementCreated(IElement e) { // e.setHint(ElementHints.KEY_TRANSFORM, new AffineTransform()); // } // // @Override // public void onElementDeactivated(IDiagram d, IElement e) { // } // // @Override // public void onElementDestroyed(IElement e) { //// List nodeHandlers = e.getElementClass().getItemsByClass(SceneGraph.class); //// for(SceneGraph n : nodeHandlers) { //// System.out.println("element gone:"+e); //// n.cleanup(e); //// } // } // } // // static double getOrientationDelta(IElement e, AffineTransform tr) { // Double angle = e.getHint(KEY_DIRECTION); // if (angle == null || Double.isNaN(angle)) // return Double.NaN; // double angrad = Math.toRadians(angle); // // Vector2d forcedAxis = new Vector2d(Math.cos(angrad), Math.sin(angrad)); // Vector2d x = new Vector2d(tr.getScaleX(), tr.getShearX()); // forcedAxis.normalize(); // x.normalize(); // double cosa = forcedAxis.dot(x); // double delta = Math.acos(cosa); // return delta; // } // // static class MonitorImageFactory implements IFactory { // private double staticScaleX = 1, staticScaleY = 1; // // public MonitorImageFactory(double staticScaleX, double staticScaleY) { // this.staticScaleX = staticScaleX; // this.staticScaleY = staticScaleY; // } // // @Override // public Image get() throws ProvisionException { // return new AbstractImage() { // Shape path = align(DEFAULT_HORIZONTAL_MARGIN, DEFAULT_VERTICAL_MARGIN, DEFAULT_HORIZONTAL_ALIGN, DEFAULT_VERTICAL_ALIGN, // new Rectangle2D.Double(0, 0, 50*staticScaleX, 22*staticScaleY)); // // @Override // public Rectangle2D getBounds() { // return path.getBounds2D(); // } // // @Override // public EnumSet getFeatures() { // return EnumSet.of(Feature.Vector); // } // // @Override // public Shape getOutline() { // return path; // } // // @Override // public Node init(G2DParentNode parent) { // MonitorNode node = parent.getOrCreateNode(""+hashCode(), MonitorNode.class); // node.setText(""); // node.setSize(50, 22); // node.setBorderWidth(1); // node.setText("Drop Me"); // node.setTransform(AffineTransform.getScaleInstance(staticScaleX, staticScaleY)); // return node; // } // }; // } // } // // static final IProvider MONITOR_IMAGE = // ProviderUtils.reference( // ProviderUtils.cache( // ProviderUtils.rasterize( // new MonitorImageFactory(0.5, 0.5) // ))); // // static final StaticSymbol MONITOR_SYMBOL = new StaticSymbolImpl( MONITOR_IMAGE.get() ); // // static final FillColor FILL_COLOR = new FillColorImpl(DEFAULT_FILL_COLOR); // // public static final ElementClass MONITOR_CLASS = // ElementClass.compile( // MonitorHandlerImpl.INSTANCE, // Transformer.INSTANCE, // BorderColorImpl.BLACK, // FILL_COLOR, // MonitorSGNode.INSTANCE, // TextImpl.INSTANCE, // TextEditorImpl.INSTANCE, // TextFontImpl.DEFAULT, // TextColorImpl.BLACK, // SimpleElementLayers.INSTANCE, // MONITOR_SYMBOL // ); // // // staticScale{X,Y} define the scale of the static monitor image // public static ElementClass create(IElement parentElement, Map substitutions, Object component, String suffix, double staticScaleX, double staticScaleY, ElementHandler... extraHandlers) { // // Bit of a hack to be able to define the scale // IProvider staticMonitorSymbolProvider = ProviderUtils.reference( // ProviderUtils.cache( // ProviderUtils // .rasterize( // new MonitorImageFactory(staticScaleX, staticScaleY)))); // StaticSymbol staticMonitorSymbol = new StaticSymbolImpl( staticMonitorSymbolProvider.get() ); // return ElementClass.compile( // new Initializer(parentElement, substitutions, component, suffix, parentElement != null ? false : true), // MonitorHandlerImpl.INSTANCE, // Transformer.INSTANCE, // BorderColorImpl.BLACK, // FILL_COLOR, // MonitorSGNode.INSTANCE, // TextImpl.INSTANCE, // TextEditorImpl.INSTANCE, // TextFontImpl.DEFAULT, // TextColorImpl.BLACK, // SimpleElementLayers.INSTANCE, // staticMonitorSymbol // ).newClassWith(extraHandlers); // } // //}