/******************************************************************************* * 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.threadlog.ui; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.text.DecimalFormat; import java.text.Format; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import javax.swing.JPanel; public class TimeLineViewer extends JPanel { private static final long serialVersionUID = -7410066541298449720L; public static long TOOL_TIP_DELAY = 500; public static double MIN_GRID_LINE_SEPARATION = 15; // Time line data List lanes = new ArrayList(); // For panning and zooming double xScale = 100.0; double xOffset = 0.0; double yOffset = 0.0; int oldX; int oldY; // Tool tips Timer toolTipTimer = new Timer(); class ToolTipTask extends TimerTask { @Override public void run() { System.out.println("show tooltip"); } } public TimeLineViewer() { addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { oldX = e.getX(); oldY = e.getY(); } }); addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { int curX = e.getX(); int curY = e.getY(); int diffX = curX - oldX; int diffY = curY - oldY; oldX = curX; oldY = curY; xOffset -= diffX/xScale; yOffset -= diffY; repaint(); } TimerTask toolTipTask; @Override public void mouseMoved(MouseEvent e) { if(toolTipTask != null) toolTipTask.cancel(); toolTipTask = new ToolTipTask(); toolTipTimer.schedule(toolTipTask, TOOL_TIP_DELAY); } }); addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent e) { xOffset += e.getX() / xScale; xScale *= Math.pow(1.25, -e.getWheelRotation()); xOffset -= e.getX() / xScale; repaint(); } }); } public void addLane(Lane lane) { lanes.add(lane); } public void clear() { lanes.clear(); } public void paintIntervals(Graphics2D g) { for(int laneId=0;laneId < lanes.size();++laneId) { Lane lane = lanes.get(laneId); double y = 35.0*laneId - yOffset; double height = 30.0; for(Interval interval : lane.intervals) { double x = (interval.begin - xOffset) * xScale; double width = (interval.end - interval.begin) * xScale; Shape shape = new RoundRectangle2D.Double(x, y, width, height, 10.0, 10.0); g.setColor(Color.WHITE); g.fill(shape); g.setColor(Color.BLACK); g.draw(shape); Rectangle2D bounds = g.getFontMetrics().getStringBounds(interval.text, g); if(bounds.getWidth() < width) g.drawString(interval.text, (float)(x+0.5*(width-bounds.getWidth())), (float)(y+20.0)); } } } public void paintGrid(Graphics2D g) { Dimension dim = getSize(); g.setBackground(Color.WHITE); g.clearRect(0, 0, dim.width, dim.height); double stepsize = 0.001; double majorStepsize; while(true) { majorStepsize = stepsize * 5.0; if(stepsize * xScale >= MIN_GRID_LINE_SEPARATION) break; stepsize = majorStepsize; majorStepsize = stepsize * 2.0; if(stepsize * xScale >= MIN_GRID_LINE_SEPARATION) break; stepsize = majorStepsize; } double firstP = Math.ceil(xOffset / stepsize) * stepsize; double lastP = Math.floor((xOffset + dim.width / xScale) / stepsize) * stepsize; if(firstP < 0.0) firstP = 0.0; Format format = new DecimalFormat(); for(double p = firstP;p <= lastP; p+=stepsize) { int x = (int)((p - xOffset) * xScale); if(Math.abs(p/majorStepsize - Math.round(p/majorStepsize)) < 1e-3) { g.setColor(Color.BLACK); String text = format.format(p); Rectangle2D bounds = g.getFontMetrics().getStringBounds(text, g); g.drawString(text, (float)(x-bounds.getWidth()*0.5), 12.0f); } else g.setColor(Color.LIGHT_GRAY); g.drawLine(x, 14, x, (int)dim.getHeight()); } } @Override public void paint(Graphics _g) { Graphics2D g = (Graphics2D)_g; paintGrid(g); paintIntervals(g); } }