-/*****************************************************************************\r
- * Copyright (c) 2007, 2008 Intel Corporation, 2010, 2012 Ericsson.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * Intel Corporation - Initial API and implementation\r
- * Ruslan A. Scherbakov, Intel - Initial API and implementation\r
- * Alvaro Sanchez-Leon - Updated for TMF\r
- * Patrick Tasse - Refactoring\r
- *\r
- *****************************************************************************/\r
-\r
-package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;\r
-\r
-import java.text.SimpleDateFormat;\r
-import java.util.Calendar;\r
-import java.util.Date;\r
-import java.util.GregorianCalendar;\r
-\r
-import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.MouseEvent;\r
-import org.eclipse.swt.events.MouseListener;\r
-import org.eclipse.swt.events.MouseMoveListener;\r
-import org.eclipse.swt.events.PaintEvent;\r
-import org.eclipse.swt.graphics.GC;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.widgets.Composite;\r
-\r
-/**\r
- * Implementation of the scale for the time graph view.\r
- *\r
- * This goes above the "gantt chart" area.\r
- *\r
- * @version 1.0\r
- * @author Alvaro Sanchez-Leon\r
- * @author Patrick Tasse\r
- */\r
-public class TimeGraphScale extends TimeGraphBaseControl implements MouseListener, MouseMoveListener {\r
-\r
- public TimeGraphScale(Composite parent, TimeGraphColorScheme colors) {\r
- super(parent, colors, SWT.NO_BACKGROUND | SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED);\r
- addMouseListener(this);\r
- addMouseMoveListener(this);\r
- }\r
-\r
- private static final long SEC_IN_NS = 1000000000;\r
- private static final long MIN_IN_NS = 60 * SEC_IN_NS;\r
- private static final long HOUR_IN_NS = 60 * MIN_IN_NS;\r
- private static final long DAY_IN_NS = 24 * HOUR_IN_NS;\r
- private static final long MONTH_IN_NS = 31 * DAY_IN_NS; // upper limit\r
- private static final long YEAR_IN_NS = 366 * DAY_IN_NS; // upper limit\r
-\r
- private static final double LOG10_1 = Math.log10(1);\r
- private static final double LOG10_2 = Math.log10(2);\r
- private static final double LOG10_3 = Math.log10(3);\r
- private static final double LOG10_5 = Math.log10(5);\r
-\r
- private static final Calendar GREGORIAN_CALENDAR = GregorianCalendar.getInstance();\r
-\r
- private ITimeDataProvider _timeProvider;\r
- private int _dragState = 0;\r
- private int _dragX0 = 0;\r
- private int _dragX = 0;\r
- private long _time0bak;\r
- private long _time1bak;\r
- private boolean _isInUpdate;\r
- private final Rectangle _rect0 = new Rectangle(0, 0, 0, 0);\r
- private int _height;\r
-\r
- public void setTimeProvider(ITimeDataProvider timeProvider) {\r
- _timeProvider = timeProvider;\r
- }\r
-\r
- private long _timeDelta;\r
-\r
- @Override\r
- public Point computeSize(int wHint, int hHint, boolean changed) {\r
- return super.computeSize(wHint, _height, changed);\r
- }\r
-\r
- public void setHeight(int height) {\r
- this._height = height;\r
- }\r
-\r
- private void calcTimeDelta(int width, double pixelsPerNanoSec) {\r
- double minDelta = (double) ((pixelsPerNanoSec == 0) ? YEAR_IN_NS : width / pixelsPerNanoSec);\r
- long unit = 1;\r
- if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r
- if (minDelta > 6 * MONTH_IN_NS) {\r
- unit = YEAR_IN_NS;\r
- } else if (minDelta > 3 * MONTH_IN_NS) {\r
- unit = 6 * MONTH_IN_NS;\r
- } else if (minDelta > 10 * DAY_IN_NS) {\r
- unit = MONTH_IN_NS;\r
- } else if (minDelta > 12 * HOUR_IN_NS) {\r
- unit = DAY_IN_NS;\r
- } else if (minDelta > 3 * HOUR_IN_NS) {\r
- unit = 6 * HOUR_IN_NS;\r
- } else if (minDelta > 30 * MIN_IN_NS) {\r
- unit = HOUR_IN_NS;\r
- } else if (minDelta > 10 * MIN_IN_NS) {\r
- unit = 15 * MIN_IN_NS;\r
- } else if (minDelta > 30 * SEC_IN_NS) {\r
- unit = MIN_IN_NS;\r
- } else if (minDelta > 20 * SEC_IN_NS) {\r
- unit = 30 * SEC_IN_NS;\r
- } else if (minDelta <= 1) {\r
- _timeDelta = 1;\r
- return;\r
- }\r
- }\r
- double log = Math.log10((double) minDelta / unit);\r
- long pow10 = (long) log;\r
- double remainder = log - pow10;\r
- if (remainder < LOG10_1) {\r
- _timeDelta = (long) Math.pow(10, pow10) * unit;\r
- } else if (remainder < LOG10_2) {\r
- _timeDelta = 2 * (long) Math.pow(10, pow10) * unit;\r
- } else if (remainder < LOG10_3 && unit >= HOUR_IN_NS && unit < YEAR_IN_NS) {\r
- _timeDelta = 3 * (long) Math.pow(10, pow10) * unit;\r
- } else if (remainder < LOG10_5) {\r
- _timeDelta = 5 * (long) Math.pow(10, pow10) * unit;\r
- } else {\r
- _timeDelta = 10 * (long) Math.pow(10, pow10) * unit;\r
- }\r
- }\r
-\r
- private static TimeDraw TIMEDRAW_NANOSEC = new TimeDrawNanosec();\r
- private static TimeDraw TIMEDRAW_MICROSEC = new TimeDrawMicrosec();\r
- private static TimeDraw TIMEDRAW_MILLISEC = new TimeDrawMillisec();\r
- private static TimeDraw TIMEDRAW_SEC = new TimeDrawSec();\r
- private static TimeDraw TIMEDRAW_ABS_NANOSEC = new TimeDrawAbsNanoSec();\r
- private static TimeDraw TIMEDRAW_ABS_MICROSEC = new TimeDrawAbsMicroSec();\r
- private static TimeDraw TIMEDRAW_ABS_MILLISEC = new TimeDrawAbsMillisec();\r
- private static TimeDraw TIMEDRAW_ABS_SEC = new TimeDrawAbsSec();\r
- private static TimeDraw TIMEDRAW_ABS_MIN = new TimeDrawAbsMin();\r
- private static TimeDraw TIMEDRAW_ABS_HRS = new TimeDrawAbsHrs();\r
- private static TimeDraw TIMEDRAW_ABS_DAY = new TimeDrawAbsDay();\r
- private static TimeDraw TIMEDRAW_ABS_MONTH = new TimeDrawAbsMonth();\r
- private static TimeDraw TIMEDRAW_ABS_YEAR = new TimeDrawAbsYear();\r
-\r
- TimeDraw getTimeDraw(long timeDelta) {\r
- TimeDraw timeDraw;\r
- if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r
- if (timeDelta >= YEAR_IN_NS) {\r
- timeDraw = TIMEDRAW_ABS_YEAR;\r
- } else if (timeDelta >= MONTH_IN_NS) {\r
- timeDraw = TIMEDRAW_ABS_MONTH;\r
- } else if (timeDelta >= DAY_IN_NS) {\r
- timeDraw = TIMEDRAW_ABS_DAY;\r
- } else if (timeDelta >= HOUR_IN_NS) {\r
- timeDraw = TIMEDRAW_ABS_HRS;\r
- } else if (timeDelta >= MIN_IN_NS) {\r
- timeDraw = TIMEDRAW_ABS_MIN;\r
- } else if (timeDelta >= SEC_IN_NS) {\r
- timeDraw = TIMEDRAW_ABS_SEC;\r
- } else if (timeDelta >= 1000000) {\r
- timeDraw = TIMEDRAW_ABS_MILLISEC;\r
- } else if (timeDelta >= 1000) {\r
- timeDraw = TIMEDRAW_ABS_MICROSEC;\r
- } else {\r
- timeDraw = TIMEDRAW_ABS_NANOSEC;\r
- }\r
- return timeDraw;\r
- }\r
- if (timeDelta >= 1000000000) {\r
- timeDraw = TIMEDRAW_SEC;\r
- } else if (timeDelta >= 1000000) {\r
- timeDraw = TIMEDRAW_MILLISEC;\r
- } else if (timeDelta >= 1000) {\r
- timeDraw = TIMEDRAW_MICROSEC;\r
- } else {\r
- timeDraw = TIMEDRAW_NANOSEC;\r
- }\r
- return timeDraw;\r
- }\r
-\r
- @Override\r
- void paint(Rectangle rect, PaintEvent e) {\r
-\r
- if (_isInUpdate || null == _timeProvider) {\r
- return;\r
- }\r
-\r
- GC gc = e.gc;\r
- gc.fillRectangle(rect);\r
-\r
- long time0 = _timeProvider.getTime0();\r
- long time1 = _timeProvider.getTime1();\r
- long selectedTime = _timeProvider.getSelectedTime();\r
- int leftSpace = _timeProvider.getNameSpace();\r
- int timeSpace = _timeProvider.getTimeSpace();\r
-\r
- gc.setBackground(_colors.getColor(TimeGraphColorScheme.TOOL_BACKGROUND));\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.TOOL_FOREGROUND));\r
- Utils.init(_rect0, rect);\r
-\r
- // draw top left area\r
- _rect0.width = leftSpace;\r
- _rect0.x += 4;\r
- _rect0.width -= 4;\r
- Rectangle absHeaderRect = new Rectangle(_rect0.x, _rect0.y, _rect0.width, _rect0.height);\r
- _rect0.x -= 4;\r
- _rect0.width += 4;\r
-\r
- // prepare and draw right rect of the timescale\r
- _rect0.x += leftSpace;\r
- _rect0.width = rect.width - leftSpace;\r
-\r
- // draw bottom border and erase all other area\r
- gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1,\r
- rect.y + rect.height - 1);\r
- _rect0.height--;\r
- gc.fillRectangle(_rect0);\r
-\r
- if (time1 <= time0 || timeSpace < 2) {\r
- return;\r
- }\r
-\r
- int numDigits = calculateDigits(time0, time1);\r
-\r
- int labelWidth = gc.getCharWidth('0') * numDigits;\r
- double pixelsPerNanoSec = (timeSpace <= RIGHT_MARGIN) ? 0 :\r
- (double) (timeSpace - RIGHT_MARGIN) / (time1 - time0);\r
- calcTimeDelta(labelWidth, pixelsPerNanoSec);\r
-\r
- TimeDraw timeDraw = getTimeDraw(_timeDelta);\r
-\r
- // draw zoom rectangle\r
- if (3 == _dragState && null != _timeProvider) {\r
- if (_dragX0 < _dragX) {\r
- gc.drawRectangle(leftSpace + _dragX0, rect.y, _dragX - _dragX0 - 1, rect.height - 8);\r
- } else if (_dragX0 > _dragX) {\r
- gc.drawRectangle(leftSpace + _dragX, rect.y, _dragX0 - _dragX - 1, rect.height - 8);\r
- }\r
- }\r
-\r
- if (_rect0.isEmpty()) {\r
- return;\r
- }\r
-\r
- // draw selected time\r
- int x = _rect0.x + (int) ((double)(selectedTime - time0) * pixelsPerNanoSec);\r
- if (x >= _rect0.x && x < _rect0.x + _rect0.width) {\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.SELECTED_TIME));\r
- gc.drawLine(x, _rect0.y + _rect0.height - 6, x, _rect0.y\r
- + _rect0.height);\r
- gc.setForeground(_colors.getColor(TimeGraphColorScheme.TOOL_FOREGROUND));\r
- }\r
-\r
- // draw time scale ticks\r
- _rect0.y = rect.y;\r
- _rect0.height = rect.height - 4;\r
- _rect0.width = labelWidth;\r
-\r
- long time;\r
- if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r
- time = floorToCalendar(time0, _timeDelta);\r
- } else {\r
- time = (long) (Math.ceil((double) time0 / _timeDelta) * _timeDelta);\r
- }\r
-\r
- int y = _rect0.y + _rect0.height;\r
-\r
- if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r
- timeDraw.drawAbsHeader(gc, time, absHeaderRect);\r
- }\r
-\r
- while (true) {\r
- x = rect.x + leftSpace + (int) (Math.floor((time - time0) * pixelsPerNanoSec));\r
- if (x >= rect.x + leftSpace + rect.width - _rect0.width) {\r
- break;\r
- }\r
- if (x >= rect.x + leftSpace) {\r
- gc.drawLine(x, y, x, y + 4);\r
- _rect0.x = x;\r
- if (x + _rect0.width <= rect.x + rect.width) {\r
- timeDraw.draw(gc, time, _rect0);\r
- }\r
- }\r
- if (pixelsPerNanoSec == 0 || time > Long.MAX_VALUE - _timeDelta || _timeDelta == 0) {\r
- break;\r
- }\r
- if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r
- if (_timeDelta >= YEAR_IN_NS) {\r
- long millis = time / 1000000L;\r
- GREGORIAN_CALENDAR.setTime(new Date(millis));\r
- GREGORIAN_CALENDAR.add(Calendar.YEAR, (int) (_timeDelta / YEAR_IN_NS));\r
- millis = GREGORIAN_CALENDAR.getTimeInMillis();\r
- time = millis * 1000000L;\r
- } else if (_timeDelta >= MONTH_IN_NS) {\r
- long millis = time / 1000000L;\r
- GREGORIAN_CALENDAR.setTime(new Date(millis));\r
- GREGORIAN_CALENDAR.add(Calendar.MONTH, (int) (_timeDelta / MONTH_IN_NS));\r
- millis = GREGORIAN_CALENDAR.getTimeInMillis();\r
- time = millis * 1000000L;\r
- } else if (_timeDelta >= DAY_IN_NS) {\r
- long millis = time / 1000000L;\r
- GREGORIAN_CALENDAR.setTime(new Date(millis));\r
- GREGORIAN_CALENDAR.add(Calendar.DAY_OF_MONTH, (int) (_timeDelta / DAY_IN_NS));\r
- millis = GREGORIAN_CALENDAR.getTimeInMillis();\r
- time = millis * 1000000L;\r
- } else {\r
- time += _timeDelta;\r
- }\r
- } else {\r
- time += _timeDelta;\r
- }\r
- }\r
- }\r
-\r
- private long floorToCalendar(long time, long timeDelta) {\r
- if (_timeDelta >= YEAR_IN_NS) {\r
- GREGORIAN_CALENDAR.setTime(new Date(time / 1000000));\r
- int year = GREGORIAN_CALENDAR.get(Calendar.YEAR);\r
- int yearDelta = (int) (timeDelta / YEAR_IN_NS);\r
- year = (year / yearDelta) * yearDelta;\r
- GREGORIAN_CALENDAR.set(Calendar.YEAR, year);\r
- GREGORIAN_CALENDAR.set(Calendar.MONTH, 0); // January 1st of year\r
- GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1);\r
- GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);\r
- GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);\r
- GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);\r
- GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);\r
- time = GREGORIAN_CALENDAR.getTimeInMillis() * 1000000;\r
- } else if (_timeDelta >= MONTH_IN_NS) {\r
- GREGORIAN_CALENDAR.setTime(new Date(time / 1000000));\r
- int month = GREGORIAN_CALENDAR.get(Calendar.MONTH);\r
- int monthDelta = (int) (timeDelta / MONTH_IN_NS);\r
- month = (month / monthDelta) * monthDelta;\r
- GREGORIAN_CALENDAR.set(Calendar.MONTH, month);\r
- GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1); // 1st of month\r
- GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);\r
- GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);\r
- GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);\r
- GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);\r
- time = GREGORIAN_CALENDAR.getTimeInMillis() * 1000000;\r
- } else {\r
- long offset = GREGORIAN_CALENDAR.getTimeZone().getOffset(time / 1000000L) * 1000000L;\r
- time += offset;\r
- time = (time / timeDelta) * timeDelta;\r
- time -= offset;\r
- }\r
- return time;\r
- }\r
-\r
- private int calculateDigits(long time0, long time1) {\r
- int numDigits = 5;\r
- long timeRange = time1 - time0;\r
-\r
- if (_timeProvider.isCalendarFormat()) {\r
- // Calculate the number of digits to represent the minutes provided\r
- // 11:222\r
- // HH:mm:ss\r
- numDigits += 8;\r
- if (timeRange < 10000) {\r
- // HH:11:222:333:444__\r
- numDigits += 10;\r
- } else if (timeRange < 10000000) {\r
- // HH:11:222:333__\r
- numDigits += 6;\r
- }\r
- } else {\r
- // Calculate the number of digits to represent the minutes provided\r
- long min = (long) ((time1 * 1E-9) / 60); // to sec then to minutes\r
- String strMinutes = String.valueOf(min);\r
- // 11:222\r
- if (strMinutes != null) {\r
- numDigits += strMinutes.length();\r
- } else {\r
- numDigits += 2;\r
- }\r
- if (timeRange < 10000) {\r
- // 11:222:333:444__\r
- numDigits += 8;\r
- } else if (timeRange < 10000000) {\r
- // 11:222:333__\r
- numDigits += 4;\r
- }\r
- }\r
-\r
- return numDigits;\r
- }\r
-\r
- @Override\r
- public void mouseDown(MouseEvent e) {\r
- getParent().setFocus();\r
- if (_dragState == 0 && null != _timeProvider) {\r
- int x = e.x - _timeProvider.getNameSpace();\r
- if (1 == e.button && x > 0) {\r
- setCapture(true);\r
- _dragState = 1;\r
- } else if (3 == e.button) {\r
- _dragState = 3;\r
- }\r
- if (x < 0) {\r
- x = 0;\r
- } else if (x > getSize().x - _timeProvider.getNameSpace()) {\r
- x = getSize().x - _timeProvider.getNameSpace();\r
- }\r
- _dragX = _dragX0 = x;\r
- _time0bak = _timeProvider.getTime0();\r
- _time1bak = _timeProvider.getTime1();\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseUp(MouseEvent e) {\r
- if (e.button == 1 && _dragState == 1) {\r
- setCapture(false);\r
- _dragState = 0;\r
-\r
- // Notify time provider to check the need for listener notification\r
- if (_dragX != _dragX0 && _timeProvider.getTime0() != _timeProvider.getTime1()) {\r
- _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());\r
- }\r
- } else if (e.button == 3 && _dragState == 3 && null != _timeProvider) {\r
- _dragState = 0;\r
- if (_dragX0 == _dragX || _timeProvider.getTime0() == _timeProvider.getTime1()) {\r
- return;\r
- }\r
- int timeSpace = _timeProvider.getTimeSpace();\r
- int leftSpace = _timeProvider.getNameSpace();\r
- int x = Math.max(0, e.x - leftSpace);\r
- if (timeSpace > 0) {\r
- _dragX = x;\r
- if (_dragX0 > _dragX) { // drag right to left\r
- _dragX = _dragX0;\r
- _dragX0 = x;\r
- }\r
- long time0 = _time0bak + (long) ((_time1bak - _time0bak) * ((double) _dragX0 / timeSpace));\r
- long time1 = _time0bak + (long) ((_time1bak - _time0bak) * ((double) _dragX / timeSpace));\r
-\r
- _timeProvider.setStartFinishTimeNotify(time0, time1);\r
- _time0bak = _timeProvider.getTime0();\r
- _time1bak = _timeProvider.getTime1();\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseMove(MouseEvent e) {\r
- if (_dragX0 < 0 || _dragState == 0 || _timeProvider == null) {\r
- return;\r
- }\r
- Point size = getSize();\r
- int leftSpace = _timeProvider.getNameSpace();\r
- int timeSpace = _timeProvider.getTimeSpace();\r
- int x = e.x - leftSpace;\r
- if (1 == _dragState) {\r
- if (x > 0 && size.x > leftSpace && _dragX != x) {\r
- _dragX = x;\r
- if (_timeProvider.getTime0() == _timeProvider.getTime1()) {\r
- return;\r
- }\r
- long interval = (long) ((_time1bak - _time0bak) * ((double) _dragX0 / _dragX));\r
- if (interval == Long.MAX_VALUE) {\r
- _timeProvider.setStartFinishTime(_time0bak, Long.MAX_VALUE);\r
- } else {\r
- long time1 = _time0bak + (long) ((_time1bak - _time0bak) * ((double) _dragX0 / _dragX));\r
- _timeProvider.setStartFinishTime(_time0bak, time1);\r
- }\r
- }\r
- } else if (3 == _dragState) {\r
- if (x < 0) {\r
- _dragX = 0;\r
- } else if (x > timeSpace) {\r
- _dragX = timeSpace;\r
- } else {\r
- _dragX = x;\r
- }\r
- redraw();\r
- }\r
- }\r
-\r
- @Override\r
- public void mouseDoubleClick(MouseEvent e) {\r
- if (null != _timeProvider && _timeProvider.getTime0() != _timeProvider.getTime1()) {\r
- _timeProvider.resetStartFinishTime();\r
- _time0bak = _timeProvider.getTime0();\r
- _time1bak = _timeProvider.getTime1();\r
- }\r
- }\r
-}\r
-\r
-abstract class TimeDraw {\r
- static String S = ":" ; //$NON-NLS-1$\r
- static String S0 = ":0" ; //$NON-NLS-1$\r
- static String S00 = ":00"; //$NON-NLS-1$\r
- protected static final SimpleDateFormat stimeformat = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat stimeformatheader = new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat sminformat = new SimpleDateFormat("HH:mm"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat sminformatheader = new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat shrsformat = new SimpleDateFormat("MMM dd HH:mm"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat shrsformatheader = new SimpleDateFormat("yyyy"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat sdayformat = new SimpleDateFormat("MMM dd"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat sdayformatheader = new SimpleDateFormat("yyyy"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat smonthformat = new SimpleDateFormat("yyyy MMM"); //$NON-NLS-1$\r
- protected static final SimpleDateFormat syearformat = new SimpleDateFormat("yyyy"); //$NON-NLS-1$\r
-\r
- static String pad(long n) {\r
- String s = S;\r
- if (n < 10) {\r
- s = S00;\r
- } else if (n < 100) {\r
- s = S0;\r
- }\r
- return s + n;\r
- }\r
-\r
- public abstract void draw(GC gc, long time, Rectangle rect);\r
-\r
- public void drawAbsHeader(GC gc, long time, Rectangle absHeaderRect) {\r
- // Override to draw absolute time header\r
- // This is for the time information not shown in the draw of each tick\r
- }\r
-\r
- public abstract String hint();\r
-}\r
-\r
-class TimeDrawSec extends TimeDraw {\r
- static String _hint = "sec"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- time /= 1000000000;\r
- Utils.drawText(gc, time + "", rect, true); //$NON-NLS-1$\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawMillisec extends TimeDraw {\r
- static String _hint = "s:ms"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- time /= 1000000;\r
- long ms = time % 1000;\r
- time /= 1000;\r
- Utils.drawText(gc, time + pad(ms), rect, true);\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawMicrosec extends TimeDraw {\r
- static String _hint = "s:ms:mcs"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- time /= 1000;\r
- long mcs = time % 1000;\r
- time /= 1000;\r
- long ms = time % 1000;\r
- time /= 1000;\r
- Utils.drawText(gc, time + pad(ms) + pad(mcs), rect, true);\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawNanosec extends TimeDraw {\r
- static String _hint = "s:ms:mcs:ns"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- long ns = time % 1000;\r
- time /= 1000;\r
- long mcs = time % 1000;\r
- time /= 1000;\r
- long ms = time % 1000;\r
- time /= 1000;\r
- Utils.drawText(gc, time + pad(ms) + pad(mcs) + pad(ns), rect, true);\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsYear extends TimeDraw {\r
- static String _hint = "YYYY"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = syearformat.format(new Date((long) (time / 1000000)));\r
- Utils.drawText(gc, stime, rect, true);\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsMonth extends TimeDraw {\r
- static String _hint = "YYYY Mmm"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = smonthformat.format(new Date((long) (time / 1000000)));\r
- Utils.drawText(gc, stime, rect, true);\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsDay extends TimeDraw {\r
- static String _hint = "Mmm dd"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = sdayformat.format(new Date((long) (time / 1000000)));\r
- Utils.drawText(gc, stime, rect, true);\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = sdayformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsHrs extends TimeDraw {\r
- static String _hint = "Mmm dd HH:mm"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = shrsformat.format(new Date((long) (time / 1000000)));\r
- Utils.drawText(gc, stime, rect, true);\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = shrsformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsMin extends TimeDraw {\r
- static String _hint = "HH:mm"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = sminformat.format(new Date((long) (time / 1000000)));\r
- Utils.drawText(gc, stime, rect, true);\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = sminformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsSec extends TimeDraw {\r
- static String _hint = "HH:mm:ss"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = stimeformat.format(new Date((long) (time / 1000000)));\r
- Utils.drawText(gc, stime, rect, true);\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsMillisec extends TimeDraw {\r
- static String _hint = "HH:ss:ms"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = stimeformat.format(new Date((long) (time / 1000000)));\r
- String ns = Utils.formatNs(time, Resolution.MILLISEC);\r
-\r
- Utils.drawText(gc, stime + "." + ns, rect, true); //$NON-NLS-1$\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsMicroSec extends TimeDraw {\r
- static String _hint = "HH:ss:ms:mcs"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = stimeformat.format(new Date((long) (time / 1000000)));\r
- String micr = Utils.formatNs(time, Resolution.MICROSEC);\r
- Utils.drawText(gc, stime + "." + micr, rect, true); //$NON-NLS-1$\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
-\r
-class TimeDrawAbsNanoSec extends TimeDraw {\r
- static String _hint = "HH:ss:ms:mcs:ns"; //$NON-NLS-1$\r
-\r
- @Override\r
- public void draw(GC gc, long time, Rectangle rect) {\r
- String stime = stimeformat.format(new Date((long) (time / 1000000)));\r
- String ns = Utils.formatNs(time, Resolution.NANOSEC);\r
- Utils.drawText(gc, stime + "." + ns, rect, true); //$NON-NLS-1$\r
- }\r
-\r
- @Override\r
- public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r
- String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r
- int headerwidth = gc.stringExtent(header).x + 4;\r
- if (headerwidth <= rect.width) {\r
- rect.x += (rect.width - headerwidth);\r
- Utils.drawText(gc, header, rect, true);\r
- }\r
- }\r
-\r
- @Override\r
- public String hint() {\r
- return _hint;\r
- }\r
-}\r
+/*****************************************************************************
+ * Copyright (c) 2007, 2014 Intel Corporation, Ericsson
+ * 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:
+ * Intel Corporation - Initial API and implementation
+ * Ruslan A. Scherbakov, Intel - Initial API and implementation
+ * Alvaro Sanchez-Leon - Updated for TMF
+ * Patrick Tasse - Refactoring
+ * Marc-Andre Laperle - Add time zone preference
+ *****************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;
+
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.eclipse.linuxtools.internal.tmf.ui.Messages;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTimestampFormatUpdateSignal;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimePreferences;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Implementation of the scale for the time graph view.
+ *
+ * This goes above the "gantt chart" area.
+ *
+ * @version 1.0
+ * @author Alvaro Sanchez-Leon
+ * @author Patrick Tasse
+ */
+public class TimeGraphScale extends TimeGraphBaseControl implements
+ MouseListener, MouseMoveListener {
+
+ private static final long MICROSEC_IN_NS = 1000;
+ private static final long MILLISEC_IN_NS = 1000000;
+ private static final long SEC_IN_NS = 1000000000;
+ private static final long MIN_IN_NS = 60 * SEC_IN_NS;
+ private static final long HOUR_IN_NS = 60 * MIN_IN_NS;
+ private static final long DAY_IN_NS = 24 * HOUR_IN_NS;
+ private static final long MONTH_IN_NS = 31 * DAY_IN_NS; // upper limit
+ private static final long YEAR_IN_NS = 366 * DAY_IN_NS; // upper limit
+
+ private static final double LOG10_1 = Math.log10(1);
+ private static final double LOG10_2 = Math.log10(2);
+ private static final double LOG10_3 = Math.log10(3);
+ private static final double LOG10_5 = Math.log10(5);
+
+ private static final Calendar GREGORIAN_CALENDAR = Calendar.getInstance();
+
+ private static final TimeDraw TIMEDRAW_NANOSEC = new TimeDrawNanosec();
+ private static final TimeDraw TIMEDRAW_MICROSEC = new TimeDrawMicrosec();
+ private static final TimeDraw TIMEDRAW_MILLISEC = new TimeDrawMillisec();
+ private static final TimeDraw TIMEDRAW_SEC = new TimeDrawSec();
+ private static final TimeDraw TIMEDRAW_ABS_NANOSEC = new TimeDrawAbsNanoSec();
+ private static final TimeDraw TIMEDRAW_ABS_MICROSEC = new TimeDrawAbsMicroSec();
+ private static final TimeDraw TIMEDRAW_ABS_MILLISEC = new TimeDrawAbsMillisec();
+ private static final TimeDraw TIMEDRAW_ABS_SEC = new TimeDrawAbsSec();
+ private static final TimeDraw TIMEDRAW_ABS_MIN = new TimeDrawAbsMin();
+ private static final TimeDraw TIMEDRAW_ABS_HRS = new TimeDrawAbsHrs();
+ private static final TimeDraw TIMEDRAW_ABS_DAY = new TimeDrawAbsDay();
+ private static final TimeDraw TIMEDRAW_ABS_MONTH = new TimeDrawAbsMonth();
+ private static final TimeDraw TIMEDRAW_ABS_YEAR = new TimeDrawAbsYear();
+ private static final TimeDraw TIMEDRAW_NUMBER = new TimeDrawNumber();
+ private static final TimeDraw TIMEDRAW_CYCLES = new TimeDrawCycles();
+
+ private static final int DRAG_EXTERNAL = -1;
+ private static final int NO_BUTTON = 0;
+ private static final int LEFT_BUTTON = 1;
+
+ private ITimeDataProvider fTimeProvider;
+ private int fDragState = NO_BUTTON;
+ private int fDragX0 = 0;
+ private int fDragX = 0;
+ private long fTime0bak;
+ private long fTime1bak;
+ private boolean fIsInUpdate;
+ private int fHeight;
+
+ /**
+ * Standard constructor
+ *
+ * @param parent
+ * The parent composite object
+ * @param colors
+ * The color scheme to use
+ */
+ public TimeGraphScale(Composite parent, TimeGraphColorScheme colors) {
+ super(parent, colors, SWT.NO_BACKGROUND | SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED);
+ TmfSignalManager.register(this);
+ addMouseListener(this);
+ addMouseMoveListener(this);
+ TimeDraw.updateTimeZone();
+ }
+
+ @Override
+ public void dispose() {
+ TmfSignalManager.deregister(this);
+ super.dispose();
+ }
+
+ /**
+ * Assign the time provider for this scale
+ *
+ * @param timeProvider
+ * The provider to use
+ */
+ public void setTimeProvider(ITimeDataProvider timeProvider) {
+ fTimeProvider = timeProvider;
+ }
+
+ /**
+ * Get the time provider used by this scale
+ *
+ * @return The time provider
+ * @since 3.1
+ */
+ public ITimeDataProvider getTimeProvider() {
+ return fTimeProvider;
+ }
+
+ @Override
+ public Point computeSize(int wHint, int hHint, boolean changed) {
+ return super.computeSize(wHint, fHeight, changed);
+ }
+
+ /**
+ * Set the height of the scale
+ *
+ * @param height
+ * The height to use
+ */
+ public void setHeight(int height) {
+ this.fHeight = height;
+ }
+
+ /**
+ * Set the drag range to paint decorators
+ *
+ * @param begin
+ * The begin x-coordinate
+ * @param end
+ * The end x-coordinate
+ * @since 2.1
+ */
+ public void setDragRange(int begin, int end) {
+ if (NO_BUTTON == fDragState || DRAG_EXTERNAL == fDragState) {
+ fDragX0 = begin - fTimeProvider.getNameSpace();
+ fDragX = end - fTimeProvider.getNameSpace();
+ if (begin >= 0 || end >= 0) {
+ fDragState = DRAG_EXTERNAL;
+ } else {
+ fDragState = NO_BUTTON;
+ }
+ }
+ redraw();
+ }
+
+ private long calcTimeDelta(int width, double pixelsPerNanoSec) {
+ long timeDelta;
+ double minDelta = (pixelsPerNanoSec == 0) ? YEAR_IN_NS : width / pixelsPerNanoSec;
+ long unit = 1;
+ if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
+ if (minDelta > 6 * MONTH_IN_NS) {
+ unit = YEAR_IN_NS;
+ } else if (minDelta > 3 * MONTH_IN_NS) {
+ unit = 6 * MONTH_IN_NS;
+ } else if (minDelta > 10 * DAY_IN_NS) {
+ unit = MONTH_IN_NS;
+ } else if (minDelta > 12 * HOUR_IN_NS) {
+ unit = DAY_IN_NS;
+ } else if (minDelta > 3 * HOUR_IN_NS) {
+ unit = 6 * HOUR_IN_NS;
+ } else if (minDelta > 30 * MIN_IN_NS) {
+ unit = HOUR_IN_NS;
+ } else if (minDelta > 10 * MIN_IN_NS) {
+ unit = 15 * MIN_IN_NS;
+ } else if (minDelta > 30 * SEC_IN_NS) {
+ unit = MIN_IN_NS;
+ } else if (minDelta > 20 * SEC_IN_NS) {
+ unit = 30 * SEC_IN_NS;
+ } else if (minDelta <= 1) {
+ timeDelta = 1;
+ return timeDelta;
+ }
+ }
+ double log = Math.log10(minDelta / unit);
+ long pow10 = (long) log;
+ double remainder = log - pow10;
+ if (remainder < LOG10_1) {
+ timeDelta = (long) Math.pow(10, pow10) * unit;
+ } else if (remainder < LOG10_2) {
+ timeDelta = 2 * (long) Math.pow(10, pow10) * unit;
+ } else if (remainder < LOG10_3 && unit >= HOUR_IN_NS && unit < YEAR_IN_NS) {
+ timeDelta = 3 * (long) Math.pow(10, pow10) * unit;
+ } else if (remainder < LOG10_5) {
+ timeDelta = 5 * (long) Math.pow(10, pow10) * unit;
+ } else {
+ timeDelta = 10 * (long) Math.pow(10, pow10) * unit;
+ }
+ if (timeDelta <= 0) {
+ timeDelta = 1;
+ }
+ return timeDelta;
+ }
+
+ TimeDraw getTimeDraw(long timeDelta) {
+ TimeDraw timeDraw;
+ if (fTimeProvider != null) {
+ switch (fTimeProvider.getTimeFormat()) {
+ case CALENDAR:
+ if (timeDelta >= YEAR_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_YEAR;
+ } else if (timeDelta >= MONTH_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_MONTH;
+ } else if (timeDelta >= DAY_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_DAY;
+ } else if (timeDelta >= HOUR_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_HRS;
+ } else if (timeDelta >= MIN_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_MIN;
+ } else if (timeDelta >= SEC_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_SEC;
+ } else if (timeDelta >= MILLISEC_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_MILLISEC;
+ } else if (timeDelta >= MICROSEC_IN_NS) {
+ timeDraw = TIMEDRAW_ABS_MICROSEC;
+ } else {
+ timeDraw = TIMEDRAW_ABS_NANOSEC;
+ }
+ return timeDraw;
+ case NUMBER:
+ return TIMEDRAW_NUMBER;
+ case CYCLES:
+ return TIMEDRAW_CYCLES;
+ case RELATIVE:
+ default:
+ }
+
+ }
+ if (timeDelta >= SEC_IN_NS) {
+ timeDraw = TIMEDRAW_SEC;
+ } else if (timeDelta >= MILLISEC_IN_NS) {
+ timeDraw = TIMEDRAW_MILLISEC;
+ } else if (timeDelta >= MICROSEC_IN_NS) {
+ timeDraw = TIMEDRAW_MICROSEC;
+ } else {
+ timeDraw = TIMEDRAW_NANOSEC;
+ }
+ return timeDraw;
+ }
+
+ @Override
+ void paint(Rectangle rect, PaintEvent e) {
+
+ if (fIsInUpdate || null == fTimeProvider) {
+ return;
+ }
+
+ GC gc = e.gc;
+ gc.fillRectangle(rect);
+
+ long time0 = fTimeProvider.getTime0();
+ long time1 = fTimeProvider.getTime1();
+ int leftSpace = fTimeProvider.getNameSpace();
+ int timeSpace = fTimeProvider.getTimeSpace();
+
+ gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.TOOL_BACKGROUND));
+ gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.TOOL_FOREGROUND));
+ Rectangle rect0 = new Rectangle(0, 0, 0, 0);
+ Utils.init(rect0, rect);
+
+ // draw top left area
+ rect0.width = leftSpace;
+ rect0.x += 4;
+ rect0.width -= 4;
+ Rectangle absHeaderRect = new Rectangle(rect0.x, rect0.y, rect0.width, rect0.height);
+ rect0.x -= 4;
+ rect0.width += 4;
+
+ // prepare and draw right rect of the timescale
+ rect0.x += leftSpace;
+ rect0.width = rect.width - leftSpace;
+
+ // draw bottom border and erase all other area
+ gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1,
+ rect.y + rect.height - 1);
+ rect0.height--;
+ gc.fillRectangle(rect0);
+
+ if (time1 <= time0 || timeSpace < 2) {
+ return;
+ }
+
+ int numDigits = calculateDigits(time0, time1);
+
+ int labelWidth = gc.getCharWidth('0') * numDigits;
+ double pixelsPerNanoSec = (timeSpace <= RIGHT_MARGIN) ? 0 :
+ (double) (timeSpace - RIGHT_MARGIN) / (time1 - time0);
+ long timeDelta = calcTimeDelta(labelWidth, pixelsPerNanoSec);
+
+ TimeDraw timeDraw = getTimeDraw(timeDelta);
+
+ // draw range decorators
+ if (DRAG_EXTERNAL == fDragState) {
+ int x1 = leftSpace + Math.min(fDragX0, fDragX);
+ int x2 = leftSpace + Math.max(fDragX0, fDragX);
+ drawRangeDecorators(rect0, gc, x1, x2);
+ } else {
+ int x1;
+ int x2;
+ long selectionBegin = fTimeProvider.getSelectionBegin();
+ long selectionEnd = fTimeProvider.getSelectionEnd();
+ x1 = leftSpace + (int) ((selectionBegin - time0) * pixelsPerNanoSec);
+ x2 = leftSpace + (int) ((selectionEnd - time0) * pixelsPerNanoSec);
+ drawRangeDecorators(rect0, gc, x1, x2);
+ }
+
+ if (rect0.isEmpty()) {
+ return;
+ }
+
+ // draw time scale ticks
+ rect0.y = rect.y;
+ rect0.height = rect.height - 4;
+ rect0.width = labelWidth;
+
+ long time;
+ if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
+ time = floorToCalendar(time0, timeDelta);
+ } else {
+ time = (time0 / timeDelta) * timeDelta;
+ if (time != time0) {
+ time += timeDelta;
+ }
+ }
+
+ int y = rect0.y + rect0.height;
+
+ if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
+ timeDraw.drawAbsHeader(gc, time, absHeaderRect);
+ }
+
+ while (true) {
+ int x = rect.x + leftSpace + (int) (Math.floor((time - time0) * pixelsPerNanoSec));
+ if (x >= rect.x + leftSpace + rect.width - rect0.width) {
+ break;
+ }
+ if (x >= rect.x + leftSpace) {
+ gc.drawLine(x, y, x, y + 4);
+ rect0.x = x;
+ if (x + rect0.width <= rect.x + rect.width) {
+ timeDraw.draw(gc, time, rect0);
+ }
+ }
+ if (pixelsPerNanoSec == 0 || time > Long.MAX_VALUE - timeDelta || timeDelta == 0) {
+ break;
+ }
+ if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
+ if (timeDelta >= YEAR_IN_NS) {
+ long millis = time / MILLISEC_IN_NS;
+ GREGORIAN_CALENDAR.setTime(new Date(millis));
+ GREGORIAN_CALENDAR.add(Calendar.YEAR, (int) (timeDelta / YEAR_IN_NS));
+ millis = GREGORIAN_CALENDAR.getTimeInMillis();
+ time = millis * MILLISEC_IN_NS;
+ } else if (timeDelta >= MONTH_IN_NS) {
+ long millis = time / MILLISEC_IN_NS;
+ GREGORIAN_CALENDAR.setTime(new Date(millis));
+ GREGORIAN_CALENDAR.add(Calendar.MONTH, (int) (timeDelta / MONTH_IN_NS));
+ millis = GREGORIAN_CALENDAR.getTimeInMillis();
+ time = millis * MILLISEC_IN_NS;
+ } else if (timeDelta >= DAY_IN_NS) {
+ long millis = time / MILLISEC_IN_NS;
+ GREGORIAN_CALENDAR.setTime(new Date(millis));
+ GREGORIAN_CALENDAR.add(Calendar.DAY_OF_MONTH, (int) (timeDelta / DAY_IN_NS));
+ millis = GREGORIAN_CALENDAR.getTimeInMillis();
+ time = millis * MILLISEC_IN_NS;
+ } else {
+ time += timeDelta;
+ }
+ } else {
+ time += timeDelta;
+ }
+ }
+ }
+
+ private static void drawRangeDecorators(Rectangle rect, GC gc, int x1, int x2) {
+ int y1 = rect.y + rect.height - 9;
+ int y2 = rect.y + rect.height - 5;
+ int ym = (y1 + y2) / 2;
+ if (x1 >= rect.x) {
+ // T1
+ gc.drawLine(x1 - 3, y1, x1 - 3, y2);
+ gc.drawLine(x1 - 4, y1, x1 - 2, y1);
+ gc.drawLine(x1, y1, x1, y2);
+ }
+ if (x2 >= rect.x && x2 - x1 > 3) {
+ // T2
+ gc.drawLine(x2 - 2, y1, x2 - 2, y2);
+ gc.drawLine(x2 - 3, y1, x2 - 1, y1);
+ }
+ if (x2 >= rect.x && x2 - x1 > 0) {
+ gc.drawLine(x2 + 1, y1, x2 + 3, y1);
+ gc.drawLine(x2 + 3, y1, x2 + 3, ym);
+ gc.drawLine(x2 + 1, ym, x2 + 3, ym);
+ gc.drawLine(x2 + 1, ym, x2 + 1, y2);
+ gc.drawLine(x2 + 1, y2, x2 + 3, y2);
+ }
+ }
+
+ private static long floorToCalendar(long time, long timeDelta) {
+ long ret = time;
+
+ if (timeDelta >= YEAR_IN_NS) {
+ GREGORIAN_CALENDAR.setTime(new Date(ret / MILLISEC_IN_NS));
+ int year = GREGORIAN_CALENDAR.get(Calendar.YEAR);
+ int yearDelta = (int) (timeDelta / YEAR_IN_NS);
+ year = (year / yearDelta) * yearDelta;
+ GREGORIAN_CALENDAR.set(Calendar.YEAR, year);
+ GREGORIAN_CALENDAR.set(Calendar.MONTH, 0); // January 1st of year
+ GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1);
+ GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);
+ GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);
+ GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);
+ GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);
+ ret = GREGORIAN_CALENDAR.getTimeInMillis() * MILLISEC_IN_NS;
+ } else if (timeDelta >= MONTH_IN_NS) {
+ GREGORIAN_CALENDAR.setTime(new Date(ret / MILLISEC_IN_NS));
+ int month = GREGORIAN_CALENDAR.get(Calendar.MONTH);
+ int monthDelta = (int) (timeDelta / MONTH_IN_NS);
+ month = (month / monthDelta) * monthDelta;
+ GREGORIAN_CALENDAR.set(Calendar.MONTH, month);
+ GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1); // 1st of month
+ GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);
+ GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);
+ GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);
+ GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);
+ ret = GREGORIAN_CALENDAR.getTimeInMillis() * MILLISEC_IN_NS;
+ } else {
+ long offset = GREGORIAN_CALENDAR.getTimeZone().getOffset(ret / MILLISEC_IN_NS) * MILLISEC_IN_NS;
+ ret += offset;
+ ret = (ret / timeDelta) * timeDelta;
+ ret -= offset;
+ }
+ return ret;
+ }
+
+ private int calculateDigits(long time0, long time1) {
+ int numDigits = 5;
+ long timeRange = time1 - time0;
+
+ if (fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
+ // Calculate the number of digits to represent the minutes provided
+ // 11:222
+ // HH:mm:ss
+ numDigits += 8;
+ if (timeRange < 10000) {
+ // HH:11:222:333:444__
+ numDigits += 10;
+ } else if (timeRange < 10000000) {
+ // HH:11:222:333__
+ numDigits += 6;
+ }
+ } else {
+ long sec = time1 / SEC_IN_NS;
+ numDigits = Long.toString(sec).length();
+ int thousandGroups = (numDigits - 1) / 3;
+ numDigits += thousandGroups;
+ numDigits += 12; // .000 000 000
+ if (fTimeProvider.getTimeFormat() == TimeFormat.CYCLES) {
+ numDigits += Messages.Utils_ClockCyclesUnit.length();
+ }
+ }
+
+ return numDigits;
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ getParent().setFocus();
+ if (fDragState == NO_BUTTON && null != fTimeProvider) {
+ int x = e.x - fTimeProvider.getNameSpace();
+ if (LEFT_BUTTON == e.button && x > 0) {
+ setCapture(true);
+ fDragState = LEFT_BUTTON;
+ }
+ if (x < 0) {
+ x = 0;
+ } else if (x > getSize().x - fTimeProvider.getNameSpace()) {
+ x = getSize().x - fTimeProvider.getNameSpace();
+ }
+ fDragX = x;
+ fDragX0 = x;
+ fTime0bak = fTimeProvider.getTime0();
+ fTime1bak = fTimeProvider.getTime1();
+ }
+ }
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ if (e.button == LEFT_BUTTON && fDragState == LEFT_BUTTON) {
+ setCapture(false);
+ fDragState = NO_BUTTON;
+
+ // Notify time provider to check the need for listener notification
+ if (fDragX != fDragX0 && fTimeProvider.getTime0() != fTimeProvider.getTime1()) {
+ fTimeProvider.setStartFinishTimeNotify(fTimeProvider.getTime0(), fTimeProvider.getTime1());
+ }
+ }
+ }
+
+ @Override
+ public void mouseMove(MouseEvent e) {
+ if (fDragX0 < 0 || fDragState == NO_BUTTON || fTimeProvider == null) {
+ return;
+ }
+ Point size = getSize();
+ int leftSpace = fTimeProvider.getNameSpace();
+ int x = e.x - leftSpace;
+ if (LEFT_BUTTON == fDragState) {
+ if (x > 0 && size.x > leftSpace && fDragX != x) {
+ fDragX = x;
+ if (fTimeProvider.getTime0() == fTimeProvider.getTime1()) {
+ return;
+ }
+ long interval = (long) ((fTime1bak - fTime0bak) * ((double) fDragX0 / fDragX));
+ if (interval == Long.MAX_VALUE) {
+ fTimeProvider.setStartFinishTime(fTime0bak, Long.MAX_VALUE);
+ } else {
+ long time1 = fTime0bak + (long) ((fTime1bak - fTime0bak) * ((double) fDragX0 / fDragX));
+ fTimeProvider.setStartFinishTime(fTime0bak, time1);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ if (e.button == 1 && null != fTimeProvider && fTimeProvider.getTime0() != fTimeProvider.getTime1() && (e.stateMask & SWT.BUTTON_MASK) == 0) {
+ fTimeProvider.resetStartFinishTime();
+ fTimeProvider.notifyStartFinishTime();
+ fTime0bak = fTimeProvider.getTime0();
+ fTime1bak = fTimeProvider.getTime1();
+ }
+ }
+
+ /**
+ * Update the display to use the updated timestamp format
+ *
+ * @param signal the incoming signal
+ * @since 2.1
+ */
+ @TmfSignalHandler
+ public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
+ TimeDraw.updateTimeZone();
+ Utils.updateTimeZone();
+ redraw();
+ }
+}
+
+abstract class TimeDraw {
+ protected static final long MICROSEC_IN_NS = 1000;
+ protected static final long MILLISEC_IN_NS = 1000000;
+ protected static final long MILLISEC_IN_US = 1000;
+ protected static final long SEC_IN_NS = 1000000000;
+ protected static final long SEC_IN_MS = 1000;
+ private static final String S = "" ; //$NON-NLS-1$
+ private static final String S0 = "0" ; //$NON-NLS-1$
+ private static final String S00 = "00"; //$NON-NLS-1$
+ protected static final long PAD_1000 = 1000;
+ protected static final SimpleDateFormat SEC_FORMAT_HEADER = new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
+ protected static final SimpleDateFormat SEC_FORMAT = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
+ protected static final SimpleDateFormat MIN_FORMAT_HEADER = new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
+ protected static final SimpleDateFormat MIN_FORMAT = new SimpleDateFormat("HH:mm"); //$NON-NLS-1$
+ protected static final SimpleDateFormat HOURS_FORMAT_HEADER = new SimpleDateFormat("yyyy"); //$NON-NLS-1$
+ protected static final SimpleDateFormat HOURS_FORMAT = new SimpleDateFormat("MMM dd HH:mm"); //$NON-NLS-1$
+ protected static final SimpleDateFormat DAY_FORMAT_HEADER = new SimpleDateFormat("yyyy"); //$NON-NLS-1$
+ protected static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("MMM dd"); //$NON-NLS-1$
+ protected static final SimpleDateFormat MONTH_FORMAT = new SimpleDateFormat("yyyy MMM"); //$NON-NLS-1$
+ protected static final SimpleDateFormat YEAR_FORMAT = new SimpleDateFormat("yyyy"); //$NON-NLS-1$
+
+ protected static final SimpleDateFormat formatArray[] = {
+ SEC_FORMAT, SEC_FORMAT_HEADER, MIN_FORMAT, MIN_FORMAT_HEADER,
+ HOURS_FORMAT, HOURS_FORMAT_HEADER, DAY_FORMAT, DAY_FORMAT_HEADER, MONTH_FORMAT, YEAR_FORMAT
+ };
+
+ /**
+ * Updates the timezone using the preferences.
+ */
+ public static void updateTimeZone() {
+ final TimeZone timeZone = TmfTimePreferences.getInstance().getTimeZone();
+ for (SimpleDateFormat sdf : formatArray) {
+ sdf.setTimeZone(timeZone);
+ }
+ }
+
+ static String sep(long n) {
+ StringBuilder retVal = new StringBuilder();
+ String s = Long.toString(n);
+ for (int i = 0; i < s.length(); i++) {
+ int pos = s.length() - i - 1;
+ retVal.append(s.charAt(i));
+ if (pos % 3 == 0 && pos != 0) {
+ retVal.append(' ');
+ }
+ }
+ return retVal.toString();
+ }
+
+ static String pad(long n) {
+ String s;
+ if (n < 10) {
+ s = S00;
+ } else if (n < 100) {
+ s = S0;
+ } else {
+ s = S;
+ }
+ return s + n;
+ }
+
+ public abstract int draw(GC gc, long time, Rectangle rect);
+
+ /**
+ * Override to draw absolute time header. This is for the time information
+ * not shown in the draw of each tick
+ *
+ * @param gc
+ * Graphics context
+ * @param nanosec
+ * time in nanosec
+ * @param absHeaderRect
+ * Header rectangle
+ */
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle absHeaderRect) {
+ }
+}
+
+class TimeDrawSec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ long sec = nanosec / SEC_IN_NS;
+ return Utils.drawText(gc, sep(sec), rect, true);
+ }
+}
+
+class TimeDrawMillisec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ long millisec = nanosec / MILLISEC_IN_NS;
+ long ms = millisec % PAD_1000;
+ long sec = millisec / SEC_IN_MS;
+ return Utils.drawText(gc, sep(sec) + "." + pad(ms), rect, true); //$NON-NLS-1$
+ }
+}
+
+class TimeDrawMicrosec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ long microsec = nanosec / MICROSEC_IN_NS;
+ long us = microsec % PAD_1000;
+ long millisec = microsec / MILLISEC_IN_US;
+ long ms = millisec % PAD_1000;
+ long sec = millisec / SEC_IN_MS;
+ return Utils.drawText(gc, sep(sec) + "." + pad(ms) + " " + pad(us), rect, true); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
+
+class TimeDrawNanosec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ long ns = nanosec % PAD_1000;
+ long microsec = nanosec / MICROSEC_IN_NS;
+ long us = microsec % PAD_1000;
+ long millisec = microsec / MILLISEC_IN_US;
+ long ms = millisec % PAD_1000;
+ long sec = millisec / SEC_IN_MS;
+ return Utils.drawText(gc, sep(sec) + "." + pad(ms) + " " + pad(us) + " " + pad(ns), rect, true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+}
+
+class TimeDrawAbsYear extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = YEAR_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ return Utils.drawText(gc, stime, rect, true);
+ }
+}
+
+class TimeDrawAbsMonth extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = MONTH_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ return Utils.drawText(gc, stime, rect, true);
+ }
+}
+
+class TimeDrawAbsDay extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = DAY_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ return Utils.drawText(gc, stime, rect, true);
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = DAY_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawAbsHrs extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = HOURS_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ return Utils.drawText(gc, stime, rect, true);
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = HOURS_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawAbsMin extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = MIN_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ return Utils.drawText(gc, stime, rect, true);
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = MIN_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawAbsSec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ return Utils.drawText(gc, stime, rect, true);
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawAbsMillisec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ String ns = Utils.formatNs(nanosec, Resolution.MILLISEC);
+ return Utils.drawText(gc, stime + "." + ns, rect, true); //$NON-NLS-1$
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawAbsMicroSec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ String micr = Utils.formatNs(nanosec, Resolution.MICROSEC);
+ return Utils.drawText(gc, stime + "." + micr, rect, true); //$NON-NLS-1$
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawAbsNanoSec extends TimeDraw {
+ @Override
+ public int draw(GC gc, long nanosec, Rectangle rect) {
+ String stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
+ String ns = Utils.formatNs(nanosec, Resolution.NANOSEC);
+ return Utils.drawText(gc, stime + "." + ns, rect, true); //$NON-NLS-1$
+ }
+
+ @Override
+ public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
+ String header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
+ int headerwidth = gc.stringExtent(header).x + 4;
+ if (headerwidth <= rect.width) {
+ rect.x += (rect.width - headerwidth);
+ Utils.drawText(gc, header, rect, true);
+ }
+ }
+}
+
+class TimeDrawNumber extends TimeDraw {
+ @Override
+ public int draw(GC gc, long time, Rectangle rect) {
+ String stime = NumberFormat.getInstance().format(time);
+ return Utils.drawText(gc, stime, rect, true);
+ }
+}
+
+class TimeDrawCycles extends TimeDraw {
+ @Override
+ public int draw(GC gc, long time, Rectangle rect) {
+ String stime = Utils.formatTime(time, TimeFormat.CYCLES, Resolution.SECONDS);
+ return Utils.drawText(gc, stime, rect, true);
+ }
+}