| /* |
| * 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.apache.pivot.charts; |
| |
| import java.util.Comparator; |
| |
| import org.apache.pivot.beans.DefaultProperty; |
| import org.apache.pivot.charts.content.ValueMarker; |
| import org.apache.pivot.collections.ArrayList; |
| import org.apache.pivot.collections.List; |
| import org.apache.pivot.collections.ListListener; |
| import org.apache.pivot.collections.Sequence; |
| import org.apache.pivot.util.ListenerList; |
| import org.apache.pivot.util.Service; |
| import org.apache.pivot.util.Utils; |
| import org.apache.pivot.wtk.Component; |
| |
| /** |
| * Abstract base class for chart views. |
| */ |
| @DefaultProperty("chartData") |
| public abstract class ChartView extends Component { |
| /** |
| * Represents a chart category. |
| */ |
| public static class Category { |
| private ChartView chartView = null; |
| |
| private String key; |
| private String label; |
| |
| public Category() { |
| this(null, null); |
| } |
| |
| public Category(String key) { |
| this(key, key); |
| } |
| |
| public Category(String key, String label) { |
| this.key = key; |
| this.label = label; |
| } |
| |
| public ChartView getChartView() { |
| return chartView; |
| } |
| |
| public String getKey() { |
| return key; |
| } |
| |
| public void setKey(String key) { |
| Utils.checkNull(key, "key"); |
| |
| String previousKey = this.key; |
| |
| if (previousKey != key) { |
| this.key = key; |
| |
| if (chartView != null) { |
| chartView.chartViewCategoryListeners.categoryKeyChanged(chartView, |
| chartView.categories.indexOf(this), previousKey); |
| } |
| } |
| } |
| |
| public String getLabel() { |
| return label; |
| } |
| |
| public void setLabel(String label) { |
| Utils.checkNull(label, "label"); |
| |
| String previousLabel = this.label; |
| |
| if (previousLabel != label) { |
| this.label = label; |
| |
| if (chartView != null) { |
| chartView.chartViewCategoryListeners.categoryLabelChanged(chartView, |
| chartView.categories.indexOf(this), previousLabel); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Represents an element of a chart, such as a bar or a pie wedge. |
| */ |
| public static class Element { |
| private int seriesIndex; |
| private int elementIndex; |
| |
| public Element(int seriesIndex, int elementIndex) { |
| this.seriesIndex = seriesIndex; |
| this.elementIndex = elementIndex; |
| } |
| |
| /** |
| * Returns the element's series index. |
| * |
| * @return The element's series index. |
| */ |
| public int getSeriesIndex() { |
| return seriesIndex; |
| } |
| |
| /** |
| * Returns the element's index within its series. For a category series, |
| * the element index represents the index of the category in the |
| * category sequence. Otherwise, it represents the index of the item |
| * within the series. |
| * |
| * @return The element index. |
| */ |
| public int getElementIndex() { |
| return elementIndex; |
| } |
| |
| @Override |
| public String toString() { |
| String string = getClass().getName() + seriesIndex + ", " + elementIndex; |
| return string; |
| } |
| } |
| |
| /** |
| * Chart view skin interface. |
| */ |
| public interface Skin { |
| public Element getElementAt(int x, int y); |
| } |
| |
| /** |
| * Internal class for managing the chart's category list. |
| */ |
| public final class CategorySequence implements Sequence<Category> { |
| @Override |
| public int add(Category category) { |
| int index = getLength(); |
| insert(category, index); |
| |
| return index; |
| } |
| |
| @Override |
| public void insert(Category category, int index) { |
| Utils.checkNull(category, "category"); |
| |
| if (category.getChartView() != null) { |
| throw new IllegalArgumentException( |
| "Category is already in use by another chart view."); |
| } |
| |
| categories.insert(category, index); |
| category.chartView = ChartView.this; |
| |
| chartViewCategoryListeners.categoryInserted(ChartView.this, index); |
| } |
| |
| @Override |
| public Category update(int index, Category category) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public int remove(Category category) { |
| int index = indexOf(category); |
| if (index != -1) { |
| remove(index, 1); |
| } |
| |
| return index; |
| } |
| |
| @Override |
| public Sequence<Category> remove(int index, int count) { |
| Sequence<Category> removed = categories.remove(index, count); |
| |
| if (count > 0) { |
| for (int i = 0, n = removed.getLength(); i < n; i++) { |
| removed.get(i).chartView = null; |
| } |
| |
| chartViewCategoryListeners.categoriesRemoved(ChartView.this, index, removed); |
| } |
| |
| return removed; |
| } |
| |
| @Override |
| public Category get(int index) { |
| return categories.get(index); |
| } |
| |
| @Override |
| public int indexOf(Category category) { |
| return categories.indexOf(category); |
| } |
| |
| @Override |
| public int getLength() { |
| return categories.getLength(); |
| } |
| } |
| |
| /** |
| * List event handler. |
| */ |
| private class ListHandler implements ListListener<Object> { |
| @Override |
| public void itemInserted(List<Object> list, int index) { |
| chartViewSeriesListeners.seriesInserted(ChartView.this, index); |
| } |
| |
| @Override |
| public void itemsRemoved(List<Object> list, int index, Sequence<Object> items) { |
| int count = items.getLength(); |
| chartViewSeriesListeners.seriesRemoved(ChartView.this, index, count); |
| } |
| |
| @Override |
| public void itemUpdated(List<Object> list, int index, Object previousItem) { |
| chartViewSeriesListeners.seriesUpdated(ChartView.this, index); |
| } |
| |
| @Override |
| public void listCleared(List<Object> list) { |
| chartViewSeriesListeners.seriesCleared(ChartView.this); |
| } |
| |
| @Override |
| public void comparatorChanged(List<Object> list, Comparator<Object> previousComparator) { |
| if (list.getComparator() != null) { |
| chartViewSeriesListeners.seriesSorted(ChartView.this); |
| } |
| } |
| } |
| |
| private class ValueMarkersHandler implements ListListener<ValueMarker> { |
| @Override |
| public void itemInserted(List<ValueMarker> list, int index) { |
| chartViewListeners.chartDataChanged(ChartView.this, getChartData()); |
| } |
| |
| @Override |
| public void itemsRemoved(List<ValueMarker> list, int index, Sequence<ValueMarker> items) { |
| chartViewListeners.chartDataChanged(ChartView.this, getChartData()); |
| } |
| |
| @Override |
| public void itemUpdated(List<ValueMarker> list, int index, ValueMarker previousItem) { |
| chartViewListeners.chartDataChanged(ChartView.this, getChartData()); |
| } |
| |
| @Override |
| public void listCleared(List<ValueMarker> list) { |
| chartViewListeners.chartDataChanged(ChartView.this, getChartData()); |
| } |
| |
| @Override |
| public void comparatorChanged(List<ValueMarker> list, |
| Comparator<ValueMarker> previousComparator) { |
| // No-op |
| } |
| } |
| |
| protected List<?> chartData; |
| private String seriesNameKey; |
| |
| private String title = null; |
| private String horizontalAxisLabel = null; |
| private String verticalAxisLabel = null; |
| private boolean showLegend; |
| |
| private List<Category> categories = new ArrayList<>(); |
| private CategorySequence categorySequence = new CategorySequence(); |
| |
| private ListHandler chartDataHandler = new ListHandler(); |
| private ValueMarkersHandler valueMarkersHandler = new ValueMarkersHandler(); |
| |
| private ChartViewListener.Listeners chartViewListeners = new ChartViewListener.Listeners(); |
| private ChartViewCategoryListener.Listeners chartViewCategoryListeners = new ChartViewCategoryListener.Listeners(); |
| private ChartViewSeriesListener.Listeners chartViewSeriesListeners = new ChartViewSeriesListener.Listeners(); |
| |
| private List<ValueMarker> valueMarkers; |
| |
| public static final String DEFAULT_SERIES_NAME_KEY = "name"; |
| public static final String PROVIDER_NAME = Provider.class.getName(); |
| |
| private static Provider provider = null; |
| |
| static { |
| provider = (Provider) Service.getProvider(PROVIDER_NAME); |
| |
| if (provider == null) { |
| throw new ProviderNotFoundException(); |
| } |
| } |
| |
| public ChartView() { |
| this(DEFAULT_SERIES_NAME_KEY, new ArrayList<>()); |
| } |
| |
| public ChartView(String seriesNameKey, List<?> chartData) { |
| setSeriesNameKey(seriesNameKey); |
| setTitle(title); |
| setChartData(chartData); |
| setShowLegend(showLegend); |
| setValueMarkers(new ArrayList<ValueMarker>()); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| protected void installSkin(Class<? extends Component> componentClass) { |
| Class<? extends org.apache.pivot.wtk.Skin> skinClass = provider.getSkinClass((Class<? extends ChartView>) componentClass); |
| |
| try { |
| setSkin(skinClass.newInstance()); |
| } catch (InstantiationException exception) { |
| throw new IllegalArgumentException(exception); |
| } catch (IllegalAccessException exception) { |
| throw new IllegalArgumentException(exception); |
| } |
| } |
| |
| public CategorySequence getCategories() { |
| return categorySequence; |
| } |
| |
| public List<?> getChartData() { |
| return chartData; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public void setChartData(List<?> chartData) { |
| Utils.checkNull(chartData, "chartData"); |
| |
| List<?> previousChartData = this.chartData; |
| |
| if (previousChartData != chartData) { |
| if (previousChartData != null) { |
| ((List<Object>) previousChartData).getListListeners().remove(chartDataHandler); |
| } |
| |
| ((List<Object>) chartData).getListListeners().add(chartDataHandler); |
| |
| this.chartData = chartData; |
| chartViewListeners.chartDataChanged(this, previousChartData); |
| } |
| } |
| |
| public String getSeriesNameKey() { |
| return seriesNameKey; |
| } |
| |
| public void setSeriesNameKey(String seriesNameKey) { |
| Utils.checkNull(seriesNameKey, "seriesNameKey"); |
| |
| String previousSeriesNameKey = this.seriesNameKey; |
| |
| if (previousSeriesNameKey != seriesNameKey) { |
| this.seriesNameKey = seriesNameKey; |
| chartViewListeners.seriesNameKeyChanged(this, previousSeriesNameKey); |
| } |
| } |
| |
| public String getTitle() { |
| return title; |
| } |
| |
| public void setTitle(String title) { |
| String previousTitle = this.title; |
| |
| if (previousTitle != title) { |
| this.title = title; |
| chartViewListeners.titleChanged(this, previousTitle); |
| } |
| } |
| |
| public String getHorizontalAxisLabel() { |
| return horizontalAxisLabel; |
| } |
| |
| public void setHorizontalAxisLabel(String horizontalAxisLabel) { |
| String previousHorizontalAxisLabel = this.horizontalAxisLabel; |
| |
| if (previousHorizontalAxisLabel != horizontalAxisLabel) { |
| this.horizontalAxisLabel = horizontalAxisLabel; |
| chartViewListeners.horizontalAxisLabelChanged(this, previousHorizontalAxisLabel); |
| } |
| } |
| |
| public String getVerticalAxisLabel() { |
| return verticalAxisLabel; |
| } |
| |
| public void setVerticalAxisLabel(String verticalAxisLabel) { |
| String previousVerticalAxisLabel = this.verticalAxisLabel; |
| |
| if (previousVerticalAxisLabel != verticalAxisLabel) { |
| this.verticalAxisLabel = verticalAxisLabel; |
| chartViewListeners.verticalAxisLabelChanged(this, previousVerticalAxisLabel); |
| } |
| } |
| |
| public boolean getShowLegend() { |
| return showLegend; |
| } |
| |
| public void setShowLegend(boolean showLegend) { |
| if (this.showLegend != showLegend) { |
| this.showLegend = showLegend; |
| chartViewListeners.showLegendChanged(this); |
| } |
| } |
| |
| public Element getElementAt(int x, int y) { |
| return ((Skin) getSkin()).getElementAt(x, y); |
| } |
| |
| public ListenerList<ChartViewListener> getChartViewListeners() { |
| return chartViewListeners; |
| } |
| |
| public ListenerList<ChartViewCategoryListener> getChartViewCategoryListeners() { |
| return chartViewCategoryListeners; |
| } |
| |
| public ListenerList<ChartViewSeriesListener> getChartViewSeriesListeners() { |
| return chartViewSeriesListeners; |
| } |
| |
| public List<ValueMarker> getValueMarkers() { |
| return valueMarkers; |
| } |
| |
| public void setValueMarkers(List<ValueMarker> valueMarkers) { |
| List<ValueMarker> previousValueMarkers = this.valueMarkers; |
| |
| if (previousValueMarkers != valueMarkers) { |
| if (previousValueMarkers != null) { |
| previousValueMarkers.getListListeners().remove(valueMarkersHandler); |
| } |
| |
| this.valueMarkers = valueMarkers; |
| if (valueMarkers != null) { |
| valueMarkers.getListListeners().add(valueMarkersHandler); |
| } |
| } |
| } |
| |
| } |