CompositeChartPanel

package com.gossamer.voyant.client.ui.chart;

import com.gossamer.cobra.calculator.core.event.CalculationEvent;

import com.gossamer.cobra.calculator.core.event.PeriodEvent;

import com.gossamer.voyant.client.AppStyle;

import com.gossamer.voyant.client.dispatch.ClientCalculationListener;

import com.gossamer.voyant.client.dispatch.EventDispatcher;

import com.gossamer.voyant.client.dispatch.ClientPeriodListener;

import com.gossamer.voyant.client.ui.StageTimelinePanel;

import com.gossamer.voyant.client.ui.VoyantEventQueue;

import com.gossamer.voyant.client.ui.chartview.ChartConfig;

import com.gossamer.voyant.model.Plan;

import javax.swing.*;

import java.awt.*;

/**

* Contains a chart, a stages bar, and possibly an ages bar.<br>

*/

public class CompositeChartPanel

extends JPanel implements ChartConfig.ChartConfigListener {

public static final CompositeChartPanel upperCCP = new CompositeChartPanel(false);

public static final CompositeChartPanel lowerCCP = new CompositeChartPanel(true);

static {

new VoyantChartMouseListener(upperCCP.voyantChartPanel, lowerCCP.voyantChartPanel);

}

private VoyantChartPanel voyantChartPanel;

private ChartStageEditorPanel chartStageEditorPanel;

private VoyantChart voyantChart;

private VoyantCategoryPlot voyantCategoryPlot;

private boolean lowerPane;

private CCPListener ccpListener = new CCPListener();

private ChartConfig chartConfig;

private StageTimelinePanel stageTimelinePanel;

private ChartDomainLabel chartDomainLabel;

public static void reset() {

EventDispatcher.registerListener(upperCCP.ccpListener);

EventDispatcher.registerListener(lowerCCP.ccpListener);

EventDispatcher.registerListener(upperCCP.voyantCategoryPlot.getChartRefreshListener());

EventDispatcher.registerListener(lowerCCP.voyantCategoryPlot.getChartRefreshListener());

EventDispatcher.registerListener(upperCCP.voyantChartPanel);

EventDispatcher.registerListener(lowerCCP.voyantChartPanel);

EventDispatcher.registerListener(upperCCP.chartDomainLabel.getListener());

// There is no chartDomainLabel for the lowerpane

}

public CompositeChartPanel(boolean lowerPane) {

this.lowerPane = lowerPane;

chartConfig = lowerPane ? ChartConfig.LOWER_CHART_CONFIG : ChartConfig.UPPER_CHART_CONFIG;

// -------------------------------------------

setLayout(new BorderLayout());

chartConfig.registerLast(this);

createVoyantChart();

voyantChartPanel = new VoyantChartPanel(voyantChart, chartConfig, lowerPane);

if (!lowerPane) {

chartStageEditorPanel = new ChartStageEditorPanel();

JPanel chartContainer = new JPanel(new ChartLayout()) {

@Override

// to ensure componentZOrder is respected

public boolean isOptimizedDrawingEnabled() {

return false;

}

};

chartContainer.setOpaque(false);

chartContainer.setComponentZOrder(chartStageEditorPanel, 0);

chartContainer.setComponentZOrder(voyantChartPanel, 1);

add(BorderLayout.CENTER, chartContainer);

}

else {

add(BorderLayout.CENTER, voyantChartPanel);

}

add(lowerPane ? BorderLayout.NORTH : BorderLayout.SOUTH, createChartLabelPanel());

setOpaque(false);

}

public static VoyantChartPanel getVoyantChartPanel(boolean lowerPane) {

return lowerPane ? lowerCCP.voyantChartPanel : upperCCP.voyantChartPanel;

}

public void showChartStageEditorPanel() {

VoyantChartMouseListener.removeHoverAndInfoPanels();

chartStageEditorPanel.activate();

revalidate();

repaint();

}

public void hideChartStageEditorPanel() {

chartStageEditorPanel.deactivate();

revalidate();

repaint();

}

public void reveal() {

setVisible(true);

}

public void veil() {

setVisible(false);

if (this == upperCCP) {

hideChartStageEditorPanel();

}

}

public void chartConfigChange(ChartConfig newChartConfig) {

autoAdjustRangeAxis();

}

/**

* Redraws the chart.

*/

public void refreshChart() {

VoyantChart.refreshAll();

stageTimelinePanel.update();

if (chartDomainLabel != null) {

chartDomainLabel.repaint();

}

}

/**

* Used to maintain chart-scale consistency between calculations even when views are changed

* or dataseries are hidden

* @return the greatest value in the Y-axis scale of the chart

*/

public double getUpperBound() {

return voyantChart.getUpperBound();

}

/**

* "Blink" the setting for auto-adjusting the range axis to cause it to re-adjust and then remain fixed again.<br>

* Also refreshes chart

*/

public void autoAdjustRangeAxis() {

// Don't do this if the lower pane is showing percentages

if (ChartConfig.isShowingPercentLowerPane() && lowerPane) {

return;

}

voyantChart.autoResizeRangeAxis();

}

/**

* Set the range axis on the plot to the height parameter<br>

* Also refreshes chart

*/

public void setChartHeight(final double height) {

voyantChart.setChartHeight(height);

}

/**

* Tells the chart to turn on or off automatic range axis scaling.<br>

* Will not refresh the chart

* @param auto on or off

*/

private void setAutoAdjustRangeAxis(boolean auto) {

voyantChart.setAutoAdjustRangeAxis(auto);

}

private VoyantChart createVoyantChart() {

voyantCategoryPlot = new VoyantCategoryPlot(chartConfig, lowerPane);

voyantChart = new VoyantChart(voyantCategoryPlot, chartConfig);

voyantChart.setBorderVisible(false);

voyantChart.setBackgroundPaint(AppStyle.getInstance().chartRangeBackgroundColor);

return voyantChart;

}

private JPanel createChartLabelPanel() {

JPanel panel = new JPanel(new BorderLayout());

panel.setBackground(AppStyle.getInstance().chartDomainBackgroundColor);

stageTimelinePanel = new StageTimelinePanel(voyantChartPanel, lowerPane, chartConfig);

panel.add(BorderLayout.NORTH, stageTimelinePanel);

if (!lowerPane) {

chartDomainLabel = new ChartDomainLabel(voyantChartPanel);

panel.add(BorderLayout.SOUTH, chartDomainLabel);

}

return panel;

}

public static void refreshCharts() {

upperCCP.refreshChart();

lowerCCP.refreshChart();

}

protected class CCPListener

implements ClientCalculationListener, ClientPeriodListener {

public void calculationStarted(CalculationEvent e, Plan plan) {

// Do this NOW

try {

setAutoAdjustRangeAxis(true);

} catch (Exception e1) {}

}

public void calculationCompleted(CalculationEvent e, Plan plan) {

// Do this NOW

try {

setAutoAdjustRangeAxis(false);

} catch (Exception e1) {}

// Then do this later

VoyantEventQueue.invokeLater(new Runnable() {

public void run() {

refreshChart();

repaint();

}

});

}

public void periodStarted(PeriodEvent event, Plan plan) {

// no op

}

public void periodCompleted(PeriodEvent event, Plan plan) {

VoyantEventQueue.invokeLater(new Runnable() {

public void run() {

autoAdjustRangeAxis();

}

});

}

}

private class ChartLayout implements LayoutManager2 {

public void layoutContainer(Container parent) {

Dimension size = parent.getSize();

voyantChartPanel.setBounds(0, 0, size.width, size.height);

voyantChartPanel.setSize(size);

int leftSide = (int) VoyantCategoryPlot.getRangeAxisWidth();

chartStageEditorPanel.setBounds(leftSide, 0, size.width, size.height);

}

public float getLayoutAlignmentX(Container target) {

return 0;

}

public float getLayoutAlignmentY(Container target) {

return 0;

}

public Dimension maximumLayoutSize(Container target) {

return voyantChartPanel.getMaximumSize();

}

public Dimension preferredLayoutSize(Container parent) {

return voyantChartPanel.getPreferredSize();

}

public Dimension minimumLayoutSize(Container parent) {

return voyantChartPanel.getMinimumSize();

}

// --------------------------------------------

public void addLayoutComponent(Component comp, Object constraints) {}

public void invalidateLayout(Container target) {}

public void addLayoutComponent(String name, Component comp) {}

public void removeLayoutComponent(Component comp) {}

}

}