X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.trend%2Fsrc%2Forg%2Fsimantics%2Ftrend%2Fimpl%2FTrendParticipant.java;h=54109db8732cccbe4bbda1942fec01b269c9ddad;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=66a67eb62658ba4f4699a309f2ae1c95c303ab35;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.trend/src/org/simantics/trend/impl/TrendParticipant.java b/bundles/org.simantics.trend/src/org/simantics/trend/impl/TrendParticipant.java index 66a67eb62..54109db87 100644 --- a/bundles/org.simantics.trend/src/org/simantics/trend/impl/TrendParticipant.java +++ b/bundles/org.simantics.trend/src/org/simantics/trend/impl/TrendParticipant.java @@ -1,910 +1,910 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 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.trend.impl; - -import java.awt.Cursor; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.print.PrinterException; -import java.io.File; -import java.io.IOException; - -import org.simantics.databoard.accessor.error.AccessorException; -import org.simantics.databoard.util.Bean; -import org.simantics.g2d.canvas.Hints; -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.canvas.IMouseCursorHandle; -import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; -import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; -import org.simantics.g2d.canvas.impl.HintReflection.HintListener; -import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; -import org.simantics.g2d.chassis.ITooltipProvider; -import org.simantics.g2d.participant.TimeParticipant; -import org.simantics.history.HistoryException; -import org.simantics.history.csv.CSVFormatter; -import org.simantics.history.util.ProgressMonitor; -import org.simantics.scenegraph.g2d.IG2DNode; -import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; -import org.simantics.scenegraph.g2d.events.MouseEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent; -import org.simantics.scenegraph.g2d.events.TimeEvent; -import org.simantics.scenegraph.g2d.events.command.CommandEvent; -import org.simantics.scenegraph.g2d.events.command.Commands; -import org.simantics.trend.configuration.ItemPlacement; -import org.simantics.trend.configuration.TrendItem.Renderer; -import org.simantics.trend.util.PrintUtil; -import org.simantics.utils.datastructures.hints.IHintContext.Key; -import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; -import org.simantics.utils.datastructures.hints.IHintObservable; - -public class TrendParticipant extends AbstractCanvasParticipant { - - /** - * Key for storing chart value tip box relative position. Changed by - * {@link TrendParticipant} after user finishes dragging this class around. - * */ - public static final Key KEY_VALUE_TIP_BOX_RELATIVE_POS = new KeyOf(Point2D.class); - - /** Key for chart redraw interval in milliseconds (drawn only if dirty) */ - public static final Key KEY_TREND_DRAW_INTERVAL = new KeyOf(Long.class); - - /** The time code when trend was last redrawn */ - public static final Key KEY_TREND_SHAPE_LAST = new KeyOf(Long.class); - - /** Key for interval time of value scale */ - public static final Key KEY_TREND_AUTOSCALE_INTERVAL = new KeyOf(Long.class); - - /** Key for time of last autoscale */ - public static final Key KEY_TREND_AUTOSCALE_LAST = new KeyOf(Long.class); - - public static final double KEY_MOVE = 0.33; - - /** Cursor when panning */ - public MouseCursors cursors = new MouseCursors(); - - @HintListener(Class=Hints.class, Field="KEY_CONTROL_BOUNDS") - public void selectionChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { - trend.shapedirty = true; - setDirty(); - } - - TrendNode trend; - - @Dependency TimeParticipant time; - - Grab grab; - - // The single item on which the mouse hovers over is set to this field. (Binary items are selectable). - public ItemNode hoveringItem; - - @Override - public void addedToContext(ICanvasContext ctx) { - super.addedToContext(ctx); - time.registerForEvents(getClass()); - } - - public void setTrend(TrendNode node) { - trend = node; - } - - public TrendNode getTrend() { - return trend; - } - -// @SGInit -// public void initSG(G2DParentNode parent) { -// Set nodes = NodeUtil.collectNodes(parent, TrendNode.class); -// trends.addAll(nodes); -// } - - @SGCleanup - public void cleanupSG() { - } - - protected void updateNode() { -// titleNode.setText(text) -// node.setEnabled(isPaintingEnabled()); -// node.setGridColor(getGridColor()); -// node.setGridSize(getGridSize()); - } - - @EventHandler(priority = 0) - public boolean handleTimeEvent(TimeEvent e) { - //System.out.println("(" + isRemoved() + ") time event: " + e.time + " (" + e.interval + ")"); - if (isRemoved()) { - if (time != null) - time.unregisterForEvents(getClass()); - return false; - } - - long currentTime = e.time; - - Long drawInterval = getHint(KEY_TREND_DRAW_INTERVAL); - if (drawInterval == null) drawInterval = 200L; - Long lastDrawTime = getHint(KEY_TREND_SHAPE_LAST); - boolean drawIntervalElapsed = lastDrawTime == null || (currentTime>=lastDrawTime+drawInterval); - if (drawIntervalElapsed) { -// System.out.println("elapsed="+drawIntervalElapsed+" currentTime="+currentTime+" lastDraw="+lastDrawTime+", interval="+drawInterval+", nextDrawTime="+(lastDrawTime+drawInterval)); -// System.out.println("elapsed="+drawIntervalElapsed+" currentTime="+currentTime+" lastDraw="+lastDrawTime+", interval="+drawInterval); - setHint(KEY_TREND_SHAPE_LAST, currentTime); - trend.shapedirty |= trend.datadirty; - trend.datadirty = false; - } - - // Scale time - Long autoscaleInterval = getHint(KEY_TREND_AUTOSCALE_INTERVAL); - if (autoscaleInterval == null) autoscaleInterval = 1000L; - Long autoscaleTime = getHint(KEY_TREND_AUTOSCALE_LAST); - boolean autoscale = autoscaleTime==null || (currentTime>=autoscaleTime+autoscaleInterval); - if (autoscale) { - boolean l = trend.autoscale(trend.autoscaletime, autoscale); - if (!draggingValueTip(grab)) { - trend.updateValueTipTime(); - } - if (l) { - trend.layout(); - } - - setHint(KEY_TREND_AUTOSCALE_LAST, currentTime); - } - - // IT IS DRAW TIME - if (trend.shapedirty) { -// System.out.println(currentTime+": Draw time!"); - setDirty(); - } - - return false; - } - - @EventHandler(priority = 0) - public boolean mouseClick(MouseClickEvent me) { - IG2DNode node = trend.pickNode( me.controlPosition ); - - if (me.clickCount==2 && node!=null) { - trend.valueTipTime = trend.prevValueTipTime; - if (node instanceof Plot) { - boolean binaryArea = me.controlPosition.getY()>trend.plot.getY()+trend.plot.analogAreaHeight; - if (binaryArea) { - trend.horizRuler.zoomOut(); - } else { - trend.zoomOut(); - } - setDirty(); - return true; - } else if (node instanceof HorizRuler) { - HorizRuler hr = (HorizRuler) node; - hr.zoomOut(); - setDirty(); - return true; - } else if (node instanceof VertRuler) { - VertRuler vr = (VertRuler) node; - vr.zoomOut(); - setDirty(); - return true; - } - } - - // Click ValueTip - if (me.clickCount==1 && me.button==MouseEvent.LEFT_BUTTON && node!=null && node instanceof Plot) { - trend.prevValueTipTime = trend.valueTipTime; - if (trend.valueTipTime == null) { - trend.valueTipTime = Double.isNaN(trend.mouseHoverTime)?null:trend.mouseHoverTime; - trend.valueTipHover = true; - } else { - double valueTipX = trend.horizRuler.toX( trend.valueTipTime ); - double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); - boolean hit = x>=valueTipX-TrendLayout.VALUE_TIP_HOVER_SENSITIVITY && x<=valueTipX+TrendLayout.VALUE_TIP_HOVER_SENSITIVITY; - if (hit) trend.valueTipTime = null; - } - setDirty(); - } - - /* - // Right click removes value tip - if (me.clickCount==1 && me.button==MouseEvent.RIGHT_BUTTON) { - if (trend.valueTipTime != null) { - trend.valueTipTime = null; - setDirty(); - } - }*/ - - if (me.clickCount==1 && me.button==MouseEvent.LEFT_BUTTON) { - if (node instanceof VertRuler) { - VertRuler vr = (VertRuler) node; - trend.selectVertRuler( trend.vertRulers.indexOf(vr) ); - setDirty(); - } else if (node == null || node instanceof TextNode) { - Plot p = trend.plot; - double x = me.controlPosition.getX() - p.getX(); - double y = me.controlPosition.getY() - p.getY(); - if ( x>=0 && x<=p.getWidth() && y<=0 && y>=-Plot.DIAMOND_SIZE*2) { - // Click hits milestone area - milestoneSearch: for ( Milestone ms : trend.milestones.milestones ) { - double mx = trend.horizRuler.toX( ms.time ); - if ( x>=mx-Plot.DIAMOND_SIZE && x<=mx+Plot.DIAMOND_SIZE ) { - ITooltipProvider tp = getContext().getTooltipProvider(); - if (tp!=null) { - tp.show(ms.label, ms.description); - } - break milestoneSearch; - } - } - } - - } - - } - return false; - } - - @EventHandler(priority = 0) - public boolean mouseDown(MouseButtonPressedEvent me) { - // Start Box-Zoom - if (me.button==MouseEvent.LEFT_BUTTON) { - IG2DNode node = trend.pickNode( me.controlPosition ); - if (node == null || node instanceof Plot) { - - // Start value box grab - { - double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); - double y = me.controlPosition.getY() - trend.plot.getBounds().getY(); - if (trend.plot.valueTipBoxBounds.contains(x, y)) { - //System.out.println("grabbed value box @ " + x + ", " + y); - grab = new Grab(); - grab.valueBoxRelPos.setLocation(trend.spec.viewProfile.valueViewPositionX, trend.spec.viewProfile.valueViewPositionY); - grab.valueBoxPos.setFrame(trend.plot.valueTipBoxBounds); - grab.mousepos = new Point2D.Double( me.controlPosition.getX(), me.controlPosition.getY() ); - grab.valueBoxGrab = true; - return true; - } - } - - // Start Value-Tip grab - if (trend.valueTipTime!=null) { - double valueTipX = trend.horizRuler.toX( trend.valueTipTime ); - double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); - boolean hit = x>=valueTipX-TrendLayout.VALUE_TIP_HOVER_SENSITIVITY && x<=valueTipX+TrendLayout.VALUE_TIP_HOVER_SENSITIVITY; - if (hit) { - grab = new Grab(); - grab.mousepos = new Point2D.Double( me.controlPosition.getX(), me.controlPosition.getY() ); - grab.sx = trend.horizRuler.unitsPerPixel(); - grab.sy = new double[ trend.vertRulers.size() ]; - grab.valueTipGrab = true; - return true; - } - } - - // Start Box-Zoom - boolean binaryArea = me.controlPosition.getY()>trend.plot.getY()+trend.plot.analogAreaHeight; - boolean timeZoom = (me.stateMask & MouseEvent.SHIFT_MASK)>0 || binaryArea; - if (trend.selection==null) { - trend.selection = trend.addNode("Selection", SelectionNode.class); - trend.selection.setZIndex( 10 ); - trend.selection.start( me.controlPosition, binaryArea, timeZoom ); - } - return true; - } - } - - // Start grab - IG2DNode node = trend.pickNode( me.controlPosition ); - if ( (me.button==MouseEvent.MIDDLE_BUTTON) && - node!=null && node instanceof Plot) { - //Plot p = (Plot) node; - TrendNode trend = (TrendNode) node.getParent(); - boolean shift = (me.stateMask & MouseEvent.SHIFT_MASK)>0; - boolean alt = (me.stateMask & MouseEvent.ALT_MASK)>0; - //boolean analogArea = me.controlPosition.getY() < p.getY()+p.analogAreaHeight; - //boolean binaryArea = me.controlPosition.getY() >= p.getY()+p.analogAreaHeight; - grab = new Grab(); - grab.mousepos = new Point2D.Double( me.controlPosition.getX(), me.controlPosition.getY() ); - grab.sx = trend.horizRuler.unitsPerPixel(); - grab.sy = new double[ trend.vertRulers.size() ]; - grab.horiz = !shift || alt; - grab.vert = shift || alt; - if (grab.vert) { - for (int i=0; i1 && rect.getHeight()>1) { - if (trend.selection.timeZoom) { - trend.horizRuler.zoomIn( rect.getX()-trend.horizRuler.getX(), rect.getWidth() ); - } else { - trend.zoomIn( - rect.getX()-trend.plot.getX(), - rect.getY()-trend.plot.getY(), - rect.getWidth(), rect.getHeight(), true, true ); - } - trend.layout(); - trend.shapedirty = true; - setDirty(); - } - trend.selection.delete(); - trend.selection = null; - - return true; - } - - if (grab!=null && grab.mouseButton==me.button) { - grab.cursor.remove(); - grab = null; - } - return false; - } - - @EventHandler(priority = 0) - public boolean mouseExit(MouseExitEvent me) { - trend.valueTipHover = false; - setHoverTime( null ); - return false; - } - - void setHoverTime(Double time) { - if ( time==null && Double.isNaN(trend.mouseHoverTime) ) return; - if ( time!=null && trend.mouseHoverTime==time ) return; - if ( time==null ) { - trend.mouseHoverTime = Double.NaN; - } else { - trend.mouseHoverTime = time; - trend.lastMouseHoverTime = time; - } - setDirty(); - } - -// @EventHandler(priority = 0) -// public boolean mouseEnter(MouseExitEvent me) { -// //double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); -// //double time = trend.horizRuler.toTime( x ) - trend.horizRuler.basetime; -// return false; -// } - - @SuppressWarnings("unused") - @EventHandler(priority = 0) - public boolean mouseMoved(MouseMovedEvent me) { -// ITooltipProvider tt = getContext().getTooltipProvider(); -// if (tt!=null) { -// tt.setTooltipText("Hello"); -// } - - IG2DNode pick = trend.pickNode( me.controlPosition ); - - TrackMouseMovement: { - if ( pick == trend.plot ) { - double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); - double time = trend.horizRuler.toTime( x ); - double sx = (trend.horizRuler.end-trend.horizRuler.from) / trend.horizRuler.getWidth(); - double timeSnapTolerance = sx * 7.0; - boolean shift = (me.stateMask & MouseEvent.SHIFT_MASK)>0; - - // SNAP - When shift is held - if (shift) { - Double snappedTime = null; - try { - snappedTime = trend.snapToValue( time, timeSnapTolerance ); - if (snappedTime != null) time = snappedTime; - } catch (HistoryException e) { - } catch (AccessorException e) { - } - } - - setHoverTime(time); - } - } - - // Implement value box moving while dragging. - if (draggingValueBox(grab)) { - Rectangle2D plotBox = trend.plot.getBounds(); - Rectangle2D valueBoxPos = grab.valueBoxPos; - Rectangle2D valueBox = trend.plot.valueTipBoxBounds; - double dx = me.controlPosition.getX() - grab.mousepos.getX(); - double dy = me.controlPosition.getY() - grab.mousepos.getY(); - double margin = Plot.VALUE_TIP_BOX_PLOT_MARGIN; - double maxX = plotBox.getWidth() - margin - valueBox.getWidth(); - double maxY = plotBox.getHeight() - margin - valueBox.getHeight(); - double boxX = valueBoxPos.getX() + dx; - double boxY = valueBoxPos.getY() + dy; - double pw = plotBox.getWidth() - 2 * margin; - double ph = plotBox.getHeight() - 2 * margin; - double w = pw - valueBox.getWidth(); - double h = ph - valueBox.getHeight(); - if (w > 0 && h > 0) { - double rx = (boxX - margin) / w; - double ry = (boxY - margin) / h; - rx = Math.max(0, Math.min(rx, 1)); - ry = Math.max(0, Math.min(ry, 1)); - trend.spec.viewProfile.valueViewPositionX = rx; - trend.spec.viewProfile.valueViewPositionY = ry; - setDirty(); - } - return false; - } - - ValueToolTip: if ( pick == trend.plot) { - if (draggingValueTip(grab)) { - // Move grabbed value-tip - trend.valueTipTime = Double.isNaN(trend.mouseHoverTime) ? null : trend.mouseHoverTime; - return false; - } else { - // Track hover color - if (trend.valueTipTime!=null) { - double valueTipX = trend.horizRuler.toX( trend.valueTipTime ); - double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); - boolean hit = x>=valueTipX-TrendLayout.VALUE_TIP_HOVER_SENSITIVITY && x<=valueTipX+TrendLayout.VALUE_TIP_HOVER_SENSITIVITY; - trend.valueTipHover = hit; - } - } - } - - // Item pick - ItemPick: { - if ( pick instanceof VertRuler ) { - VertRuler vr = (VertRuler) pick; - hoveringItem = null; - for (ItemNode item : trend.analogItems) { - if (item.item.renderer != Renderer.Analog || item.ruler==vr) { - if ( hoveringItem != null) break; - hoveringItem = item; - } - } - } else if ( pick == null || pick instanceof Plot ) { - hoveringItem = trend.plot.pickItem( me.controlPosition ); - } else { - hoveringItem = null; - } - } - - // Box-Zoom - if (trend.selection!=null) { - trend.selection.setEndPoint( me.controlPosition ); - setHoverTime(null); - setDirty(); - return true; - } - - // Drag axis - if (grab != null) { - double dx = me.controlPosition.getX() - grab.mousepos.x; - double dy = me.controlPosition.getY() - grab.mousepos.y; - grab.mousepos.setLocation(me.controlPosition); - - if (grab.plot) { - if (grab.horiz) { - trend.horizRuler.translate(-dx*grab.sx); - } - if (grab.vert) { - for (int i=0; i=trend.vertRulers.size()) break; - trend.vertRulers.get(i).translate(dy*grab.sy[i]); - } - } - } else if (grab.horizRuler) { - trend.horizRuler.translate(-dx*grab.sx); - } else if (grab.vertRuler>=0) { - if (grab.vertRuler<=trend.vertRulers.size()) { - VertRuler vr = trend.vertRulers.get( grab.vertRuler ); - trend.selectVertRuler( grab.vertRuler ); - vr.translate(dy*grab.sy[ grab.vertRuler ]); - } - } - trend.layout(); - trend.shapedirty = true; - setDirty(); - return true; - } - return false; - } - - @EventHandler(priority = 0) - public boolean mouseWheel(MouseWheelMovedEvent me) { - IG2DNode node = trend.pickNode( me.controlPosition ); - if (node instanceof Plot || node instanceof HorizRuler || node instanceof VertRuler) { - Point2D pt = node.parentToLocal( me.controlPosition ); - boolean shift = (me.stateMask & MouseEvent.SHIFT_MASK)>0; - boolean alt = (me.stateMask & MouseEvent.ALT_MASK)>0; - double pw = trend.plot.getWidth(); - double ph = trend.plot.analogAreaHeight; - - double r = Math.pow(0.9, me.wheelRotation); - - double w = r * pw; - double h = r * ph; - double rx = pt.getX() / pw; - double ry = pt.getY() / ph; - - double zx = (pw-w)*rx; - double zy = (ph-h)*ry; - - if (node instanceof Plot) { - TrendNode trend = (TrendNode) node.getParent(); - if (shift||alt) { - for (VertRuler vr : trend.vertRulers) { - vr.zoomIn(zy, h); - } - } - if (!shift) { - trend.horizRuler.zoomIn(zx, w); - } - } - - if (node instanceof HorizRuler) { - //HorizRuler hr = (HorizRuler) node; - trend.horizRuler.zoomIn(zx, w); - } - - if (node instanceof VertRuler) { - VertRuler vr = (VertRuler) node; - trend.selectVertRuler( trend.vertRulers.indexOf(vr) ); - vr.zoomIn(zy, h); - } - trend.shapedirty = true; - trend.layout(); - setDirty(); - return true; - } - return false; - } - - @EventHandler(priority = 0) - public boolean handleCommandEvent(CommandEvent e) { - - if (e.command == Commands.CANCEL) { - if (trend.selection != null) { - trend.selection.delete(); - trend.selection = null; - setDirty(); - return true; - } - - if (grab!=null) { - if (draggingValueBox(grab)) { - trend.spec.viewProfile.valueViewPositionX = grab.valueBoxRelPos.getX(); - trend.spec.viewProfile.valueViewPositionY = grab.valueBoxRelPos.getY(); - } - if (grab.cursor!=null) grab.cursor.remove(); - grab = null; - setDirty(); - return true; - } - - if (trend.valueTipTime != null) { - trend.valueTipTime = null; - setDirty(); - return true; - } - return false; - } - - if (e.command == Commands.PAN_LEFT) { - double pw = trend.plot.getWidth(); - double ph = trend.plot.analogAreaHeight; - double zx = -pw * KEY_MOVE; - double zy = 0; - trend.zoomIn(zx, zy, pw, ph, true, true); - trend.layout(); - setDirty(); - } - - if (e.command == Commands.PAN_RIGHT) { - double pw = trend.plot.getWidth(); - double ph = trend.plot.analogAreaHeight; - double zx = +pw * KEY_MOVE; - double zy = 0; - trend.zoomIn(zx, zy, pw, ph, true, true); - trend.horizRuler.autoscroll = false; - trend.layout(); - setDirty(); - } - - if (e.command == Commands.PAN_UP) { - double pw = trend.plot.getWidth(); - double ph = trend.plot.analogAreaHeight; - double zx = 0; - double zy = -ph * KEY_MOVE; - trend.zoomIn(zx, zy, pw, ph, true, true); - trend.horizRuler.autoscroll = false; - trend.layout(); - setDirty(); - } - - if (e.command == Commands.PAN_DOWN) { - double pw = trend.plot.getWidth(); - double ph = trend.plot.analogAreaHeight; - double zx = 0; - double zy = +ph * KEY_MOVE; - trend.zoomIn(zx, zy, pw, ph, true, true); - trend.horizRuler.autoscroll = false; - trend.layout(); - setDirty(); - } - - // Zoom out to time window settings (VK_4) - if (e.command.equals(Commands.AUTOSCALE)) { - trend.horizRuler.autoscroll = true; - for (VertRuler vertRuler : trend.vertRulers) vertRuler.autoscroll = true; - trend.zoomOut(); - trend.layout(); - setDirty(); - } - - // Fit all visible (VK_1) - if (e.command.equals(Commands.ZOOM_TO_FIT)) { - trend.readMinMaxFromEnd(); - trend.horizRuler.setFromEnd(trend.horizRuler.iFrom, trend.horizRuler.iEnd); - trend.horizRuler.fireListener(); - int c = trend.vertRulers.size(); - for (int i=0; i nodes = NodeUtil.collectNodes(parent, TrendNode.class); +// trends.addAll(nodes); +// } + + @SGCleanup + public void cleanupSG() { + } + + protected void updateNode() { +// titleNode.setText(text) +// node.setEnabled(isPaintingEnabled()); +// node.setGridColor(getGridColor()); +// node.setGridSize(getGridSize()); + } + + @EventHandler(priority = 0) + public boolean handleTimeEvent(TimeEvent e) { + //System.out.println("(" + isRemoved() + ") time event: " + e.time + " (" + e.interval + ")"); + if (isRemoved()) { + if (time != null) + time.unregisterForEvents(getClass()); + return false; + } + + long currentTime = e.time; + + Long drawInterval = getHint(KEY_TREND_DRAW_INTERVAL); + if (drawInterval == null) drawInterval = 200L; + Long lastDrawTime = getHint(KEY_TREND_SHAPE_LAST); + boolean drawIntervalElapsed = lastDrawTime == null || (currentTime>=lastDrawTime+drawInterval); + if (drawIntervalElapsed) { +// System.out.println("elapsed="+drawIntervalElapsed+" currentTime="+currentTime+" lastDraw="+lastDrawTime+", interval="+drawInterval+", nextDrawTime="+(lastDrawTime+drawInterval)); +// System.out.println("elapsed="+drawIntervalElapsed+" currentTime="+currentTime+" lastDraw="+lastDrawTime+", interval="+drawInterval); + setHint(KEY_TREND_SHAPE_LAST, currentTime); + trend.shapedirty |= trend.datadirty; + trend.datadirty = false; + } + + // Scale time + Long autoscaleInterval = getHint(KEY_TREND_AUTOSCALE_INTERVAL); + if (autoscaleInterval == null) autoscaleInterval = 1000L; + Long autoscaleTime = getHint(KEY_TREND_AUTOSCALE_LAST); + boolean autoscale = autoscaleTime==null || (currentTime>=autoscaleTime+autoscaleInterval); + if (autoscale) { + boolean l = trend.autoscale(trend.autoscaletime, autoscale); + if (!draggingValueTip(grab)) { + trend.updateValueTipTime(); + } + if (l) { + trend.layout(); + } + + setHint(KEY_TREND_AUTOSCALE_LAST, currentTime); + } + + // IT IS DRAW TIME + if (trend.shapedirty) { +// System.out.println(currentTime+": Draw time!"); + setDirty(); + } + + return false; + } + + @EventHandler(priority = 0) + public boolean mouseClick(MouseClickEvent me) { + IG2DNode node = trend.pickNode( me.controlPosition ); + + if (me.clickCount==2 && node!=null) { + trend.valueTipTime = trend.prevValueTipTime; + if (node instanceof Plot) { + boolean binaryArea = me.controlPosition.getY()>trend.plot.getY()+trend.plot.analogAreaHeight; + if (binaryArea) { + trend.horizRuler.zoomOut(); + } else { + trend.zoomOut(); + } + setDirty(); + return true; + } else if (node instanceof HorizRuler) { + HorizRuler hr = (HorizRuler) node; + hr.zoomOut(); + setDirty(); + return true; + } else if (node instanceof VertRuler) { + VertRuler vr = (VertRuler) node; + vr.zoomOut(); + setDirty(); + return true; + } + } + + // Click ValueTip + if (me.clickCount==1 && me.button==MouseEvent.LEFT_BUTTON && node!=null && node instanceof Plot) { + trend.prevValueTipTime = trend.valueTipTime; + if (trend.valueTipTime == null) { + trend.valueTipTime = Double.isNaN(trend.mouseHoverTime)?null:trend.mouseHoverTime; + trend.valueTipHover = true; + } else { + double valueTipX = trend.horizRuler.toX( trend.valueTipTime ); + double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); + boolean hit = x>=valueTipX-TrendLayout.VALUE_TIP_HOVER_SENSITIVITY && x<=valueTipX+TrendLayout.VALUE_TIP_HOVER_SENSITIVITY; + if (hit) trend.valueTipTime = null; + } + setDirty(); + } + + /* + // Right click removes value tip + if (me.clickCount==1 && me.button==MouseEvent.RIGHT_BUTTON) { + if (trend.valueTipTime != null) { + trend.valueTipTime = null; + setDirty(); + } + }*/ + + if (me.clickCount==1 && me.button==MouseEvent.LEFT_BUTTON) { + if (node instanceof VertRuler) { + VertRuler vr = (VertRuler) node; + trend.selectVertRuler( trend.vertRulers.indexOf(vr) ); + setDirty(); + } else if (node == null || node instanceof TextNode) { + Plot p = trend.plot; + double x = me.controlPosition.getX() - p.getX(); + double y = me.controlPosition.getY() - p.getY(); + if ( x>=0 && x<=p.getWidth() && y<=0 && y>=-Plot.DIAMOND_SIZE*2) { + // Click hits milestone area + milestoneSearch: for ( Milestone ms : trend.milestones.milestones ) { + double mx = trend.horizRuler.toX( ms.time ); + if ( x>=mx-Plot.DIAMOND_SIZE && x<=mx+Plot.DIAMOND_SIZE ) { + ITooltipProvider tp = getContext().getTooltipProvider(); + if (tp!=null) { + tp.show(ms.label, ms.description); + } + break milestoneSearch; + } + } + } + + } + + } + return false; + } + + @EventHandler(priority = 0) + public boolean mouseDown(MouseButtonPressedEvent me) { + // Start Box-Zoom + if (me.button==MouseEvent.LEFT_BUTTON) { + IG2DNode node = trend.pickNode( me.controlPosition ); + if (node == null || node instanceof Plot) { + + // Start value box grab + { + double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); + double y = me.controlPosition.getY() - trend.plot.getBounds().getY(); + if (trend.plot.valueTipBoxBounds.contains(x, y)) { + //System.out.println("grabbed value box @ " + x + ", " + y); + grab = new Grab(); + grab.valueBoxRelPos.setLocation(trend.spec.viewProfile.valueViewPositionX, trend.spec.viewProfile.valueViewPositionY); + grab.valueBoxPos.setFrame(trend.plot.valueTipBoxBounds); + grab.mousepos = new Point2D.Double( me.controlPosition.getX(), me.controlPosition.getY() ); + grab.valueBoxGrab = true; + return true; + } + } + + // Start Value-Tip grab + if (trend.valueTipTime!=null) { + double valueTipX = trend.horizRuler.toX( trend.valueTipTime ); + double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); + boolean hit = x>=valueTipX-TrendLayout.VALUE_TIP_HOVER_SENSITIVITY && x<=valueTipX+TrendLayout.VALUE_TIP_HOVER_SENSITIVITY; + if (hit) { + grab = new Grab(); + grab.mousepos = new Point2D.Double( me.controlPosition.getX(), me.controlPosition.getY() ); + grab.sx = trend.horizRuler.unitsPerPixel(); + grab.sy = new double[ trend.vertRulers.size() ]; + grab.valueTipGrab = true; + return true; + } + } + + // Start Box-Zoom + boolean binaryArea = me.controlPosition.getY()>trend.plot.getY()+trend.plot.analogAreaHeight; + boolean timeZoom = (me.stateMask & MouseEvent.SHIFT_MASK)>0 || binaryArea; + if (trend.selection==null) { + trend.selection = trend.addNode("Selection", SelectionNode.class); + trend.selection.setZIndex( 10 ); + trend.selection.start( me.controlPosition, binaryArea, timeZoom ); + } + return true; + } + } + + // Start grab + IG2DNode node = trend.pickNode( me.controlPosition ); + if ( (me.button==MouseEvent.MIDDLE_BUTTON) && + node!=null && node instanceof Plot) { + //Plot p = (Plot) node; + TrendNode trend = (TrendNode) node.getParent(); + boolean shift = (me.stateMask & MouseEvent.SHIFT_MASK)>0; + boolean alt = (me.stateMask & MouseEvent.ALT_MASK)>0; + //boolean analogArea = me.controlPosition.getY() < p.getY()+p.analogAreaHeight; + //boolean binaryArea = me.controlPosition.getY() >= p.getY()+p.analogAreaHeight; + grab = new Grab(); + grab.mousepos = new Point2D.Double( me.controlPosition.getX(), me.controlPosition.getY() ); + grab.sx = trend.horizRuler.unitsPerPixel(); + grab.sy = new double[ trend.vertRulers.size() ]; + grab.horiz = !shift || alt; + grab.vert = shift || alt; + if (grab.vert) { + for (int i=0; i1 && rect.getHeight()>1) { + if (trend.selection.timeZoom) { + trend.horizRuler.zoomIn( rect.getX()-trend.horizRuler.getX(), rect.getWidth() ); + } else { + trend.zoomIn( + rect.getX()-trend.plot.getX(), + rect.getY()-trend.plot.getY(), + rect.getWidth(), rect.getHeight(), true, true ); + } + trend.layout(); + trend.shapedirty = true; + setDirty(); + } + trend.selection.delete(); + trend.selection = null; + + return true; + } + + if (grab!=null && grab.mouseButton==me.button) { + grab.cursor.remove(); + grab = null; + } + return false; + } + + @EventHandler(priority = 0) + public boolean mouseExit(MouseExitEvent me) { + trend.valueTipHover = false; + setHoverTime( null ); + return false; + } + + void setHoverTime(Double time) { + if ( time==null && Double.isNaN(trend.mouseHoverTime) ) return; + if ( time!=null && trend.mouseHoverTime==time ) return; + if ( time==null ) { + trend.mouseHoverTime = Double.NaN; + } else { + trend.mouseHoverTime = time; + trend.lastMouseHoverTime = time; + } + setDirty(); + } + +// @EventHandler(priority = 0) +// public boolean mouseEnter(MouseExitEvent me) { +// //double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); +// //double time = trend.horizRuler.toTime( x ) - trend.horizRuler.basetime; +// return false; +// } + + @SuppressWarnings("unused") + @EventHandler(priority = 0) + public boolean mouseMoved(MouseMovedEvent me) { +// ITooltipProvider tt = getContext().getTooltipProvider(); +// if (tt!=null) { +// tt.setTooltipText("Hello"); +// } + + IG2DNode pick = trend.pickNode( me.controlPosition ); + + TrackMouseMovement: { + if ( pick == trend.plot ) { + double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); + double time = trend.horizRuler.toTime( x ); + double sx = (trend.horizRuler.end-trend.horizRuler.from) / trend.horizRuler.getWidth(); + double timeSnapTolerance = sx * 7.0; + boolean shift = (me.stateMask & MouseEvent.SHIFT_MASK)>0; + + // SNAP - When shift is held + if (shift) { + Double snappedTime = null; + try { + snappedTime = trend.snapToValue( time, timeSnapTolerance ); + if (snappedTime != null) time = snappedTime; + } catch (HistoryException e) { + } catch (AccessorException e) { + } + } + + setHoverTime(time); + } + } + + // Implement value box moving while dragging. + if (draggingValueBox(grab)) { + Rectangle2D plotBox = trend.plot.getBounds(); + Rectangle2D valueBoxPos = grab.valueBoxPos; + Rectangle2D valueBox = trend.plot.valueTipBoxBounds; + double dx = me.controlPosition.getX() - grab.mousepos.getX(); + double dy = me.controlPosition.getY() - grab.mousepos.getY(); + double margin = Plot.VALUE_TIP_BOX_PLOT_MARGIN; + double maxX = plotBox.getWidth() - margin - valueBox.getWidth(); + double maxY = plotBox.getHeight() - margin - valueBox.getHeight(); + double boxX = valueBoxPos.getX() + dx; + double boxY = valueBoxPos.getY() + dy; + double pw = plotBox.getWidth() - 2 * margin; + double ph = plotBox.getHeight() - 2 * margin; + double w = pw - valueBox.getWidth(); + double h = ph - valueBox.getHeight(); + if (w > 0 && h > 0) { + double rx = (boxX - margin) / w; + double ry = (boxY - margin) / h; + rx = Math.max(0, Math.min(rx, 1)); + ry = Math.max(0, Math.min(ry, 1)); + trend.spec.viewProfile.valueViewPositionX = rx; + trend.spec.viewProfile.valueViewPositionY = ry; + setDirty(); + } + return false; + } + + ValueToolTip: if ( pick == trend.plot) { + if (draggingValueTip(grab)) { + // Move grabbed value-tip + trend.valueTipTime = Double.isNaN(trend.mouseHoverTime) ? null : trend.mouseHoverTime; + return false; + } else { + // Track hover color + if (trend.valueTipTime!=null) { + double valueTipX = trend.horizRuler.toX( trend.valueTipTime ); + double x = me.controlPosition.getX() - trend.horizRuler.getBounds().getX(); + boolean hit = x>=valueTipX-TrendLayout.VALUE_TIP_HOVER_SENSITIVITY && x<=valueTipX+TrendLayout.VALUE_TIP_HOVER_SENSITIVITY; + trend.valueTipHover = hit; + } + } + } + + // Item pick + ItemPick: { + if ( pick instanceof VertRuler ) { + VertRuler vr = (VertRuler) pick; + hoveringItem = null; + for (ItemNode item : trend.analogItems) { + if (item.item.renderer != Renderer.Analog || item.ruler==vr) { + if ( hoveringItem != null) break; + hoveringItem = item; + } + } + } else if ( pick == null || pick instanceof Plot ) { + hoveringItem = trend.plot.pickItem( me.controlPosition ); + } else { + hoveringItem = null; + } + } + + // Box-Zoom + if (trend.selection!=null) { + trend.selection.setEndPoint( me.controlPosition ); + setHoverTime(null); + setDirty(); + return true; + } + + // Drag axis + if (grab != null) { + double dx = me.controlPosition.getX() - grab.mousepos.x; + double dy = me.controlPosition.getY() - grab.mousepos.y; + grab.mousepos.setLocation(me.controlPosition); + + if (grab.plot) { + if (grab.horiz) { + trend.horizRuler.translate(-dx*grab.sx); + } + if (grab.vert) { + for (int i=0; i=trend.vertRulers.size()) break; + trend.vertRulers.get(i).translate(dy*grab.sy[i]); + } + } + } else if (grab.horizRuler) { + trend.horizRuler.translate(-dx*grab.sx); + } else if (grab.vertRuler>=0) { + if (grab.vertRuler<=trend.vertRulers.size()) { + VertRuler vr = trend.vertRulers.get( grab.vertRuler ); + trend.selectVertRuler( grab.vertRuler ); + vr.translate(dy*grab.sy[ grab.vertRuler ]); + } + } + trend.layout(); + trend.shapedirty = true; + setDirty(); + return true; + } + return false; + } + + @EventHandler(priority = 0) + public boolean mouseWheel(MouseWheelMovedEvent me) { + IG2DNode node = trend.pickNode( me.controlPosition ); + if (node instanceof Plot || node instanceof HorizRuler || node instanceof VertRuler) { + Point2D pt = node.parentToLocal( me.controlPosition ); + boolean shift = (me.stateMask & MouseEvent.SHIFT_MASK)>0; + boolean alt = (me.stateMask & MouseEvent.ALT_MASK)>0; + double pw = trend.plot.getWidth(); + double ph = trend.plot.analogAreaHeight; + + double r = Math.pow(0.9, me.wheelRotation); + + double w = r * pw; + double h = r * ph; + double rx = pt.getX() / pw; + double ry = pt.getY() / ph; + + double zx = (pw-w)*rx; + double zy = (ph-h)*ry; + + if (node instanceof Plot) { + TrendNode trend = (TrendNode) node.getParent(); + if (shift||alt) { + for (VertRuler vr : trend.vertRulers) { + vr.zoomIn(zy, h); + } + } + if (!shift) { + trend.horizRuler.zoomIn(zx, w); + } + } + + if (node instanceof HorizRuler) { + //HorizRuler hr = (HorizRuler) node; + trend.horizRuler.zoomIn(zx, w); + } + + if (node instanceof VertRuler) { + VertRuler vr = (VertRuler) node; + trend.selectVertRuler( trend.vertRulers.indexOf(vr) ); + vr.zoomIn(zy, h); + } + trend.shapedirty = true; + trend.layout(); + setDirty(); + return true; + } + return false; + } + + @EventHandler(priority = 0) + public boolean handleCommandEvent(CommandEvent e) { + + if (e.command == Commands.CANCEL) { + if (trend.selection != null) { + trend.selection.delete(); + trend.selection = null; + setDirty(); + return true; + } + + if (grab!=null) { + if (draggingValueBox(grab)) { + trend.spec.viewProfile.valueViewPositionX = grab.valueBoxRelPos.getX(); + trend.spec.viewProfile.valueViewPositionY = grab.valueBoxRelPos.getY(); + } + if (grab.cursor!=null) grab.cursor.remove(); + grab = null; + setDirty(); + return true; + } + + if (trend.valueTipTime != null) { + trend.valueTipTime = null; + setDirty(); + return true; + } + return false; + } + + if (e.command == Commands.PAN_LEFT) { + double pw = trend.plot.getWidth(); + double ph = trend.plot.analogAreaHeight; + double zx = -pw * KEY_MOVE; + double zy = 0; + trend.zoomIn(zx, zy, pw, ph, true, true); + trend.layout(); + setDirty(); + } + + if (e.command == Commands.PAN_RIGHT) { + double pw = trend.plot.getWidth(); + double ph = trend.plot.analogAreaHeight; + double zx = +pw * KEY_MOVE; + double zy = 0; + trend.zoomIn(zx, zy, pw, ph, true, true); + trend.horizRuler.autoscroll = false; + trend.layout(); + setDirty(); + } + + if (e.command == Commands.PAN_UP) { + double pw = trend.plot.getWidth(); + double ph = trend.plot.analogAreaHeight; + double zx = 0; + double zy = -ph * KEY_MOVE; + trend.zoomIn(zx, zy, pw, ph, true, true); + trend.horizRuler.autoscroll = false; + trend.layout(); + setDirty(); + } + + if (e.command == Commands.PAN_DOWN) { + double pw = trend.plot.getWidth(); + double ph = trend.plot.analogAreaHeight; + double zx = 0; + double zy = +ph * KEY_MOVE; + trend.zoomIn(zx, zy, pw, ph, true, true); + trend.horizRuler.autoscroll = false; + trend.layout(); + setDirty(); + } + + // Zoom out to time window settings (VK_4) + if (e.command.equals(Commands.AUTOSCALE)) { + trend.horizRuler.autoscroll = true; + for (VertRuler vertRuler : trend.vertRulers) vertRuler.autoscroll = true; + trend.zoomOut(); + trend.layout(); + setDirty(); + } + + // Fit all visible (VK_1) + if (e.command.equals(Commands.ZOOM_TO_FIT)) { + trend.readMinMaxFromEnd(); + trend.horizRuler.setFromEnd(trend.horizRuler.iFrom, trend.horizRuler.iEnd); + trend.horizRuler.fireListener(); + int c = trend.vertRulers.size(); + for (int i=0; i