Subversion Repositories public

Rev

Rev 91 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
87 luk 1
/*
2
 * TaskTableModel.java - implementation of tracked tasks table model
3
 *
89 luk 4
 * Copyright (c) 2006, 2007, 2008 Lukas Jelinek, http://www.aiken.cz
87 luk 5
 *
6
 * ==========================================================================
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License Version 2 as
10
 * published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 *
21
 * ==========================================================================
22
 */
23
 
24
package cz.aiken.util.lwtt;
25
 
26
import javax.swing.*;
27
import javax.swing.table.*;
28
import java.util.*;
29
import java.io.*;
30
import java.awt.event.*;
89 luk 31
import java.math.*;
32
import java.text.*;
87 luk 33
 
34
/**
35
 * This class represents the task table model.
36
 * @author luk
37
 */
38
public class TaskTableModel extends AbstractTableModel implements ActionListener {
39
 
40
    private ArrayList<Task> tasks = new ArrayList<Task>();
41
    private javax.swing.Timer timer = new javax.swing.Timer(300000, this);
42
 
89 luk 43
    private MessageFormat timeFormat = new MessageFormat("{0,number}:{1,number,00}");
93 luk 44
    private MessageFormat priceFormat = new MessageFormat("{0,number}.{1,number,00}");
89 luk 45
 
46
    private TaskFrame taskFrame = null;
47
 
87 luk 48
    /**
49
     * Creates a new instance of TaskTableModel
89 luk 50
     * @param tf task frame instance
87 luk 51
     */
89 luk 52
    public TaskTableModel(TaskFrame tf) {
53
        taskFrame = tf;
87 luk 54
        loadFromFile();
55
        timer.start();
56
    }
57
 
58
    /**
59
     * Returns the value at the given coordinates.
60
     * @param rowIndex row index
61
     * @param columnIndex column index
62
     * @return appropriate cell value; if the arguments are invalid
63
     * it returns <CODE>null</CODE>
64
     */
65
    public Object getValueAt(int rowIndex, int columnIndex) {
66
        switch (columnIndex) {
89 luk 67
            case 0:
68
                return tasks.get(rowIndex).getName();
69
            case 1:
70
                long mins = tasks.get(rowIndex).getConsumption() / 60000;
71
                BigDecimal hm[] = new BigDecimal((int) mins).divideAndRemainder(new BigDecimal(60));
72
                return timeFormat.format(hm);
93 luk 73
            case 2:
74
                double tp = tasks.get(rowIndex).getTotalPrice();
75
                BigDecimal pr[] = new BigDecimal(tp * 100).divideAndRemainder(new BigDecimal(100));
76
                return priceFormat.format(pr);
87 luk 77
            default: return null;
78
        }
79
    }
80
 
81
    /**
82
     * Returns the row count.
83
     * @return row count
84
     */
85
    public int getRowCount() {
86
        return tasks.size();
87
    }
88
 
89
    /**
90
     * Returns the column count (currently 2).
91
     * @return column count
92
     */
93
    public int getColumnCount() {
93 luk 94
        return 3;
87 luk 95
    }
96
 
97
    /**
98
     * Sets a new value of the given cell. If at least one of the
99
     * coordinates is invalid it does nothing.
100
     * @param aValue new value
101
     * @param rowIndex row index
102
     * @param columnIndex column index
103
     */
89 luk 104
    @Override
87 luk 105
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
106
        switch (columnIndex) {
107
            case 0: tasks.get(rowIndex).setName((String) aValue);
108
                break;
109
        }
110
    }
111
 
112
    /**
113
     * Returns the name of the given column.
114
     * @param column column index
115
     * @return column name; if the index is invalid it returns an empty
116
     * string
117
     */
89 luk 118
    @Override
87 luk 119
    public String getColumnName(int column) {
120
        switch (column) {
121
            case 0: return "Task name";
89 luk 122
            case 1: return "Time consumption [h:min]";
93 luk 123
            case 2: return "Total price";
87 luk 124
            default: return "";
125
        }
126
    }
127
 
128
    /**
129
     * Returns the class of the given column.
130
     * @param columnIndex column index
131
     * @return appropriate class object; if the column index is invalid
132
     * it returns <CODE>Void.class</CODE>.
133
     */
89 luk 134
    @Override
