001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.logistics.ui.inventory;
028:
029: import java.util.Date;
030:
031: import java.awt.*;
032:
033: import javax.swing.JPanel;
034: import javax.swing.BorderFactory;
035: import javax.swing.JLabel;
036:
037: import com.klg.jclass.chart.JCChart;
038: import com.klg.jclass.chart.data.JCDefaultDataSource;
039: import com.klg.jclass.util.swing.JCExitFrame;
040: import com.klg.jclass.chart.JCFillStyle;
041: import com.klg.jclass.chart.JCAxis;
042: import com.klg.jclass.chart.JCAxisTitle;
043: import com.klg.jclass.chart.JCPickListener;
044: import com.klg.jclass.chart.EventTrigger;
045: import com.klg.jclass.chart.JCChartListener;
046:
047: import com.klg.jclass.util.legend.JCLegend;
048: import com.klg.jclass.util.legend.JCMultiColLegend;
049:
050: import com.klg.jclass.chart.ChartDataView;
051: import com.klg.jclass.chart.ChartDataViewSeries;
052: import com.klg.jclass.chart.ChartDataModel;
053: import com.klg.jclass.chart.ChartDataEvent;
054: import com.klg.jclass.chart.ChartText;
055:
056: import org.cougaar.util.log.Logging;
057: import org.cougaar.util.log.Logger;
058:
059: import org.cougaar.logistics.ui.inventory.data.InventoryData;
060: import org.cougaar.logistics.ui.inventory.data.InventoryPreferenceData;
061: import org.cougaar.logistics.plugin.inventory.TimeUtils;
062:
063: /**
064: * <pre>
065: * <p/>
066: * The InventoryChart class is the base class for all Inventory
067: * charts displayed in the GUI. It contains all the shared
068: * behavior of all charts in the GUI.
069: */
070:
071: public abstract class InventoryChart extends JPanel {
072:
073: private final static long MILLIS_IN_DAY = TimeUtils.MSEC_PER_DAY;
074:
075: protected static InventoryUnitConversionTable conversionTable = null;
076:
077: protected JCChart chart = null;
078: protected InventoryData inventory = null;
079:
080: protected boolean displayCDay = false;
081: protected String myYAxisTitle;
082: protected String myTitle;
083:
084: protected int viewIndex;
085:
086: protected Logger logger;
087:
088: protected long currBucketSize = MILLIS_IN_DAY;
089:
090: protected InventoryPreferenceData prefData;
091: protected InventoryColorTable colorTable;
092: protected String colorScheme;
093:
094: public InventoryChart() {
095:
096: }
097:
098: public InventoryChart(InventoryPreferenceData prefData) {
099: this .prefData = prefData;
100: colorTable = prefData.getColorTable();
101: colorScheme = prefData.getColorScheme();
102: }
103:
104: public abstract void initializeChart();
105:
106: public void initialize(String title, boolean initialDisplayCDay) {
107: int gridx = 0;
108: int gridy = 0;
109:
110: viewIndex = 0;
111:
112: logger = Logging.getLogger(this );
113:
114: displayCDay = initialDisplayCDay;
115:
116: Insets blankInsets = new Insets(0, 0, 0, 0);
117:
118: myTitle = title;
119: chart = new JCChart();
120: initializeChart();
121: customizeAxes("");
122:
123: if (myTitle != null) {
124: chart.setHeader(new JLabel(myTitle));
125: }
126:
127: // allow user to zoom in on chart
128: chart.setTrigger(0, new EventTrigger(0, EventTrigger.ZOOM));
129:
130: // allow interactive customization using left shift click
131: chart.setAllowUserChanges(true);
132: chart.setTrigger(1, new EventTrigger(Event.SHIFT_MASK,
133: EventTrigger.CUSTOMIZE));
134:
135: // allow user to display labels using right mouse click
136: chart.setTrigger(1, new EventTrigger(Event.META_MASK,
137: EventTrigger.PICK));
138:
139: // set header and legend to black
140: // set beveled borders around plot area and chart
141: ((JLabel) chart.getHeader()).setForeground(Color.black);
142: chart.setBorder(BorderFactory.createLoweredBevelBorder());
143: chart.getChartArea().setBorder(
144: BorderFactory.createLoweredBevelBorder());
145:
146: // add chart to panel
147: setLayout(new GridBagLayout());
148: chart.getHeader().setVisible(false);
149: add(chart, new GridBagConstraints(gridx, gridy++, 1, 1, 1.0,
150: 1.0, GridBagConstraints.CENTER,
151: GridBagConstraints.BOTH, blankInsets, 0, 0));
152:
153: JCMultiColLegend legend = new JCMultiColLegend();
154: legend.setNumColumns(1);
155: chart.setLegend(legend);
156:
157: // set legend invisible, because we create our own??
158: chart.getLegend().setVisible(true);
159: chart.getLegend().setPreferredSize(new Dimension(148, 110)); //95
160:
161: }
162:
163: public JCChart getChart() {
164: return chart;
165: }
166:
167: public void addChartListener(JCChartListener listener) {
168: chart.addChartListener(listener);
169: }
170:
171: public void removeChartListener(JCChartListener listener) {
172: chart.removeChartListener(listener);
173: }
174:
175: public void addPickListener(JCPickListener listener) {
176: chart.addPickListener(listener);
177: }
178:
179: public void removePickListener(JCPickListener listener) {
180: chart.removePickListener(listener);
181: }
182:
183: public JCAxis getFirstXAxis() {
184: java.util.List viewList = chart.getDataView();
185: if (viewList.size() > 0) {
186: ChartDataView chartDataView = (ChartDataView) viewList
187: .get(0);
188: return chartDataView.getXAxis();
189: }
190: return null;
191: }
192:
193: protected void resetYMin() {
194: java.util.List viewList = chart.getDataView();
195: for (int i = 0; i < viewList.size(); i++) {
196: ChartDataView chartDataView = (ChartDataView) viewList
197: .get(i);
198: JCAxis yaxis = chartDataView.getYAxis();
199: if (setYAxisMinToZero()) {
200: yaxis.setMin(0);
201: yaxis.setMinIsDefault(false);
202: } else {
203: yaxis.setMinIsDefault(true);
204: }
205: }
206: }
207:
208: public void resetAxes() {
209:
210: long baseCDayTime = 0L;
211: if (inventory != null) {
212: baseCDayTime = inventory.getStartCDay();
213: currBucketSize = inventory.getBucketSize();
214: }
215: java.util.List viewList = chart.getDataView();
216: for (int i = 0; i < viewList.size(); i++) {
217: ChartDataView chartDataView = (ChartDataView) viewList
218: .get(i);
219:
220: // use time axis for x axis
221: JCAxis xaxis = chartDataView.getXAxis();
222:
223: if (currBucketSize < MILLIS_IN_DAY) {
224: if (displayCDay) {
225: xaxis.setAnnotationMethod(JCAxis.VALUE);
226: xaxis.setPrecision(0);
227: xaxis.setTickSpacing(7);
228: xaxis.setGridSpacing(7);
229: xaxis.setGridVisible(true);
230: xaxis.setAnnotationRotation(JCAxis.ROTATE_NONE);
231:
232: /***
233: xaxis.setAnnotationMethod(JCAxis.TIME_LABELS);
234: xaxis.setTimeBase(new Date(0));
235: xaxis.setTimeUnit(JCAxis.HOURS);
236: xaxis.setTickSpacing(24);
237: xaxis.setGridSpacing(24);
238: xaxis.setTimeFormat("'CD H");
239: xaxis.setGridVisible(true);
240: xaxis.setAnnotationRotation(JCAxis.ROTATE_270);
241: **/
242: } else {
243: xaxis.setAnnotationMethod(JCAxis.TIME_LABELS);
244: xaxis.setTimeBase(new Date(
245: InventoryChartBaseCalendar.getBaseTime()));
246:
247: xaxis.setTimeUnit(JCAxis.HOURS);
248: xaxis.setTickSpacing(24);
249: xaxis.setGridSpacing(24);
250: xaxis.setTimeFormat("M/d H");
251:
252: /*
253: *if(logger.isDebugEnabled()) {
254: *logger.debug("Base Date is: " + new Date(InventoryChartBaseCalendar.getBaseTime()));
255: *}
256: */
257: xaxis.setGridVisible(true);
258: xaxis.setAnnotationRotation(JCAxis.ROTATE_270);
259: }
260:
261: } else {
262: if (displayCDay) {
263: xaxis.setAnnotationMethod(JCAxis.VALUE);
264: xaxis.setPrecision(0);
265:
266: //xaxis.setAnnotationMethod(JCAxis.TIME_LABELS);
267: //xaxis.setTimeUnit(JCAxis.DAYS);
268: //xaxis.setTimeBase(new Date(InventoryChartBaseCalendar.getBaseTime() - baseCDayTime ));
269: //xaxis.setTimeFormat("D");
270:
271: xaxis.setTickSpacing(7);
272: xaxis.setGridSpacing(7);
273: // xaxis.setTickSpacingIsDefault(true);
274: // xaxis.setGridSpacingIsDefault(true);
275: //xaxis.setMin(CDAY_MIN);
276: xaxis.setGridVisible(true);
277: xaxis.setAnnotationRotation(JCAxis.ROTATE_NONE);
278: } else {
279: xaxis.setAnnotationMethod(JCAxis.TIME_LABELS);
280: xaxis.setTimeBase(new Date(
281: InventoryChartBaseCalendar.getBaseTime()));
282:
283: xaxis.setTimeUnit(JCAxis.DAYS);
284: xaxis.setTickSpacing(7);
285: xaxis.setGridSpacing(7);
286: xaxis.setTimeFormat("M/d");
287:
288: /*
289: *if(logger.isDebugEnabled()) {
290: *logger.debug("Base Date is: " + new Date(InventoryChartBaseCalendar.getBaseTime()));
291: *}
292: */
293: xaxis.setGridVisible(true);
294: xaxis.setAnnotationRotation(JCAxis.ROTATE_270);
295: }
296: }
297:
298: // y axis titles
299: JCAxis yaxis = chartDataView.getYAxis();
300: yaxis.setGridVisible(true);
301: JCAxisTitle yAxisTitle = new JCAxisTitle(myYAxisTitle);
302: yAxisTitle.setRotation(ChartText.DEG_270);
303: yAxisTitle.setPlacement(JCLegend.WEST);
304: yaxis.setTitle(yAxisTitle);
305:
306: if (setYAxisMinToZero()) {
307: yaxis.setMin(0);
308: yaxis.setMinIsDefault(false);
309: } else {
310: yaxis.setMinIsDefault(true);
311: }
312: // yaxis.setEditable(false); // don't allow zoomin on this axis
313: //(Math.round(getYMin())); // set zero as the minimum value on the axis
314: }
315: }
316:
317: /**
318: * paintNowBar creates a horizontal line on any chart given a now time. This was needed by multiple charts
319: * in LAT. Rather than copy it to several places the base chart was the best place where it belonged - here.
320: * It is a NO-OP here as it is not called in albbn and getNowTime() always is less than 0.
321: *
322: * @param g - A Graphics Context.
323: */
324:
325: public void paintNowBar(Graphics g) {
326:
327: if (inventory == null || (inventory.getNowTime() < 0)) {
328: return;
329: }
330: //Subtract an hour to be in the start time of the scenario start time bucket.
331: long nowTime = inventory.getNowTime() - (60 * 60 * 1000);
332:
333: java.util.List viewList = chart.getDataView();
334: ChartDataView firstView = (ChartDataView) viewList.get(0);
335:
336: if (firstView == null) {
337: return;
338: }
339:
340: InventoryBaseChartDataModel dataModel = (InventoryBaseChartDataModel) firstView
341: .getDataSource();
342: //Add 1 so that you will be inside the same bucket as the start time of the scenario start time
343: int bucketTime = dataModel.computeBucketFromTime(nowTime + 1);
344:
345: // use time axis for x axis
346: JCAxis xaxis = firstView.getXAxis();
347:
348: double value = 0.0d;
349: int nowPixel = 0;
350:
351: if (displayCDay) {
352: value = bucketTime;
353:
354: JCAxis yaxis = firstView.getYAxis();
355: Rectangle yRect = yaxis.getDrawingArea();
356:
357: int yWidth = new Double(yRect.getWidth()).intValue();
358:
359: //The xaxis.toPixel(xaxis.getMin()) pixel translation of the origin value of the xaxis is wrong.
360: //It equals the x of the xAxis which is rougly 44 or the width of the y axis away. Hence the translation
361: //here. The toPixel value translated to the right by the width of the yAxis - which is just about where the
362: // origin.
363: nowPixel = new Double(xaxis.toPixel(value) + yWidth)
364: .intValue();
365: } else {
366: Date now = new Date(nowTime);
367: value = xaxis.dateToValue(now);
368: double origin = xaxis.getOrigin();
369: nowPixel = xaxis.toPixel(value) + xaxis.toPixel(origin);
370: }
371:
372: //logger.warn("\nOrigin is " + origin + "\n getMin is " + xaxis.getMin() + " and getMax is " + xaxis.getMax() +
373: //" \n and value is " + value + " \nand bucketTime is " + bucketTime +
374: //" \nand finally now Pixel is " + nowPixel);
375:
376: Color origColor = g.getColor();
377: g.setColor(Color.BLUE);
378:
379: Rectangle boundingRect = this .getBounds();
380: int boundsY = new Double(boundingRect.getY()).intValue();
381: int height = new Double(boundingRect.getHeight()).intValue();
382:
383: nowPixel = nowPixel - 1;
384: g.drawLine(nowPixel, boundsY, nowPixel, boundsY + height);
385: nowPixel++;
386: g.drawLine(nowPixel, boundsY, nowPixel, boundsY + height);
387: nowPixel++;
388: g.drawLine(nowPixel, boundsY, nowPixel, boundsY + height);
389:
390: g.setColor(origColor);
391: }
392:
393: protected void customizeAxes(String yAxisTitleText) {
394: myYAxisTitle = yAxisTitleText;
395: resetAxes();
396: }
397:
398: protected boolean setYAxisMinToZero() {
399: return true;
400: }
401:
402: public void setData(InventoryData data) {
403: inventory = data;
404: if (data.getBucketSize() != currBucketSize) {
405: resetAxes();
406: }
407: java.util.List viewList = chart.getDataView();
408: for (int i = 0; i < viewList.size(); i++) {
409: ChartDataView chartDataView = (ChartDataView) viewList
410: .get(i);
411: InventoryBaseChartDataModel dataModel = (InventoryBaseChartDataModel) chartDataView
412: .getDataSource();
413: dataModel.resetInventory(data);
414: }
415: myYAxisTitle = (conversionTable.getConversionForData(data,
416: prefData)).getUnit();
417: chart.reset();
418: resetAxes();
419: }
420:
421: public void setDisplayCDay(boolean doUseCDay) {
422: displayCDay = doUseCDay;
423: java.util.List viewList = chart.getDataView();
424: for (int i = viewList.size() - 1; i >= 0; i--) {
425: ChartDataView chartDataView = (ChartDataView) viewList
426: .get(i);
427: InventoryBaseChartDataModel dataModel = (InventoryBaseChartDataModel) chartDataView
428: .getDataSource();
429: dataModel.setDisplayCDay(displayCDay);
430: }
431: chart.reset();
432: resetAxes();
433: }
434:
435: protected ChartDataView addChartView(int chartType,
436: InventoryBaseChartDataModel dm) {
437:
438: ChartDataView chartDataView = new ChartDataView();
439: chartDataView.setChartType(chartType);
440: dm.setInitialDisplayCDay(displayCDay);
441: chartDataView.setDataSource(dm);
442: chart.setDataView(viewIndex, chartDataView);
443: viewIndex++;
444:
445: return chartDataView;
446: }
447:
448: protected int getChartViewIndex(ChartDataView chartDataView) {
449: for (int i = 0; i < viewIndex; i++) {
450: if (chartDataView == chart.getDataView(i)) {
451: return i;
452: }
453: }
454: return -1;
455: }
456:
457: protected void removeChartView(ChartDataView chartDataView) {
458: int chartIndex = getChartViewIndex(chartDataView);
459: if (chartIndex != -1) {
460: chart.removeDataView(chartIndex);
461: }
462: viewIndex--;
463: }
464:
465: protected void setSeriesColor(ChartDataViewSeries series,
466: Color color) {
467: series.getStyle().setLineColor(color);
468: series.getStyle().setFillColor(color);
469: series.getStyle().setSymbolColor(color);
470: }
471:
472: public void setXZoom(double start, double end) {
473: java.util.List viewList = chart.getDataView();
474: for (int i = 0; i < viewList.size(); i++) {
475: ChartDataView chartDataView = (ChartDataView) viewList
476: .get(i);
477: // use time axis for x axis
478: JCAxis xaxis = chartDataView.getXAxis();
479: chart.zoom(start, end, xaxis, true);
480: }
481: }
482:
483: public void prefDataChanged(InventoryPreferenceData origData,
484: InventoryPreferenceData newData) {
485: java.util.List viewList = chart.getDataView();
486: for (int i = 0; i < viewList.size(); i++) {
487: ChartDataView chartDataView = (ChartDataView) viewList
488: .get(i);
489: InventoryBaseChartDataModel dataModel = (InventoryBaseChartDataModel) chartDataView
490: .getDataSource();
491: dataModel.prefDataChanged(origData, newData);
492: }
493: prefData = newData;
494: colorTable = prefData.getColorTable();
495: colorScheme = prefData.getColorScheme();
496: }
497:
498: public static void setConversionTable(
499: InventoryUnitConversionTable convertTable) {
500: conversionTable = convertTable;
501: }
502:
503: public static InventoryUnitConversionTable getConversionTable() {
504: return conversionTable;
505: }
506: }
|