1. /* ===========================================================
  2. * JFreeChart : a free chart library for the Java(tm) platform
  3. * ===========================================================
  4. *
  5. * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
  6. *
  7. * Project Info: http://www.jfree.org/jfreechart/index.html
  8. *
  9. * This library is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU Lesser General Public License as published by
  11. * the Free Software Foundation; either version 2.1 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  17. * License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this library; if not, write to the Free Software Foundation,
  21. * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  22. *
  23. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  24. * in the United States and other countries.]
  25. *
  26. * -------------------------
  27. * TaskSeriesCollection.java
  28. * -------------------------
  29. * (C) Copyright 2002-2005, by Object Refinery Limited.
  30. *
  31. * Original Author: David Gilbert (for Object Refinery Limited);
  32. * Contributor(s): Thomas Schuster;
  33. *
  34. * $Id: TaskSeriesCollection.java,v 1.7 2005/03/04 11:45:57 mungady Exp $
  35. *
  36. * Changes
  37. * -------
  38. * 06-Jun-2002 : Version 1 (DG);
  39. * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  40. * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
  41. * CategoryToolTipGenerator interface (DG);
  42. * 10-Jan-2003 : Renamed GanttSeriesCollection --> TaskSeriesCollection (DG);
  43. * 04-Sep-2003 : Fixed bug 800324 (DG);
  44. * 16-Sep-2003 : Implemented GanttCategoryDataset (DG);
  45. * 12-Jan-2005 : Fixed bug 1099331 (DG);
  46. *
  47. */
  48. package org.jfree.data.gantt;
  49. import java.io.Serializable;
  50. import java.util.Iterator;
  51. import java.util.List;
  52. import org.jfree.data.general.AbstractSeriesDataset;
  53. import org.jfree.data.general.SeriesChangeEvent;
  54. import org.jfree.data.time.TimePeriod;
  55. import org.jfree.util.ObjectUtilities;
  56. import org.jfree.util.PublicCloneable;
  57. /**
  58. * A collection of {@link TaskSeries} objects. This class provides one
  59. * implementation of the {@link GanttCategoryDataset} interface.
  60. */
  61. public class TaskSeriesCollection extends AbstractSeriesDataset
  62. implements GanttCategoryDataset,
  63. Cloneable, PublicCloneable,
  64. Serializable {
  65. /**
  66. * Storage for aggregate task keys (the task description is used as the
  67. * key).
  68. */
  69. private List keys;
  70. /** Storage for the series. */
  71. private List data;
  72. /**
  73. * Default constructor.
  74. */
  75. public TaskSeriesCollection() {
  76. this.keys = new java.util.ArrayList();
  77. this.data = new java.util.ArrayList();
  78. }
  79. /**
  80. * Returns the number of series in the collection.
  81. *
  82. * @return The series count.
  83. */
  84. public int getSeriesCount() {
  85. return getRowCount();
  86. }
  87. /**
  88. * Returns the name of a series.
  89. *
  90. * @param series the series index (zero-based).
  91. *
  92. * @return The name of a series.
  93. */
  94. public String getSeriesName(int series) {
  95. TaskSeries ts = (TaskSeries) this.data.get(series);
  96. return ts.getName();
  97. }
  98. /**
  99. * Returns the number of rows (series) in the collection.
  100. *
  101. * @return The series count.
  102. */
  103. public int getRowCount() {
  104. return this.data.size();
  105. }
  106. /**
  107. * Returns the row keys. In this case, each series is a key.
  108. *
  109. * @return The row keys.
  110. */
  111. public List getRowKeys() {
  112. return this.data;
  113. }
  114. /**
  115. * Returns the number of column in the dataset.
  116. *
  117. * @return The column count.
  118. */
  119. public int getColumnCount() {
  120. return this.keys.size();
  121. }
  122. /**
  123. * Returns a list of the column keys in the dataset.
  124. *
  125. * @return The category list.
  126. */
  127. public List getColumnKeys() {
  128. return this.keys;
  129. }
  130. /**
  131. * Returns a column key.
  132. *
  133. * @param index the column index.
  134. *
  135. * @return The column key.
  136. */
  137. public Comparable getColumnKey(int index) {
  138. return (Comparable) this.keys.get(index);
  139. }
  140. /**
  141. * Returns the column index for a column key.
  142. *
  143. * @param columnKey the columnKey.
  144. *
  145. * @return The column index.
  146. */
  147. public int getColumnIndex(Comparable columnKey) {
  148. return this.keys.indexOf(columnKey);
  149. }
  150. /**
  151. * Returns the row index for the given row key.
  152. *
  153. * @param rowKey the row key.
  154. *
  155. * @return The index.
  156. */
  157. public int getRowIndex(Comparable rowKey) {
  158. int result = -1;
  159. int count = this.data.size();
  160. for (int i = 0; i < count; i++) {
  161. TaskSeries s = (TaskSeries) this.data.get(i);
  162. if (s.getName().equals(rowKey)) {
  163. result = i;
  164. break;
  165. }
  166. }
  167. return result;
  168. }
  169. /**
  170. * Returns the key for a row.
  171. *
  172. * @param index the row index (zero-based).
  173. *
  174. * @return The key.
  175. */
  176. public Comparable getRowKey(int index) {
  177. TaskSeries series = (TaskSeries) this.data.get(index);
  178. return series.getName();
  179. }
  180. /**
  181. * Adds a series to the dataset and sends a
  182. * {@link org.jfree.data.general.DatasetChangeEvent} to all registered
  183. * listeners.
  184. *
  185. * @param series the series (<code>null</code> not permitted).
  186. */
  187. public void add(TaskSeries series) {
  188. if (series == null) {
  189. throw new IllegalArgumentException("Null 'series' argument.");
  190. }
  191. this.data.add(series);
  192. series.addChangeListener(this);
  193. // look for any keys that we don't already know about...
  194. Iterator iterator = series.getTasks().iterator();
  195. while (iterator.hasNext()) {
  196. Task task = (Task) iterator.next();
  197. String key = task.getDescription();
  198. int index = this.keys.indexOf(key);
  199. if (index < 0) {
  200. this.keys.add(key);
  201. }
  202. }
  203. fireDatasetChanged();
  204. }
  205. /**
  206. * Removes a series from the collection and sends
  207. * a {@link org.jfree.data.general.DatasetChangeEvent}
  208. * to all registered listeners.
  209. *
  210. * @param series the series.
  211. */
  212. public void remove(TaskSeries series) {
  213. if (series == null) {
  214. throw new IllegalArgumentException("Null 'series' argument.");
  215. }
  216. if (this.data.contains(series)) {
  217. series.removeChangeListener(this);
  218. this.data.remove(series);
  219. fireDatasetChanged();
  220. }
  221. }
  222. /**
  223. * Removes a series from the collection and sends
  224. * a {@link org.jfree.data.general.DatasetChangeEvent}
  225. * to all registered listeners.
  226. *
  227. * @param series the series (zero based index).
  228. */
  229. public void remove(int series) {
  230. if ((series < 0) || (series > getSeriesCount())) {
  231. throw new IllegalArgumentException(
  232. "TaskSeriesCollection.remove(): index outside valid range.");
  233. }
  234. // fetch the series, remove the change listener, then remove the series.
  235. TaskSeries ts = (TaskSeries) this.data.get(series);
  236. ts.removeChangeListener(this);
  237. this.data.remove(series);
  238. fireDatasetChanged();
  239. }
  240. /**
  241. * Removes all the series from the collection and sends
  242. * a {@link org.jfree.data.general.DatasetChangeEvent}
  243. * to all registered listeners.
  244. */
  245. public void removeAll() {
  246. // deregister the collection as a change listener to each series in
  247. // the collection.
  248. Iterator iterator = this.data.iterator();
  249. while (iterator.hasNext()) {
  250. TaskSeries series = (TaskSeries) iterator.next();
  251. series.removeChangeListener(this);
  252. }
  253. // remove all the series from the collection and notify listeners.
  254. this.data.clear();
  255. fireDatasetChanged();
  256. }
  257. /**
  258. * Returns the value for an item.
  259. *
  260. * @param rowKey the row key.
  261. * @param columnKey the column key.
  262. *
  263. * @return The item value.
  264. */
  265. public Number getValue(Comparable rowKey, Comparable columnKey) {
  266. return getStartValue(rowKey, columnKey);
  267. }
  268. /**
  269. * Returns the value for a task.
  270. *
  271. * @param row the row index (zero-based).
  272. * @param column the column index (zero-based).
  273. *
  274. * @return The start value.
  275. */
  276. public Number getValue(int row, int column) {
  277. return getStartValue(row, column);
  278. }
  279. /**
  280. * Returns the start value for a task.
  281. *
  282. * @param rowKey the series.
  283. * @param columnKey the category.
  284. *
  285. * @return The start value.
  286. */
  287. public Number getStartValue(Comparable rowKey, Comparable columnKey) {
  288. Number result = null;
  289. int row = getRowIndex(rowKey);
  290. TaskSeries series = (TaskSeries) this.data.get(row);
  291. Task task = series.get(columnKey.toString());
  292. if (task != null) {
  293. TimePeriod duration = task.getDuration();
  294. result = new Long(duration.getStart().getTime());
  295. }
  296. return result;
  297. }
  298. /**
  299. * Returns the start value for a task.
  300. *
  301. * @param row the row index (zero-based).
  302. * @param column the column index (zero-based).
  303. *
  304. * @return The start value.
  305. */
  306. public Number getStartValue(int row, int column) {
  307. Comparable rowKey = getRowKey(row);
  308. Comparable columnKey = getColumnKey(column);
  309. return getStartValue(rowKey, columnKey);
  310. }
  311. /**
  312. * Returns the end value for a task.
  313. *
  314. * @param rowKey the series.
  315. * @param columnKey the category.
  316. *
  317. * @return The end value.
  318. */
  319. public Number getEndValue(Comparable rowKey, Comparable columnKey) {
  320. Number result = null;
  321. int row = getRowIndex(rowKey);
  322. TaskSeries series = (TaskSeries) this.data.get(row);
  323. Task task = series.get(columnKey.toString());
  324. if (task != null) {
  325. TimePeriod duration = task.getDuration();
  326. result = new Long(duration.getEnd().getTime());
  327. }
  328. return result;
  329. }
  330. /**
  331. * Returns the end value for a task.
  332. *
  333. * @param row the row index (zero-based).
  334. * @param column the column index (zero-based).
  335. *
  336. * @return The end value.
  337. */
  338. public Number getEndValue(int row, int column) {
  339. Comparable rowKey = getRowKey(row);
  340. Comparable columnKey = getColumnKey(column);
  341. return getEndValue(rowKey, columnKey);
  342. }
  343. /**
  344. * Returns the percent complete for a given item.
  345. *
  346. * @param row the row index (zero-based).
  347. * @param column the column index (zero-based).
  348. *
  349. * @return The percent complete (possibly <code>null</code>).
  350. */
  351. public Number getPercentComplete(int row, int column) {
  352. Comparable rowKey = getRowKey(row);
  353. Comparable columnKey = getColumnKey(column);
  354. return getPercentComplete(rowKey, columnKey);
  355. }
  356. /**
  357. * Returns the percent complete for a given item.
  358. *
  359. * @param rowKey the row key.
  360. * @param columnKey the column key.
  361. *
  362. * @return The percent complete.
  363. */
  364. public Number getPercentComplete(Comparable rowKey, Comparable columnKey) {
  365. Number result = null;
  366. int row = getRowIndex(rowKey);
  367. TaskSeries series = (TaskSeries) this.data.get(row);
  368. Task task = series.get(columnKey.toString());
  369. if (task != null) {
  370. result = task.getPercentComplete();
  371. }
  372. return result;
  373. }
  374. /**
  375. * Returns the number of sub-intervals for a given item.
  376. *
  377. * @param row the row index (zero-based).
  378. * @param column the column index (zero-based).
  379. *
  380. * @return The sub-interval count.
  381. */
  382. public int getSubIntervalCount(int row, int column) {
  383. Comparable rowKey = getRowKey(row);
  384. Comparable columnKey = getColumnKey(column);
  385. return getSubIntervalCount(rowKey, columnKey);
  386. }
  387. /**
  388. * Returns the number of sub-intervals for a given item.
  389. *
  390. * @param rowKey the row key.
  391. * @param columnKey the column key.
  392. *
  393. * @return The sub-interval count.
  394. */
  395. public int getSubIntervalCount(Comparable rowKey, Comparable columnKey) {
  396. int result = 0;
  397. int row = getRowIndex(rowKey);
  398. TaskSeries series = (TaskSeries) this.data.get(row);
  399. Task task = series.get(columnKey.toString());
  400. if (task != null) {
  401. result = task.getSubtaskCount();
  402. }
  403. return result;
  404. }
  405. /**
  406. * Returns the start value of a sub-interval for a given item.
  407. *
  408. * @param row the row index (zero-based).
  409. * @param column the column index (zero-based).
  410. * @param subinterval the sub-interval index (zero-based).
  411. *
  412. * @return The start value (possibly <code>null</code>).
  413. */
  414. public Number getStartValue(int row, int column, int subinterval) {
  415. Comparable rowKey = getRowKey(row);
  416. Comparable columnKey = getColumnKey(column);
  417. return getStartValue(rowKey, columnKey, subinterval);
  418. }
  419. /**
  420. * Returns the start value of a sub-interval for a given item.
  421. *
  422. * @param rowKey the row key.
  423. * @param columnKey the column key.
  424. * @param subinterval the subinterval.
  425. *
  426. * @return The start value (possibly <code>null</code>).
  427. */
  428. public Number getStartValue(Comparable rowKey, Comparable columnKey,
  429. int subinterval) {
  430. Number result = null;
  431. int row = getRowIndex(rowKey);
  432. TaskSeries series = (TaskSeries) this.data.get(row);
  433. Task task = series.get(columnKey.toString());
  434. if (task != null) {
  435. Task sub = task.getSubtask(subinterval);
  436. if (sub != null) {
  437. TimePeriod duration = sub.getDuration();
  438. result = new Long(duration.getStart().getTime());
  439. }
  440. }
  441. return result;
  442. }
  443. /**
  444. * Returns the end value of a sub-interval for a given item.
  445. *
  446. * @param row the row index (zero-based).
  447. * @param column the column index (zero-based).
  448. * @param subinterval the subinterval.
  449. *
  450. * @return The end value (possibly <code>null</code>).
  451. */
  452. public Number getEndValue(int row, int column, int subinterval) {
  453. Comparable rowKey = getRowKey(row);
  454. Comparable columnKey = getColumnKey(column);
  455. return getEndValue(rowKey, columnKey, subinterval);
  456. }
  457. /**
  458. * Returns the end value of a sub-interval for a given item.
  459. *
  460. * @param rowKey the row key.
  461. * @param columnKey the column key.
  462. * @param subinterval the subinterval.
  463. *
  464. * @return The end value (possibly <code>null</code>).
  465. */
  466. public Number getEndValue(Comparable rowKey, Comparable columnKey,
  467. int subinterval) {
  468. Number result = null;
  469. int row = getRowIndex(rowKey);
  470. TaskSeries series = (TaskSeries) this.data.get(row);
  471. Task task = series.get(columnKey.toString());
  472. if (task != null) {
  473. Task sub = task.getSubtask(subinterval);
  474. if (sub != null) {
  475. TimePeriod duration = sub.getDuration();
  476. result = new Long(duration.getEnd().getTime());
  477. }
  478. }
  479. return result;
  480. }
  481. /**
  482. * Returns the percentage complete value of a sub-interval for a given item.
  483. *
  484. * @param row the row index (zero-based).
  485. * @param column the column index (zero-based).
  486. * @param subinterval the sub-interval.
  487. *
  488. * @return The percent complete value (possibly <code>null</code>).
  489. */
  490. public Number getPercentComplete(int row, int column, int subinterval) {
  491. Comparable rowKey = getRowKey(row);
  492. Comparable columnKey = getColumnKey(column);
  493. return getPercentComplete(rowKey, columnKey, subinterval);
  494. }
  495. /**
  496. * Returns the percentage complete value of a sub-interval for a given item.
  497. *
  498. * @param rowKey the row key.
  499. * @param columnKey the column key.
  500. * @param subinterval the sub-interval.
  501. *
  502. * @return The precent complete value (possibly <code>null</code>).
  503. */
  504. public Number getPercentComplete(Comparable rowKey, Comparable columnKey,
  505. int subinterval) {
  506. Number result = null;
  507. int row = getRowIndex(rowKey);
  508. TaskSeries series = (TaskSeries) this.data.get(row);
  509. Task task = series.get(columnKey.toString());
  510. if (task != null) {
  511. Task sub = task.getSubtask(subinterval);
  512. if (sub != null) {
  513. result = sub.getPercentComplete();
  514. }
  515. }
  516. return result;
  517. }
  518. /**
  519. * Called when a series belonging to the dataset changes.
  520. *
  521. * @param event information about the change.
  522. */
  523. public void seriesChanged(SeriesChangeEvent event) {
  524. refreshKeys();
  525. fireDatasetChanged();
  526. }
  527. /**
  528. * Refreshes the keys.
  529. */
  530. private void refreshKeys() {
  531. this.keys.clear();
  532. for (int i = 0; i < getSeriesCount(); i++) {
  533. TaskSeries series = (TaskSeries) this.data.get(i);
  534. // look for any keys that we don't already know about...
  535. Iterator iterator = series.getTasks().iterator();
  536. while (iterator.hasNext()) {
  537. Task task = (Task) iterator.next();
  538. String key = task.getDescription();
  539. int index = this.keys.indexOf(key);
  540. if (index < 0) {
  541. this.keys.add(key);
  542. }
  543. }
  544. }
  545. }
  546. /**
  547. * Tests this instance for equality with an arbitrary object.
  548. *
  549. * @param obj the object (<code>null</code> permitted).
  550. *
  551. * @return A boolean.
  552. */
  553. public boolean equals(Object obj) {
  554. if (obj == this) {
  555. return true;
  556. }
  557. if (!(obj instanceof TaskSeriesCollection)) {
  558. return false;
  559. }
  560. TaskSeriesCollection that = (TaskSeriesCollection) obj;
  561. if (!ObjectUtilities.equal(this.data, that.data)) {
  562. return false;
  563. }
  564. return true;
  565. }
  566. }