87 luk 135
    public Class<?> getColumnClass(int columnIndex) {
136
        switch (columnIndex) {
137
            case 0: return String.class;
89 luk 138
            case 1: return StringBuffer.class;
93 luk 139
            case 2: return StringBuffer.class;
87 luk 140
            default: return Void.class;
141
        }
142
    }
143
 
144
    /**
145
     * Checks whether the given cell is editable.
146
     * @param rowIndex row index
147
     * @param columnIndex column index
148
     * @return <CODE>true</CODE> for the first column (index 0),
149
     * <CODE>false</CODE> otherwise
150
     */
89 luk 151
    @Override
87 luk 152
    public boolean isCellEditable(int rowIndex, int columnIndex) {
153
        return columnIndex == 0;
154
    }
155
 
93 luk 156
    public Task getTask(int index) {
157
        return tasks.get(index);
158
    }
159
 
87 luk 160
    /**
161
     * Creates a new task.
162
     */
163
    public void addNewTask() {
164
        Task t = new Task();
165
        t.setActionListener(this);
166
        tasks.add(t);
167
 
168
        int row = tasks.size()-1;
169
        fireTableRowsInserted(row, row);
170
    }
171
 
172
    /**
173
     * Removes the given tasks.
174
     * @param start start index
175
     * @param end end index (including)
176
     */
177
    public void removeTasks(int start, int end) {
178
        for (int i=end; i>=start; i--) {
179
            Task t = tasks.remove(i);
180
            t.stop();
181
            t.setActionListener(null);
182
        }
183
 
184
        fireTableRowsDeleted(start, end);
185
    }
186
 
187
    /**
188
     * Starts the given tasks.
189
     * @param start start index
190
     * @param end end index (including)
191
     */
192
    public void startTasks(int start, int end) {
193
        for (int i=start; i<=end; i++) {
194
            Task t = tasks.get(i);
195
            t.start();
196
            fireTableCellUpdated(i, 1);
93 luk 197
            fireTableCellUpdated(i, 2);
87 luk 198
        }        
199
    }
200
 
201
    /**
202
     * Stops the given tasks.
203
     * @param start start index
204
     * @param end end index (including)
205
     */
206
    public void stopTasks(int start, int end) {
207
        for (int i=start; i<=end; i++) {
208
            Task t = tasks.get(i);
209
            t.stop();
210
            fireTableCellUpdated(i, 1);
93 luk 211
            fireTableCellUpdated(i, 2);
87 luk 212
        }
213
    }
214
 
215
    /**
216
     * Stops all tasks.
217
     */
218
    public void stopAllTasks() {
219
        Iterator<Task> it = tasks.iterator();
220
        while (it.hasNext()) {
221
            it.next().stop();
222
        }
223
 
224
        fireTableDataChanged();
225
    }
226
 
227
    /**
89 luk 228
     * Resets the given tasks.
229
     * @param start index of the first resetted task
230
     * @param end index of the first NOT resetted task (the first task beyond the interval)
231
     */
232
    public void resetTasks(int start, int end) {
233
        for (int i=start; i<=end; i++) {
234
            Task t = tasks.get(i);
235
            t.setConsumption(0);
236
            fireTableCellUpdated(i, 1);
93 luk 237
            fireTableCellUpdated(i, 2);
89 luk 238
        }
239
    }
240
 
241
    /**
87 luk 242
     * Destroys the timer controlling automatic data saving.
243
     */
244
    public void cancelAutoSave() {
245
        timer.stop();
246
    }
247
 
248
    /**
249
     * Returns the absolute path to the directory where LWTT data should be
250
     * saved.
251
     * @return directory path
252
     */
253
    public static File getDir() {
254
        Properties sys = System.getProperties();
255
        return new File(sys.getProperty("user.home"), ".lwtt");
256
    }
257
 
258
    /**
259
     * Returns the absolute path to the file where LWTT data should be
260
     * saved.
261
     * @return absolute file path
262
     */
263
    public static File getPath() {
264
        return new File(getDir(), "data.xml");
265
    }
266
 
267
    /**
268
     * Checks whether the given task is running.
269
     * @param index task index
270
     * @return <CODE>true</CODE> for running task,
271
     * <CODE>false</CODE> otherwise
272
     */
