Subversion Repositories public

Rev

Rev 87 | Rev 91 | Go to most recent revision | 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}");
44
 
45
    private TaskFrame taskFrame = null;
46
 
87 luk 47
    /**
48
     * Creates a new instance of TaskTableModel
89 luk 49
     * @param tf task frame instance
87 luk 50
     */
89 luk 51
    public TaskTableModel(TaskFrame tf) {
52
        taskFrame = tf;
87 luk 53
        loadFromFile();
54
        timer.start();
55
    }
56
 
57
    /**
58
     * Returns the value at the given coordinates.
59
     * @param rowIndex row index
60
     * @param columnIndex column index
61
     * @return appropriate cell value; if the arguments are invalid
62
     * it returns <CODE>null</CODE>
63
     */
64
    public Object getValueAt(int rowIndex, int columnIndex) {
65
        switch (columnIndex) {
89 luk 66
            case 0:
67
                return tasks.get(rowIndex).getName();
68
            case 1:
69
                long mins = tasks.get(rowIndex).getConsumption() / 60000;
70
                BigDecimal hm[] = new BigDecimal((int) mins).divideAndRemainder(new BigDecimal(60));
71
                return timeFormat.format(hm);
87 luk 72
            default: return null;
73
        }
74
    }
75
 
76
    /**
77
     * Returns the row count.
78
     * @return row count
79
     */
80
    public int getRowCount() {
81
        return tasks.size();
82
    }
83
 
84
    /**
85
     * Returns the column count (currently 2).
86
     * @return column count
87
     */
88
    public int getColumnCount() {
89
        return 2;
90
    }
91
 
92
    /**
93
     * Sets a new value of the given cell. If at least one of the
94
     * coordinates is invalid it does nothing.
95
     * @param aValue new value
96
     * @param rowIndex row index
97
     * @param columnIndex column index
98
     */
89 luk 99
    @Override
87 luk 100
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
101
        switch (columnIndex) {
102
            case 0: tasks.get(rowIndex).setName((String) aValue);
103
                break;
104
        }
105
    }
106
 
107
    /**
108
     * Returns the name of the given column.
109
     * @param column column index
110
     * @return column name; if the index is invalid it returns an empty
111
     * string
112
     */
89 luk 113
    @Override
87 luk 114
    public String getColumnName(int column) {
115
        switch (column) {
116
            case 0: return "Task name";
89 luk 117
            case 1: return "Time consumption [h:min]";
87 luk 118
            default: return "";
119
        }
120
    }
121
 
122
    /**
123
     * Returns the class of the given column.
124
     * @param columnIndex column index
125
     * @return appropriate class object; if the column index is invalid
126
     * it returns <CODE>Void.class</CODE>.
127
     */
89 luk 128
    @Override
87 luk 129
    public Class<?> getColumnClass(int columnIndex) {
130
        switch (columnIndex) {
131
            case 0: return String.class;
89 luk 132
            case 1: return StringBuffer.class;
87 luk 133
            default: return Void.class;
134
        }
135
    }
136
 
137
    /**
138
     * Checks whether the given cell is editable.
139
     * @param rowIndex row index
140
     * @param columnIndex column index
141
     * @return <CODE>true</CODE> for the first column (index 0),
142
     * <CODE>false</CODE> otherwise
143
     */
89 luk 144
    @Override
87 luk 145
    public boolean isCellEditable(int rowIndex, int columnIndex) {
146
        return columnIndex == 0;
147
    }
148
 
149
    /**
150
     * Creates a new task.
151
     */
152
    public void addNewTask() {
153
        Task t = new Task();
154
        t.setActionListener(this);
155
        tasks.add(t);
156
 
157
        int row = tasks.size()-1;
158
        fireTableRowsInserted(row, row);
159
    }
160
 
161
    /**
162
     * Removes the given tasks.
163
     * @param start start index
164
     * @param end end index (including)
165
     */
166
    public void removeTasks(int start, int end) {
167
        for (int i=end; i>=start; i--) {
168
            Task t = tasks.remove(i);
169
            t.stop();
170
            t.setActionListener(null);
171
        }
172
 
173
        fireTableRowsDeleted(start, end);
174
    }
175
 
176
    /**
177
     * Starts the given tasks.
178
     * @param start start index
179
     * @param end end index (including)
180
     */
181
    public void startTasks(int start, int end) {
182
        for (int i=start; i<=end; i++) {
183
            Task t = tasks.get(i);
184
            t.start();
185
            fireTableCellUpdated(i, 1);
186
        }        
187
    }
188
 
189
    /**
190
     * Stops the given tasks.
191
     * @param start start index
192
     * @param end end index (including)
193
     */
194
    public void stopTasks(int start, int end) {
195
        for (int i=start; i<=end; i++) {
196
            Task t = tasks.get(i);
197
            t.stop();
198
            fireTableCellUpdated(i, 1);
199
        }
200
    }
201
 
202
    /**
203
     * Stops all tasks.
204
     */
205
    public void stopAllTasks() {
206
        Iterator<Task> it = tasks.iterator();
207
        while (it.hasNext()) {
208
            it.next().stop();
209
        }
210
 
211
        fireTableDataChanged();
212
    }
