/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.modules.tracer.impl.timeline;
import java.awt.Color;
import org.netbeans.lib.profiler.charts.ItemSelection;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.List;
import org.netbeans.lib.profiler.charts.ChartContext;
import org.netbeans.lib.profiler.charts.ChartItem;
import org.netbeans.lib.profiler.charts.ChartItemChange;
import org.netbeans.lib.profiler.charts.swing.LongRect;
import org.netbeans.lib.profiler.charts.xy.XYItem;
import org.netbeans.lib.profiler.charts.xy.XYItemChange;
import org.netbeans.lib.profiler.charts.xy.XYItemPainter;
import org.netbeans.lib.profiler.charts.xy.XYItemSelection;
import org.netbeans.lib.profiler.charts.xy.synchronous.SynchronousXYChartContext;
import org.netbeans.lib.profiler.charts.xy.synchronous.SynchronousXYItem;
/**
*
* @author Jiri Sedlacek
*/
abstract class TimelineXYPainter extends XYItemPainter.Abstract {
private final int viewExtent;
private final boolean bottomBased;
private boolean painting;
protected final double dataFactor;
// --- Constructor ---------------------------------------------------------
TimelineXYPainter(int viewExtent, boolean bottomBased, double dataFactor) {
this.viewExtent = viewExtent;
this.bottomBased = bottomBased;
this.dataFactor = dataFactor;
painting = true;
}
// --- Abstract interface --------------------------------------------------
protected abstract void paint(XYItem item, List<ItemSelection> highlighted,
List<ItemSelection> selected, Graphics2D g,
Rectangle dirtyArea, SynchronousXYChartContext
context);
protected abstract Color getDefiningColor();
// --- Public interface ----------------------------------------------------
void setPainting(boolean painting) {
this.painting = painting;
}
boolean isPainting() {
return painting;
}
// --- Protected interface -------------------------------------------------
protected final int getViewExtent() {
return viewExtent;
}
// --- ItemPainter implementation ------------------------------------------
public LongRect getItemBounds(ChartItem item) {
XYItem xyItem = (XYItem)item;
return getDataBounds(xyItem.getBounds());
}
public LongRect getItemBounds(ChartItem item, ChartContext context) {
XYItem xyItem = (XYItem)item;
return getViewBounds(xyItem.getBounds(), context);
}
public boolean isBoundsChange(ChartItemChange itemChange) {
XYItemChange change = (XYItemChange)itemChange;
return !LongRect.equals(change.getOldValuesBounds(),
change.getNewValuesBounds());
}
public boolean isAppearanceChange(ChartItemChange itemChange) {
XYItemChange change = (XYItemChange)itemChange;
LongRect dirtyBounds = change.getDirtyValuesBounds();
return dirtyBounds.width != 0 || dirtyBounds.height != 0;
}
public LongRect getDirtyBounds(ChartItemChange itemChange, ChartContext context) {
XYItemChange change = (XYItemChange)itemChange;
return getViewBounds(change.getDirtyValuesBounds(), context);
}
public boolean supportsHovering(ChartItem item) {
return true;
}
public boolean supportsSelecting(ChartItem item) {
return true;
}
public LongRect getSelectionBounds(ItemSelection selection, ChartContext context) {
XYItemSelection sel = (XYItemSelection)selection;
XYItem item = sel.getItem();
int selectedValueIndex = sel.getValueIndex();
if (selectedValueIndex == -1 ||
selectedValueIndex >= item.getValuesCount())
// This happens on reset - bounds of the selection are unknown, let's clear whole area
return new LongRect(0, 0, context.getViewportWidth(),
context.getViewportHeight());
else
return getViewBounds(item, selectedValueIndex, context);
// return getViewBounds(item, new int[] { selectedValueIndex }, context);
}
public XYItemSelection getClosestSelection(ChartItem item, int viewX,
int viewY, ChartContext context) {
SynchronousXYChartContext contx = (SynchronousXYChartContext)context;
int nearestTimestampIndex = contx.getNearestTimestampIndex(viewX, viewY);
if (nearestTimestampIndex == -1) return null; // item not visible
SynchronousXYItem xyItem = (SynchronousXYItem)item;
return new XYItemSelection.Default(xyItem, nearestTimestampIndex,
ItemSelection.DISTANCE_UNKNOWN);
}
public final void paintItem(ChartItem item, List<ItemSelection> highlighted,
List<ItemSelection> selected, Graphics2D g,
Rectangle dirtyArea, ChartContext context) {
if (!painting) return;
XYItem it = (XYItem)item;
if (it.getValuesCount() < 1) return;
if (context.getViewWidth() == 0 || context.getViewHeight() == 0) return;
SynchronousXYChartContext ctx = (SynchronousXYChartContext)context;
paint((XYItem)item, highlighted, selected, g, dirtyArea, ctx);
}
// --- XYItemPainter implementation ----------------------------------------
public double getItemView(double dataY, XYItem item, ChartContext context) {
return context.getViewY(dataY * dataFactor);
}
public double getItemValue(double viewY, XYItem item, ChartContext context) {
return context.getDataY(viewY / dataFactor);
}
public double getItemValueScale(XYItem item, ChartContext context) {
double scale = context.getViewHeight(dataFactor);
if (scale <= 0) scale = -1;
return scale;
}
// --- Private implementation ----------------------------------------------
private LongRect getDataBounds(LongRect itemBounds) {
LongRect bounds = new LongRect(itemBounds);
bounds.y *= dataFactor;
bounds.height *= dataFactor;
if (bottomBased) {
bounds.height += bounds.y;
bounds.y = 0;
}
return bounds;
}
private LongRect getViewBounds(LongRect itemBounds, ChartContext context) {
LongRect dataBounds = getDataBounds(itemBounds);
LongRect viewBounds = context.getViewRect(dataBounds);
LongRect.addBorder(viewBounds, viewExtent);
return viewBounds;
}
private LongRect getViewBounds(XYItem item, int valueIndex, ChartContext context) {
long xValue = item.getXValue(valueIndex);
long yValue = (long)(item.getYValue(valueIndex) * dataFactor);
return context.getViewRect(new LongRect(xValue, yValue, 0, 0));
}
// private LongRect getViewBounds(XYItem item, int[] valuesIndexes, ChartContext context) {
//
// LongRect dataBounds = new LongRect();
//
// if (valuesIndexes == null) {
// LongRect.set(dataBounds, item.getBounds());
// dataBounds.y *= dataFactor;
// dataBounds.height *= dataFactor;
// } else {
// boolean firstPoint = true;
// for (int valueIndex : valuesIndexes) {
// if (valueIndex == -1) continue;
// long xValue = item.getXValue(valueIndex);
// long yValue = (long)(item.getYValue(valueIndex) * dataFactor);
// if (firstPoint) {
// LongRect.set(dataBounds, xValue, yValue, 0, 0);
// firstPoint = false;
// } else {
// LongRect.add(dataBounds, xValue, yValue);
// }
// }
// }
//
// LongRect viewBounds = context.getViewRect(dataBounds);
// LongRect.addBorder(viewBounds, viewExtent);
// return viewBounds;
// }
}