273
    public boolean isRunning(int index) {
274
        return tasks.get(index).isRunning();
275
    }
276
 
277
    /**
278
     * Loads application's data from the file.
279
     */
280
    public synchronized void loadFromFile() {
281
        tasks.clear();
282
 
283
        File file = getPath();
91 luk 284
        if (!file.exists()) {
285
            Properties props = new Properties();
286
            taskFrame.setStartSettings(props);
87 luk 287
            return;
91 luk 288
        }
87 luk 289
 
290
        try {
291
            FileInputStream is = new FileInputStream(file);
292
            Properties props = new Properties();
293
            props.loadFromXML(is);
294
            is.close();
295
 
89 luk 296
            taskFrame.setStartSettings(props);
297
 
87 luk 298
            Iterator<Object> it = props.keySet().iterator();
299
            while (it.hasNext()) {
300
                String key = (String) it.next();
301
                if (key.endsWith(".name")) {
302
                    String ids = key.substring(0, key.length() - 5);
303
                    String name = props.getProperty(ids + ".name");
304
                    String cons = props.getProperty(ids + ".consumption");
93 luk 305
                    String price = props.getProperty(ids + ".price", "1");
87 luk 306
                    try {
307
                        int id = Integer.parseInt(ids);
308
                        long cn = Long.parseLong(cons);
93 luk 309
                        double pr = Double.parseDouble(price);
310
                        Task t = new Task(id, name, cn, pr);
87 luk 311
                        t.setActionListener(this);
312
                        tasks.add(t);
313
                    } catch (NumberFormatException e) {
314
                        JOptionPane.showMessageDialog(null, "Cannot load data from file (bad format).", "Error", JOptionPane.ERROR_MESSAGE);
315
                    }                    
316
                }
317
            }
318
 
319
            Collections.sort(tasks);
320
 
321
            fireTableDataChanged();
322
 
323
        } catch (Exception e) {
324
            e.printStackTrace();
325
        }
326
    }
327
 
328
    /**
329
     * Saves application's data to the file.
330
     */
331
    public synchronized void saveToFile() {
332
        File dir = getDir();
333
        if (!dir.exists()) {
334
            if (!dir.mkdir()) {
335
                JOptionPane.showMessageDialog(null, "Cannot save data to file (cannot create data directory).", "Error", JOptionPane.ERROR_MESSAGE);
336
                return;
337
            }
338
        }
339
 
340
        Properties props = new Properties();
89 luk 341
        props.setProperty("window.location.x", Integer.toString(taskFrame.getX()));
342
        props.setProperty("window.location.y", Integer.toString(taskFrame.getY()));
343
        props.setProperty("window.size.w", Integer.toString(taskFrame.getWidth()));
344
        props.setProperty("window.size.h", Integer.toString(taskFrame.getHeight()));
87 luk 345
        for (int i=0; i<tasks.size(); i++) {
346
            Task t = tasks.get(i);
347
            String id = Integer.toString(t.getId());
348
            props.setProperty(id + ".name", t.getName());
349
            props.setProperty(id + ".consumption", Long.toString(t.getConsumption()));
93 luk 350
            props.setProperty(id + ".price", Double.toString(t.getPrice()));
87 luk 351
        }
352
 
353
        try {
354
            FileOutputStream os = new FileOutputStream(getPath());
355
            props.storeToXML(os, "LWTT task data");
356
            os.close();
357
        } catch (IOException e) {
358
            JOptionPane.showMessageDialog(null, "Cannot save data to file (" + e.getLocalizedMessage() + ").", "Error", JOptionPane.ERROR_MESSAGE);
359
        }
360
    }
361
 
362
    /**
363
     * Processes an action event.
364
     *
365
     * If the event has been generated by the auto-save timer it saves
366
     * the data. Otherwise (a button action occurred) it updates
367
     * the appropriate table cell.
368
     * @param e action event
369
     */
370
    public void actionPerformed(ActionEvent e) {
371
        Object src = e.getSource();
372
        if (src == timer) {
373
            saveToFile();
374
        }
375
        else {
376
            int row = tasks.indexOf(src);
377
            fireTableCellUpdated(row, 1);
93 luk 378
            fireTableCellUpdated(row, 2);
87 luk 379
        }
380
    }
381
 
382
}