/******************************************************************************* * 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.modeling.ui.diagram; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import org.simantics.databoard.Bindings; import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.WriteGraph; import org.simantics.db.common.primitiverequest.ValueImplied; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.NoSingleResultException; import org.simantics.db.exception.ResourceNotFoundException; import org.simantics.db.layer0.adapter.StringModifier; import org.simantics.db.layer0.request.PossibleActiveValuation; import org.simantics.db.layer0.request.PossibleSessionValuation; import org.simantics.db.procedure.AsyncProcedure; import org.simantics.db.procedure.Listener; import org.simantics.diagram.G2DUtils; import org.simantics.diagram.adapter.SyncElementFactory; import org.simantics.diagram.elements.MonitorClass; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.stubs.G2DResource; import org.simantics.diagram.synchronization.CompositeHintSynchronizer; import org.simantics.diagram.synchronization.IHintSynchronizer; import org.simantics.diagram.synchronization.SynchronizationHints; import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; import org.simantics.diagram.synchronization.graph.ElementLoader; import org.simantics.diagram.synchronization.graph.MonitorSynchronizer; import org.simantics.diagram.synchronization.graph.TransformSynchronizer; import org.simantics.diagram.ui.DiagramModelHints; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.diagram.handler.DataElementMap; import org.simantics.g2d.diagram.handler.Relationship; import org.simantics.g2d.diagram.handler.RelationshipHandler; 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.handler.TextEditor; import org.simantics.g2d.element.handler.impl.StaticObjectAdapter; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.ui.diagram.SliderClass.Range; import org.simantics.utils.strings.format.MetricsFormat; import org.simantics.utils.strings.format.MetricsFormatList; import org.simantics.utils.threads.ThreadUtils; public class SliderClassFactory extends SyncElementFactory { private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(MonitorSynchronizer.INSTANCE, TransformSynchronizer.INSTANCE); public static ElementClass createSliderClass(Resource elementClass) { // set "default scale" to no scaling, 1.0, 1.0 return SliderClass.create(null, null, null, null, null, 1.0, 1.0, new StaticObjectAdapter(elementClass)); } // staticScale{X,Y} define the scale of the static monitor image public static ElementClass createSliderClass(Resource elementClass, IElement parentElement, Range range, Double value, Object component, String suffix, double staticScaleX, double staticScaleY) { return SliderClass.create(parentElement, range, value, component, suffix, staticScaleX, staticScaleY, new StaticObjectAdapter(elementClass)); } @Override public void load(ReadGraph g, final ICanvasContext canvas, final IDiagram diagram, final Resource element, final IElement e) throws DatabaseException { if(!g.hasStatement(element)) return; Layer0 l0 = Layer0.getInstance(g); final G2DResource g2d = G2DResource.getInstance(g); final DiagramResource dr = DiagramResource.getInstance(g); ElementClass ec = e.getElementClass(); // Must be done here to allow for the relationship manager to work properly. e.setHint(ElementHints.KEY_OBJECT, element); e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER); //System.out.println(" ElementClass:" + ec); //System.out.println(" Element:" + e); AffineTransform at = DiagramGraphUtil.getAffineTransform(g, element); ElementUtils.setTransform(e, at); // Load alignments MetricsFormat tmpf = null; try { tmpf = G2DUtils.getMetricsFormat(g, g.getSingleObject(element, dr.HasFormat)); } catch(NoSingleResultException ex) { tmpf = MetricsFormatList.METRICS_GENERIC; } final MetricsFormat format = tmpf; e.setHint(SliderClass.KEY_NUMBER_FORMAT, format); double bounds[] = DiagramGraphUtil.getPossibleRelatedDoubleArray(g, element, g2d.HasBounds); if (bounds!=null) { e.setHint(ElementHints.KEY_BOUNDS, new Rectangle2D.Double(bounds[0], bounds[1], bounds[2], bounds[3])); } String label = g.getPossibleRelatedValue(element, l0.HasLabel); ElementUtils.setText(e, label); try { final Resource componentToElement = ModelingResources.getInstance(g).ComponentToElement; final Resource sliderComponent = g.getPossibleObject(element, dr.HasSliderComponent); final String sliderSuffix = g.getPossibleRelatedValue(element, dr.HasSliderSuffix, Bindings.STRING); // FIXME: use range instead final Double min = g.getPossibleRelatedValue(element, dr.HasSliderMinValue, Bindings.DOUBLE); final Double max = g.getPossibleRelatedValue(element, dr.HasSliderMaxValue, Bindings.DOUBLE); e.setHint(SliderClass.KEY_SLIDER_COMPONENT, sliderComponent); e.setHint(SliderClass.KEY_SLIDER_SUFFIX, sliderSuffix); e.setHint(SliderClass.KEY_SLIDER_RANGE, new SliderClass.Range(min, max)); e.setHint(SliderClass.KEY_SLIDER_VALUE, new Double(0)); final Resource parentDiagramElement = g.getPossibleObject(sliderComponent, componentToElement); // Load parent relationship now, or it unsuccessful, after all elements have been loaded. if (parentDiagramElement != null) { if (!loadRelationships(g, diagram, e, parentDiagramElement)) { e.setHint(DiagramModelHints.KEY_ELEMENT_LOADER, new ElementLoader() { @Override public void load(ReadGraph g, IDiagram diagram, IElement element) { loadRelationships(g, diagram, element, parentDiagramElement); } }); } } // create tooltip if (sliderSuffix != null) { e.setHint(SliderClass.KEY_TOOLTIP_TEXT, sliderSuffix); } final Session session = g.getSession(); String sessionId = diagram.getHint(DiagramModelHints.KEY_SESSION_ID); Resource valuation = sessionId != null ? g.syncRequest(new PossibleSessionValuation(sliderComponent, sessionId, sliderSuffix)) : g.syncRequest(new PossibleActiveValuation(sliderComponent, sliderSuffix)); if(valuation == null) { return; } session.asyncRequest(new ValueImplied(valuation), new Listener() { @Override public void execute(final Object result) { final IElement el = ElementUtils.getByData(diagram, element); if(el != null) { ThreadUtils.asyncExec(canvas.getThreadAccess(), new Runnable() { @Override public void run() { el.setHint(SliderClass.KEY_SLIDER_VALUE, result); SliderClass.update(el); } }); } } @Override public void exception(Throwable t) { } @Override public boolean isDisposed() { return canvas.isDisposed(); } }); final StringModifier modifier = g.adapt(valuation, StringModifier.class); TextEditor ed = ec.getAtMostOneItemOfClass(TextEditor.class); ed.setModifier(e, new TextEditor.Modifier() { @Override public String getValue(IElement element) { return MonitorClass.editText(element); } @Override public String isValid(IElement element, String text) { // TODO: implement validation properly return null; } @Override public void modify(final IElement element, final String text) { session.asyncRequest(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { modifier.modify(graph, text); } }); } }); } catch (ResourceNotFoundException e1) { e1.printStackTrace(); } } boolean loadRelationships(ReadGraph g, IDiagram diagram, IElement element, Resource parentElementResource) { // If no relationship handler is available, stop loading. RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class); if (rh == null) return true; DataElementMap map = diagram.getDiagramClass().getSingleItem(DataElementMap.class); IElement parentElement = map.getElement(diagram, parentElementResource); if (parentElement != null) { element.setHint(ElementHints.KEY_PARENT_ELEMENT, parentElement); rh.claim(diagram, element, Relationship.CHILD_OF, parentElement); return true; } return false; } @Override public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType, AsyncProcedure procedure) { procedure.execute(graph, createSliderClass(elementType)); } }