| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.lib.profiler.charts; |
| |
| import org.netbeans.lib.profiler.charts.swing.LongRect; |
| import org.netbeans.lib.profiler.charts.swing.Utils; |
| import org.netbeans.lib.profiler.charts.canvas.InteractiveCanvasComponent; |
| import java.awt.Color; |
| import java.awt.Graphics; |
| import java.awt.Graphics2D; |
| import java.awt.Rectangle; |
| import java.awt.RenderingHints; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * |
| * @author Jiri Sedlacek |
| */ |
| public class ChartComponent extends InteractiveCanvasComponent { |
| |
| private RenderingHints renderingHints; |
| |
| private List<ChartDecorator> preDecorators; |
| private List<ChartDecorator> postDecorators; |
| |
| private ItemsModel itemsModel; |
| private PaintersModel paintersModel; |
| |
| protected LongRect dataBounds; |
| private LongRect initialDataBounds; |
| private ChartContext chartContext; |
| |
| private ItemsModelListener itemsListener; |
| private PaintersModelListener paintersListener; |
| |
| private List<ChartOverlay> overlays; |
| |
| private ChartSelectionModel selectionModel; |
| private SelectionListener selectionListener; |
| |
| private List<ChartConfigurationListener> configurationListeners; |
| |
| |
| public ChartComponent() { |
| initRenderingHints(); |
| |
| itemsListener = new ItemsModelListener(); |
| paintersListener = new PaintersModelListener(); |
| |
| dataBounds = new LongRect(); |
| initialDataBounds = new LongRect(); |
| |
| setLayout(null); |
| |
| setSelectionModel(new ChartSelectionManager()); |
| } |
| |
| |
| // --- Models -------------------------------------------------------------- |
| |
| public final void setItemsModel(ItemsModel itemsModel) { |
| if (itemsModel == null) throw new IllegalArgumentException("ItemsModel cannot be null"); |
| if (itemsModel == this.itemsModel) return; |
| |
| if (this.itemsModel != null) this.itemsModel.removeItemsListener(itemsListener); |
| |
| this.itemsModel = itemsModel; |
| this.itemsModel.addItemsListener(itemsListener); |
| |
| updateChart(); |
| } |
| |
| public final ItemsModel getItemsModel() { |
| return itemsModel; |
| } |
| |
| public final void setPaintersModel(PaintersModel paintersModel) { |
| if (paintersModel == null) throw new IllegalArgumentException("PaintersModel cannot be null"); |
| if (paintersModel == this.paintersModel) return; |
| |
| if (this.paintersModel != null) this.paintersModel.removePaintersListener(paintersListener); |
| |
| this.paintersModel = paintersModel; |
| this.paintersModel.addPaintersListener(paintersListener); |
| |
| updateChart(); |
| } |
| |
| public final PaintersModel getPaintersModel() { |
| return paintersModel; |
| } |
| |
| public final void setSelectionModel(ChartSelectionModel selectionModel) { |
| // Cleanup previous model |
| if (this.selectionModel != null) { |
| this.selectionModel.removeSelectionListener(selectionListener); |
| if (this.selectionModel instanceof ChartSelectionManager) |
| ((ChartSelectionManager)this.selectionModel).unregisterChart(this); |
| } |
| |
| // Assign new model |
| this.selectionModel = selectionModel; |
| |
| // Setup new model |
| if (selectionModel != null) { |
| if (selectionListener == null) selectionListener = new SelectionListener(); |
| selectionModel.addSelectionListener(selectionListener); |
| if (selectionModel instanceof ChartSelectionManager) |
| ((ChartSelectionManager)selectionModel).registerChart(this); |
| } else { |
| selectionListener = null; |
| } |
| } |
| |
| public final ChartSelectionModel getSelectionModel() { |
| return selectionModel; |
| } |
| |
| |
| // --- Initial data bounds ------------------------------------------------- |
| |
| public final void setInitialDataBounds(LongRect bounds) { |
| if (LongRect.equals(bounds, initialDataBounds)) return; |
| LongRect.set(initialDataBounds, bounds); |
| if (LongRect.isEmpty(dataBounds)) { |
| resizeChart(); |
| invalidateImage(); |
| repaintDirty(); |
| } |
| } |
| |
| public final LongRect getInitialDataBounds() { |
| return initialDataBounds; |
| } |
| |
| // --- Customizable RenderingHints ----------------------------------------- |
| |
| public final void setRenderingHints(RenderingHints renderingHints) { |
| this.renderingHints = Utils.checkedRenderingHints(renderingHints); |
| } |
| |
| public final RenderingHints getRenderingHints() { |
| return (RenderingHints)renderingHints.clone(); |
| } |
| |
| private void applyRenderingHints(Graphics2D g) { |
| if (renderingHints != null) g.setRenderingHints(renderingHints); |
| } |
| |
| private void initRenderingHints() { |
| RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
| hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); |
| setRenderingHints(hints); |
| } |
| |
| |
| // --- ChartContext -------------------------------------------------------- |
| |
| public final ChartContext getChartContext() { |
| return getChartContext(null); |
| } |
| |
| protected ChartContext getChartContext(ChartItem item) { |
| if (chartContext == null) chartContext = createChartContext(); |
| return chartContext; |
| } |
| |
| protected ChartContext createChartContext() { |
| return new Context(this); |
| } |
| |
| |
| // --- Configuration Listeners --------------------------------------------- |
| |
| public final void addConfigurationListener(ChartConfigurationListener listener) { |
| if (configurationListeners == null) configurationListeners = new ArrayList(); |
| configurationListeners.add(listener); |
| } |
| |
| public final void removeConfigurationListener(ChartConfigurationListener listener) { |
| if (configurationListeners == null) return; |
| configurationListeners.remove(listener); |
| } |
| |
| |
| protected final void offsetChanged(long oldOffsetX, long oldOffsetY, |
| long newOffsetX, long newOffsetY) { |
| super.offsetChanged(oldOffsetX, oldOffsetY, newOffsetX, newOffsetY); |
| fireOffsetChanged(oldOffsetX, oldOffsetY, newOffsetX, newOffsetY); |
| } |
| |
| protected final void scaleChanged(double oldScaleX, double oldScaleY, |
| double newScaleX, double newScaleY) { |
| super.scaleChanged(oldScaleX, oldScaleY, newScaleX, newScaleY); |
| fireScaleChanged(oldScaleX, oldScaleY, newScaleX, newScaleY); |
| } |
| |
| protected final void dataBoundsChanged(long dataOffsetX, long dataOffsetY, |
| long dataWidth, long dataHeight, |
| long oldDataOffsetX, long oldDataOffsetY, |
| long oldDataWidth, long oldDataHeight) { |
| super.dataBoundsChanged(dataOffsetX, dataOffsetY, dataWidth, dataHeight, |
| oldDataOffsetX, oldDataOffsetY, oldDataWidth, oldDataHeight); |
| fireDataBoundsChanged(dataOffsetX, dataOffsetY, dataWidth, dataHeight, |
| oldDataOffsetX, oldDataOffsetY, oldDataWidth, oldDataHeight); |
| } |
| |
| protected final void contentsWillBeUpdated(long offsetX, long offsetY, |
| double scaleX, double scaleY, |
| long lastOffsetX, long lastOffsetY, |
| double lastScaleX, double lastScaleY) { |
| super.contentsWillBeUpdated(offsetX, offsetY, scaleX, scaleY, lastOffsetX, |
| lastOffsetY, lastScaleX, lastScaleY); |
| fireContentsWillBeUpdated(offsetX, offsetY, scaleX, scaleY, |
| lastOffsetX, lastOffsetY, lastScaleX, lastScaleY); |
| } |
| |
| protected final void contentsUpdated(long offsetX, long offsetY, |
| double scaleX, double scaleY, |
| long lastOffsetX, long lastOffsetY, |
| double lastScaleX, double lastScaleY, |
| int shiftX, int shiftY) { |
| super.contentsUpdated(offsetX, offsetY, scaleX, scaleY, lastOffsetX, |
| lastOffsetY, lastScaleX, lastScaleY, shiftX, shiftY); |
| fireContentsUpdated(offsetX, offsetY, scaleX, scaleY, lastOffsetX, lastOffsetY, |
| lastScaleX, lastScaleY, shiftX, shiftY); |
| } |
| |
| |
| private void fireOffsetChanged(long oldOffsetX, long oldOffsetY, |
| long newOffsetX, long newOffsetY) { |
| if (configurationListeners == null) return; |
| for (ChartConfigurationListener listener : configurationListeners) |
| listener.offsetChanged(oldOffsetX, oldOffsetY, newOffsetX, newOffsetY); |
| } |
| |
| private void fireScaleChanged(double oldScaleX, double oldScaleY, |
| double newScaleX, double newScaleY) { |
| if (configurationListeners == null) return; |
| for (ChartConfigurationListener listener : configurationListeners) |
| listener.scaleChanged(oldScaleX, oldScaleY, newScaleX, newScaleY); |
| } |
| |
| private void fireDataBoundsChanged(long dataOffsetX, long dataOffsetY, |
| long dataWidth, long dataHeight, |
| long oldDataOffsetX, long oldDataOffsetY, |
| long oldDataWidth, long oldDataHeight) { |
| if (configurationListeners == null) return; |
| for (ChartConfigurationListener listener : configurationListeners) |
| listener.dataBoundsChanged(dataOffsetX, dataOffsetY, dataWidth, |
| dataHeight, oldDataOffsetX, oldDataOffsetY, |
| oldDataWidth, oldDataHeight); |
| } |
| |
| private void fireContentsWillBeUpdated(long offsetX, long offsetY, |
| double scaleX, double scaleY, |
| long lastOffsetX, long lastOffsetY, |
| double lastScaleX, double lastScaleY) { |
| if (configurationListeners == null) return; |
| for (ChartConfigurationListener listener : configurationListeners) |
| listener.contentsWillBeUpdated(offsetX, offsetY, scaleX, scaleY, |
| lastOffsetX, lastOffsetY, lastScaleX, lastScaleY); |
| } |
| |
| private void fireContentsUpdated(long offsetX, long offsetY, |
| double scaleX, double scaleY, |
| long lastOffsetX, long lastOffsetY, |
| double lastScaleX, double lastScaleY, |
| int shiftX, int shiftY) { |
| if (configurationListeners == null) return; |
| for (ChartConfigurationListener listener : configurationListeners) |
| listener.contentsUpdated(offsetX, offsetY, scaleX, scaleY, lastOffsetX, |
| lastOffsetY, lastScaleX, lastScaleY, shiftX, shiftY); |
| } |
| |
| |
| // --- Pre & post painters support ----------------------------------------- |
| |
| public final void addPreDecorator(ChartDecorator decorator) { |
| if (preDecorators == null) preDecorators = new ArrayList(2); |
| preDecorators.add(decorator); |
| } |
| |
| public final void removePreDecorator(ChartDecorator decorator) { |
| if (preDecorators != null) preDecorators.remove(decorator); |
| } |
| |
| final List<ChartDecorator> getPreDecorators() { |
| return preDecorators; |
| } |
| |
| public final void addPostDecorator(ChartDecorator decorator) { |
| if (postDecorators == null) postDecorators = new ArrayList(2); |
| postDecorators.add(decorator); |
| } |
| |
| public final void removePostDecorator(ChartDecorator decorator) { |
| if (postDecorators != null) postDecorators.remove(decorator); |
| } |
| |
| final List<ChartDecorator> getPostDecorators() { |
| return postDecorators; |
| } |
| |
| |
| // --- Overlays ------------------------------------------------------------ |
| |
| public final void addOverlayComponent(ChartOverlay overlay) { |
| if (overlays == null) overlays = new ArrayList(); |
| |
| overlay.setChartContext(getChartContext()); |
| |
| overlays.add(overlay); |
| add(overlay); |
| } |
| |
| public final void removeOverlayComponent(ChartOverlay overlay) { |
| remove(overlay); |
| overlays.remove(overlay); |
| |
| overlay.setChartContext(null); |
| } |
| |
| |
| protected void reshaped(Rectangle oldBounds, Rectangle newBounds) { |
| super.reshaped(oldBounds, newBounds); |
| |
| if (overlays == null) return; |
| |
| for (ChartOverlay overlay : overlays) |
| overlay.setBounds(0, 0, newBounds.width, newBounds.height); |
| } |
| |
| |
| // --- Paint implementation ------------------------------------------------ |
| |
| protected void paintContents(Graphics g, Rectangle invalidArea) { |
| Graphics2D g2 = (Graphics2D)g; |
| |
| // Set clip |
| g2.setClip(invalidArea); |
| |
| // Set rendering hints |
| applyRenderingHints(g2); |
| |
| // Paint background if opaque |
| if (isOpaque()) { |
| g2.setColor(getBackground()); |
| g2.fillRect(invalidArea.x, invalidArea.y, |
| invalidArea.width, invalidArea.height); |
| } |
| |
| // Paint registered prepainters |
| if (preDecorators != null) |
| for (ChartDecorator decorator : preDecorators) |
| decorator.paint(g2, invalidArea, getChartContext()); |
| |
| // Paint chart items |
| if (itemsModel != null && paintersModel != null) { |
| int itemsCount = itemsModel.getItemsCount(); |
| |
| if (itemsCount != 0) { |
| boolean sel = selectionModel != null; |
| |
| List<ItemSelection> highlightedSelection = sel ? selectionModel.getHighlightedItems() : null; |
| List<ItemSelection> selectedSelection = sel ? selectionModel.getSelectedItems() : null; |
| List<ItemSelection> filteredHighlighted = sel ? new ArrayList() : Collections.EMPTY_LIST; |
| List<ItemSelection> filteredSelected = sel ? new ArrayList() : Collections.EMPTY_LIST; |
| |
| for (int i = 0; i < itemsCount; i++) { |
| ChartItem item = itemsModel.getItem(i); |
| ItemPainter painter = paintersModel.getPainter(item); |
| |
| if (sel) { |
| filteredHighlighted.clear(); |
| if (painter.supportsHovering(item)) |
| filterSelection(highlightedSelection, filteredHighlighted, item); |
| filteredSelected.clear(); |
| if (painter.supportsSelecting(item)) |
| filterSelection(selectedSelection, filteredSelected, item); |
| } |
| |
| painter.paintItem(item, filteredHighlighted, filteredSelected, |
| g2, invalidArea, getChartContext(item)); |
| } |
| } |
| } |
| |
| // Paint registered postpainters |
| if (postDecorators != null) |
| for (ChartDecorator decorator : postDecorators) |
| decorator.paint(g2, invalidArea, getChartContext()); |
| } |
| |
| |
| private static void filterSelection(List<ItemSelection> selection, List<ItemSelection> result, ChartItem filter) { |
| if (filter == null) return; |
| for (ItemSelection sel : selection) |
| if (sel.getItem().equals(filter)) result.add(sel); |
| } |
| |
| |
| // --- UI tweaks ----------------------------------------------------------- |
| |
| public void setBackground(Color bg) { |
| super.setBackground(Utils.checkedColor(bg)); |
| } |
| |
| |
| // --- Protected implementation ---------------------------------------------- |
| |
| protected void computeDataBounds() { |
| LongRect.clear(dataBounds); |
| if (itemsModel == null || paintersModel == null) return; |
| |
| int itemsCount = itemsModel.getItemsCount(); |
| for (int i = 0; i < itemsCount; i++) { |
| ChartItem item = itemsModel.getItem(i); |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (i == 0) |
| LongRect.set(dataBounds, painter.getItemBounds(item)); |
| else |
| LongRect.add(dataBounds, painter.getItemBounds(item)); |
| } |
| } |
| |
| protected void resizeChart() { |
| if (LongRect.isEmpty(dataBounds)) { |
| LongRect bounds = new LongRect(dataBounds); |
| if (bounds.width == 0) { |
| bounds.width = initialDataBounds.width; |
| if (bounds.x == 0) bounds.x = initialDataBounds.x; |
| } |
| if (bounds.height == 0) { |
| bounds.height = initialDataBounds.height; |
| if (bounds.y == 0) bounds.y = initialDataBounds.y; |
| } |
| setDataBounds(bounds.x, bounds.y, bounds.width, bounds.height); |
| } else { |
| setDataBounds(dataBounds.x, dataBounds.y, dataBounds.width, dataBounds.height); |
| } |
| } |
| |
| protected void updateChart() { |
| computeDataBounds(); |
| resizeChart(); |
| invalidateImage(); |
| repaintDirty(); |
| } |
| |
| protected void itemsAdded(List<ChartItem> addedItems) { |
| // Update chart size |
| LongRect oldBounds = new LongRect(dataBounds); |
| for (ChartItem item : addedItems) { |
| ItemPainter painter = paintersModel.getPainter(item); |
| LongRect.add(dataBounds, painter.getItemBounds(item)); |
| } |
| if (!LongRect.equals(oldBounds, dataBounds)) resizeChart(); |
| |
| // Update chart appearance |
| LongRect uiBounds = null; |
| for (ChartItem item : addedItems) { |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (uiBounds == null) uiBounds = |
| new LongRect(painter.getItemBounds(item, getChartContext(item))); |
| else |
| LongRect.add(uiBounds, painter.getItemBounds(item, getChartContext(item))); |
| } |
| invalidateImage(Utils.checkedRectangle(uiBounds)); |
| repaintDirty(); |
| } |
| |
| protected void itemsRemoved(List<ChartItem> removedItems) { |
| List<ItemPainter> painters = new ArrayList(removedItems.size()); |
| |
| // Try to resolve painters for all removed items |
| for (ChartItem item : removedItems) { |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (painter == null) { |
| painters = null; |
| break; |
| } |
| painters.add(painter); |
| } |
| |
| if (painters == null) { |
| // Some or all painters for removed items not available |
| updateChart(); |
| } else { |
| // All painters for removed items available |
| |
| // Update chart size |
| LongRect oldBounds = new LongRect(dataBounds); |
| computeDataBounds(); |
| if (!LongRect.equals(oldBounds, dataBounds)) resizeChart(); |
| |
| // Update chart appearance |
| LongRect uiBounds = null; |
| for (int i = 0; i < removedItems.size(); i++) { |
| ChartItem item = removedItems.get(i); |
| ItemPainter painter = painters.get(i); |
| if (uiBounds == null) uiBounds = |
| new LongRect(painter.getItemBounds(item, getChartContext(item))); |
| else |
| LongRect.add(uiBounds, painter.getItemBounds(item, getChartContext(item))); |
| } |
| invalidateImage(Utils.checkedRectangle(uiBounds)); |
| repaintDirty(); |
| } |
| } |
| |
| protected void itemsChanged(List<ChartItemChange> itemChanges) { |
| // Resolve painters for changedItems |
| List<ItemPainter> painters = new ArrayList(itemChanges.size()); |
| for (ChartItemChange change : itemChanges) |
| painters.add(paintersModel.getPainter(change.getItem())); |
| |
| // Check if items bounds changed |
| boolean boundsChange = false; |
| for (int i = 0; i < itemChanges.size(); i++) { |
| ChartItemChange change = itemChanges.get(i); |
| ItemPainter painter = painters.get(i); |
| boundsChange = painter.isBoundsChange(change); |
| if (boundsChange) break; |
| } |
| |
| // Update chart size |
| if (boundsChange) { |
| LongRect oldBounds = new LongRect(dataBounds); |
| computeDataBounds(); |
| if (!LongRect.equals(oldBounds, dataBounds)) resizeChart(); |
| } |
| |
| // Check if items appearance changed |
| boolean appearanceChange = false; |
| for (int i = 0; i < itemChanges.size(); i++) { |
| ChartItemChange change = itemChanges.get(i); |
| ItemPainter painter = painters.get(i); |
| appearanceChange = painter.isAppearanceChange(change); |
| if (appearanceChange) break; |
| } |
| |
| // Update chart appearance |
| if (appearanceChange) { |
| LongRect uiBounds = null; |
| for (int i = 0; i < itemChanges.size(); i++) { |
| ChartItemChange change = itemChanges.get(i); |
| ChartItem item = change.getItem(); |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (painter.isAppearanceChange(change)) { |
| if (uiBounds == null) uiBounds = |
| new LongRect(painter.getDirtyBounds(change, getChartContext(item))); |
| else |
| LongRect.add(uiBounds, painter.getDirtyBounds(change, getChartContext(item))); |
| } |
| } |
| invalidateImage(Utils.checkedRectangle(uiBounds)); |
| repaintDirtyAccel(); |
| } else { |
| repaintDirty(); |
| } |
| } |
| |
| protected void paintersChanged() { |
| updateChart(); |
| } |
| |
| protected void paintersChanged(List<ItemPainter> changedPainters) { |
| Set<ChartItem> changedItems = new HashSet(); |
| |
| // Update chart size |
| LongRect oldBounds = new LongRect(dataBounds); |
| computeDataBounds(); |
| if (!LongRect.equals(oldBounds, dataBounds)) resizeChart(); |
| |
| // Resolve changed items |
| for (int i = 0; i < itemsModel.getItemsCount(); i++) { |
| ChartItem item = itemsModel.getItem(i); |
| if (changedPainters.contains(paintersModel.getPainter(item))) |
| changedItems.add(item); |
| } |
| |
| // Update chart appearance |
| LongRect uiBounds = null; |
| for (ChartItem item : changedItems) { |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (uiBounds == null) uiBounds = |
| new LongRect(painter.getItemBounds(item, getChartContext(item))); |
| else |
| LongRect.add(uiBounds, painter.getItemBounds(item, getChartContext(item))); |
| } |
| invalidateImage(Utils.checkedRectangle(uiBounds)); |
| repaintDirty(); |
| } |
| |
| |
| // --- ItemsModel change support ------------------------------------------- |
| |
| private class ItemsModelListener implements ItemsListener { |
| |
| public void itemsAdded(List<ChartItem> addedItems) { |
| ChartComponent.this.itemsAdded(addedItems); |
| } |
| |
| public void itemsRemoved(List<ChartItem> removedItems) { |
| ChartComponent.this.itemsRemoved(removedItems); |
| } |
| |
| public void itemsChanged(List<ChartItemChange> itemChanges) { |
| ChartComponent.this.itemsChanged(itemChanges); |
| } |
| |
| } |
| |
| |
| // --- PaintersModel change support ---------------------------------------- |
| |
| private class PaintersModelListener implements PaintersListener { |
| |
| public void paintersChanged() { |
| ChartComponent.this.paintersChanged(); |
| } |
| |
| public void paintersChanged(List<ItemPainter> changedPainters) { |
| ChartComponent.this.paintersChanged(changedPainters); |
| } |
| |
| } |
| |
| |
| // --- Selection listener -------------------------------------------------- |
| |
| private class SelectionListener implements ChartSelectionListener { |
| |
| public void selectionModeChanged(int newMode, int oldMode) {} |
| |
| public void selectionBoundsChanged(Rectangle newBounds, Rectangle oldBounds) {} |
| |
| public void highlightedItemsChanged(List<ItemSelection> currentItems, |
| List<ItemSelection> addedItems, List<ItemSelection> removedItems) { |
| refreshSelection(addedItems, removedItems); |
| } |
| |
| public void selectedItemsChanged(List<ItemSelection> currentItems, |
| List<ItemSelection> addedItems, List<ItemSelection> removedItems) { |
| refreshSelection(addedItems, removedItems); |
| } |
| |
| |
| private void refreshSelection(List<ItemSelection> addedItems, List<ItemSelection> removedItems) { |
| // TODO: should be optimized! |
| Rectangle dirtyArea = new Rectangle(); |
| |
| if (!removedItems.isEmpty() && removedItems.get(0) != null) |
| for (ItemSelection sel : removedItems) { |
| ChartItem item = sel.getItem(); |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (painter.supportsHovering(item)) { |
| if (dirtyArea.isEmpty()) |
| dirtyArea.setBounds(Utils.checkedRectangle( |
| painter.getSelectionBounds(sel, getChartContext(item)))); |
| else |
| dirtyArea.add(Utils.checkedRectangle( |
| painter.getSelectionBounds(sel, getChartContext(item)))); |
| } |
| } |
| |
| if (!dirtyArea.isEmpty()) { |
| invalidateImage(dirtyArea); |
| paintImmediately(dirtyArea); |
| // repaintDirty(); |
| dirtyArea = new Rectangle(); |
| } |
| |
| if (!addedItems.isEmpty() && addedItems.get(0) != null) |
| for (ItemSelection sel : addedItems) { |
| ChartItem item = sel.getItem(); |
| ItemPainter painter = paintersModel.getPainter(item); |
| if (painter.supportsHovering(item)) { |
| if (dirtyArea.isEmpty()) |
| dirtyArea.setBounds(Utils.checkedRectangle( |
| painter.getSelectionBounds(sel, getChartContext(item)))); |
| else |
| dirtyArea.add(Utils.checkedRectangle( |
| painter.getSelectionBounds(sel, getChartContext(item)))); |
| } |
| } |
| |
| if (!dirtyArea.isEmpty()) { |
| invalidateImage(dirtyArea); |
| paintImmediately(dirtyArea); |
| // repaintDirty(); |
| } |
| |
| // invalidateImage(dirtyArea); |
| // immediatelyRepaintDirty(); |
| // repaintDirty(dirtyArea); |
| } |
| |
| } |
| |
| |
| // --- ChartContext implementation ----------------------------------------- |
| |
| protected static class Context implements ChartContext { |
| |
| private ChartComponent chart; |
| |
| |
| public Context(ChartComponent chart) { this.chart = chart; } |
| |
| protected ChartComponent getChartComponent() { return chart; } |
| |
| |
| public boolean isRightBased() { return chart.isRightBased(); } |
| |
| public boolean isBottomBased() { return chart.isBottomBased(); } |
| |
| public boolean fitsWidth() { return chart.fitsWidth(); } |
| |
| public boolean fitsHeight() { return chart.fitsHeight(); } |
| |
| public long getDataOffsetX() { return chart.getDataOffsetX(); } |
| |
| public long getDataOffsetY() { return chart.getDataOffsetY(); } |
| |
| public long getDataWidth() { return chart.getDataWidth(); } |
| |
| public long getDataHeight() { return chart.getDataHeight(); } |
| |
| public long getViewWidth() { return chart.getContentsWidth(); } |
| |
| public long getViewHeight() { return chart.getContentsHeight(); } |
| |
| public long getViewportOffsetX() { return 0; } |
| |
| public long getViewportOffsetY() { return 0; } |
| |
| public int getViewportWidth() { return chart.getWidth(); } |
| |
| public int getViewportHeight() { return chart.getHeight(); } |
| |
| public double getViewX(double dataX) { return chart.getViewX(dataX); } |
| |
| public double getReversedViewX(double dataX) { return chart.getReversedViewX(dataX); } |
| |
| public double getViewY(double dataY) { return chart.getViewY(dataY); } |
| |
| public double getReversedViewY(double dataY) { return chart.getReversedViewY(dataY); } |
| |
| public double getViewWidth(double dataWidth) { return chart.getViewWidth(dataWidth); } |
| |
| public double getViewHeight(double dataHeight) { return chart.getViewHeight(dataHeight); } |
| |
| public LongRect getViewRect(LongRect dataRect) { return getViewRectImpl(dataRect); } |
| |
| public double getDataX(double viewX) { return chart.getDataX(viewX); } |
| |
| public double getReversedDataX(double viewX) { return chart.getReversedDataX(viewX); } |
| |
| public double getDataY(double viewY) { return chart.getDataY(viewY); } |
| |
| public double getReversedDataY(double viewY) { return chart.getReversedDataY(viewY); } |
| |
| public double getDataWidth(double viewWidth) { return chart.getDataWidth(viewWidth); } |
| |
| public double getDataHeight(double viewHeight) { return chart.getDataHeight(viewHeight); } |
| |
| |
| private LongRect getViewRectImpl(LongRect dataRect) { |
| LongRect viewRect = new LongRect(); |
| |
| viewRect.x = (long)Math.ceil(getViewX(dataRect.x)); |
| viewRect.width = (long)Math.ceil(getViewWidth(dataRect.width)); |
| if (isRightBased()) viewRect.x -= viewRect.width; |
| |
| viewRect.y = (long)Math.ceil(getViewY(dataRect.y)); |
| viewRect.height = (long)Math.ceil(getViewHeight(dataRect.height)); |
| if (isBottomBased()) viewRect.y -= viewRect.height; |
| |
| return viewRect; |
| } |
| |
| } |
| |
| } |