001/* ======================================================
002 * Orson : a free chart beans library based on JFreeChart
003 * ======================================================
004 *
005 * (C) Copyright 2007, by Object Refinery Limited.
006 *
007 * Project Info:  not-yet-released
008 *
009 * This library is free software; you can redistribute it and/or modify it 
010 * under the terms of the GNU Lesser General Public License as published by 
011 * the Free Software Foundation; either version 2.1 of the License, or 
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but 
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022 * USA.  
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025 * in the United States and other countries.]
026 */
027
028package org.jfree.beans.editors;
029
030import java.awt.BorderLayout;
031
032import javax.swing.JFrame;
033import javax.swing.JPanel;
034import javax.swing.JScrollPane;
035import javax.swing.JSplitPane;
036import javax.swing.JTable;
037import javax.swing.border.EmptyBorder;
038import javax.swing.event.TableModelEvent;
039import javax.swing.event.TableModelListener;
040import javax.swing.table.AbstractTableModel;
041import javax.swing.table.TableModel;
042
043import org.jfree.chart.ChartFactory;
044import org.jfree.chart.ChartPanel;
045import org.jfree.chart.JFreeChart;
046import org.jfree.data.general.DefaultPieDataset;
047
048/**
049 * A GUI for editing a pie dataset.
050 */
051public class PieDatasetGUI extends JPanel implements TableModelListener {
052
053    class MyPieDatasetTableModel extends AbstractTableModel 
054            implements TableModel {
055
056        /* (non-Javadoc)
057         * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int)
058         */
059        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
060            if (columnIndex == 0) {
061                if (aValue == null) {
062                    throw new IllegalArgumentException("'aValue' is null.");
063                }
064                Comparable key = aValue.toString();
065                int keyIndex = this.dataset.getIndex(key);
066                Comparable oldKey = this.dataset.getKey(rowIndex);
067                if (keyIndex == rowIndex) {
068                    return;  // nothing to do
069                } 
070                if (keyIndex >= 0) {
071                    throw new IllegalArgumentException("Key already exists!");
072                }
073                Number value = this.dataset.getValue(rowIndex);
074                this.dataset.insertValue(rowIndex, key, value);
075                this.dataset.remove(oldKey);
076                fireTableCellUpdated(rowIndex, columnIndex);
077            }
078            else if (columnIndex == 1) {
079                Comparable key = this.dataset.getKey(rowIndex);
080                Double value = Double.valueOf(aValue.toString());
081                this.dataset.insertValue(rowIndex, key, value);
082                fireTableCellUpdated(rowIndex, columnIndex);
083            }
084        }
085
086        public boolean isCellEditable(int rowIndex, int columnIndex) {
087            return true;
088        }
089
090        private DefaultPieDataset dataset;
091        
092        private int editingRow;
093        
094        private Comparable newKey;
095        
096        private Number newValue;
097        
098        /**
099         * Creates a new table model.
100         * 
101         * @param dataset
102         */
103        public MyPieDatasetTableModel(DefaultPieDataset dataset) {
104            this.dataset = dataset;
105            this.editingRow = -1;
106        }
107        
108        public int getColumnCount() {
109            return 2;
110        }
111
112        /**
113         * Returns the current row count.
114         * 
115         * @return The row count.
116         */
117        public int getRowCount() {
118            int result = this.dataset.getItemCount();
119            if (this.editingRow >= 0) {
120                result++;
121            }
122            return result;
123        }
124
125        /**
126         * Returns a value from the table model.
127         * 
128         * @param rowIndex  the row index.
129         * @param columnIndex  the column index.
130         * 
131         * @return The value.
132         */
133        public Object getValueAt(int rowIndex, int columnIndex) {
134            
135            // if there is no editing row, or rowIndex is less than the current
136            // editing row, we can just fetch directly from the dataset...
137            if (this.editingRow < 0 || rowIndex < this.editingRow) {
138                if (columnIndex == 0) {
139                    return this.dataset.getKey(rowIndex);
140                }
141                else if (columnIndex == 1) {
142                    return this.dataset.getValue(rowIndex);
143                }
144            }
145            
146            // ...otherwise, if rowIndex is the current editing row, we should
147            // return the edit values...
148            else if (rowIndex == this.editingRow) {
149                if (columnIndex == 0) {
150                    return this.newKey;
151                }
152                else if (columnIndex ==1) {
153                    return this.newValue;
154                }
155                
156            }
157            
158            // ...finally, this is the case where there is an editing row, but
159            // we're looking for an item further on...
160            else {
161                if (columnIndex == 0) {
162                    return this.dataset.getKey(rowIndex - 1);
163                }
164                else if (columnIndex == 1) {
165                    return this.dataset.getValue(rowIndex - 1);
166                }
167            }
168  
169            // we really shouldn't get this far...
170            return null;
171        }
172
173        
174    }
175
176    /**
177     * Creates a new instance.
178     * 
179     * @param dataset  the dataset.
180     */
181    public PieDatasetGUI(DefaultPieDataset dataset) {
182        super(new BorderLayout());
183        setBorder(new EmptyBorder(2, 2, 2, 2));
184        JTable table = new JTable();
185        table.setModel(new MyPieDatasetTableModel(dataset));
186        table.getModel().addTableModelListener(this);
187        add(new JScrollPane(table));
188    }
189
190    /* (non-Javadoc)
191     * @see javax.swing.event.TableModelListener#tableChanged(javax.swing.event.TableModelEvent)
192     */
193    public void tableChanged(TableModelEvent e) {
194        System.out.println(e.toString());
195    }
196    
197    /**
198     * Starting point for a test app.
199     * 
200     * @param args  ignored.
201     */
202    public static void main(String[] args) {
203        JFrame app = new JFrame("PieDataset Editor");
204        JSplitPane gui = new JSplitPane();
205        DefaultPieDataset dataset = new DefaultPieDataset();
206        dataset.setValue("A", 1.0);
207        dataset.setValue("B", 3.0);
208        dataset.setValue("C", 3.0);
209        dataset.setValue("D", 3.0);
210        dataset.setValue("E", 3.0);
211        dataset.setValue("F", 3.0);
212        dataset.setValue("G", 3.0);
213        dataset.setValue("H", 3.0);
214        dataset.setValue("I", 3.0);
215        dataset.setValue("J", 3.0);
216        JFreeChart chart = ChartFactory.createPieChart("Pie Chart", dataset, 
217                true, true, false);
218        ChartPanel chartPanel = new ChartPanel(chart);
219        PieDatasetGUI datasetTable = new PieDatasetGUI(dataset);
220        gui.add(chartPanel, JSplitPane.TOP);
221        gui.add(datasetTable, JSplitPane.BOTTOM);
222        app.getContentPane().add(gui);
223        app.pack();
224        app.setVisible(true);
225    }
226}