213
 
214
    /**
89 luk 215
     * Resets the given tasks.
216
     * @param start index of the first resetted task
217
     * @param end index of the first NOT resetted task (the first task beyond the interval)
218
     */
219
    public void resetTasks(int start, int end) {
220
        for (int i=start; i<=end; i++) {
221
            Task t = tasks.get(i);
222
            t.setConsumption(0);
223
            fireTableCellUpdated(i, 1);
224
        }
225
    }
226
 
227
    /**
87 luk 228
     * Destroys the timer controlling automatic data saving.
229
     */
230
    public void cancelAutoSave() {
231
        timer.stop();
232
    }
233
 
234
    /**
235
     * Returns the absolute path to the directory where LWTT data should be
236
     * saved.
237
     * @return directory path
238
     */
239
    public static File getDir() {
240
        Properties sys = System.getProperties();
241
        return new File(sys.getProperty("user.home"), ".lwtt");
242
    }
243
 
244
    /**
245
     * Returns the absolute path to the file where LWTT data should be
246
     * saved.
247
     * @return absolute file path
248
     */
249
    public static File getPath() {
250
        return new File(getDir(), "data.xml");
251
    }
252
 
253
    /**
254
     * Checks whether the given task is running.
255
     * @param index task index
256
     * @return <CODE>true</CODE> for running task,
257
     * <CODE>false</CODE> otherwise
258
     */
259
    public boolean isRunning(int index) {
260
        return tasks.get(index).isRunning();
261
    }
262
 
263
    /**
264
     * Loads application's data from the file.
265
     */
266
    public synchronized void loadFromFile() {
267
        tasks.clear();
268
 
269
        File file = getPath();
270
        if (!file.exists())
271
            return;
272
 
273
        try {
274
            FileInputStream is = new FileInputStream(file);
275
            Properties props = new Properties();
276
            props.loadFromXML(is);
277
            is.close();
278
 
89 luk 279
            taskFrame.setStartSettings(props);
280
 
87 luk 281
            Iterator<Object> it = props.keySet().iterator();
282
            while (it.hasNext()) {
283
                String key = (String) it.next();
284
                if (key.endsWith(".name")) {
285
                    String ids = key.substring(0, key.length() - 5);
286
                    String name = props.getProperty(ids + ".name");
287
                    String cons = props.getProperty(ids + ".consumption");
288
                    try {
289
                        int id = Integer.parseInt(ids);
290
                        long cn = Long.parseLong(cons);
291
                        Task t = new Task(id, name, cn);
292
                        t.setActionListener(this);
293
                        tasks.add(t);
294
                    } catch (NumberFormatException e) {
295
                        JOptionPane.showMessageDialog(null, "Cannot load data from file (bad format).", "Error", JOptionPane.ERROR_MESSAGE);
296
                    }                    
297
                }
298
            }
299
 
300
            Collections.sort(tasks);
301
 
302
            fireTableDataChanged();
303
 
304
        } catch (Exception e) {
305
            e.printStackTrace();
306
        }
307
    }
308
 
309
    /**
310
     * Saves application's data to the file.
311
     */
312
    public synchronized void saveToFile() {
313
        File dir = getDir();
314
        if (!dir.exists()) {
315
            if (!dir.mkdir()) {
316
                JOptionPane.showMessageDialog(null, "Cannot save data to file (cannot create data directory).", "Error", JOptionPane.ERROR_MESSAGE);
317
                return;
318
            }
319
        }
320
 
321
        Properties props = new Properties();
89 luk 322
        props.setProperty("window.location.x", Integer.toString(taskFrame.getX()));
323
        props.setProperty("window.location.y", Integer.toString(taskFrame.getY()));
324
        props.setProperty("window.size.w", Integer.toString(taskFrame.getWidth()));
325
        props.setProperty("window.size.h", Integer.toString(taskFrame.getHeight()));
87 luk 326
        for (int i=0; i<tasks.size(); i++) {
327
            Task t = tasks.get(i);
328
            String id = Integer.toString(t.getId());
329
            props.setProperty(id + ".name", t.getName());
330
            props.setProperty(id + ".consumption", Long.toString(t.getConsumption()));
331
        }
332
 
333
        try {
334
            FileOutputStream os = new FileOutputStream(getPath());
335
            props.storeToXML(os, "LWTT task data");
336
            os.close();
337
        } catch (IOException e) {
338
            JOptionPane.showMessageDialog(null, "Cannot save data to file (" + e.getLocalizedMessage() + ").", "Error", JOptionPane.ERROR_MESSAGE);
339
        }
340
    }
341
 
342
    /**
343
     * Processes an action event.
344
     *
345
     * If the event has been generated by the auto-save timer it saves
346
     * the data. Otherwise (a button action occurred) it updates
347
     * the appropriate table cell.
348
     * @param e action event
349
     */
350
    public void actionPerformed(ActionEvent e) {
351
        Object src = e.getSource();
352
        if (src == timer) {
353
            saveToFile();
354
        }
355
        else {
356
            int row = tasks.indexOf(src);
357
            fireTableCellUpdated(row, 1);
358
        }
359
    }
360
 
361
}