OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

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

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.task;
15
 
16
import org.openconcerto.sql.Configuration;
17
import org.openconcerto.sql.model.DBSystemRoot;
18
import org.openconcerto.sql.model.SQLField;
19
import org.openconcerto.sql.model.SQLRow;
20
import org.openconcerto.sql.model.SQLRowListRSH;
21
import org.openconcerto.sql.model.SQLRowValues;
22
import org.openconcerto.sql.model.SQLSelect;
23
import org.openconcerto.sql.model.SQLTable;
24
import org.openconcerto.sql.model.Where;
25
import org.openconcerto.sql.users.User;
26
import org.openconcerto.sql.users.UserManager;
27
import org.openconcerto.sql.users.rights.UserRightsManager;
28
import org.openconcerto.task.config.ComptaBasePropsConfiguration;
29
import org.openconcerto.utils.cc.IFactory;
30
 
31
import java.sql.SQLException;
32
import java.sql.Timestamp;
144 ilm 33
import java.util.ArrayList;
17 ilm 34
import java.util.Calendar;
35
import java.util.HashSet;
36
import java.util.LinkedHashMap;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Set;
40
import java.util.Vector;
41
 
42
import javax.swing.JOptionPane;
43
import javax.swing.JTable;
44
import javax.swing.SwingUtilities;
45
import javax.swing.SwingWorker;
144 ilm 46
import javax.swing.table.AbstractTableModel;
17 ilm 47
 
144 ilm 48
public class TodoListModel extends AbstractTableModel {
17 ilm 49
 
50
    public static final int EXTENDED_MODE = 1;
51
    public static final int SIMPLE_MODE = 2;
52
    public int mode = SIMPLE_MODE;
53
    private static final int MIN_DELAY = 30;// * 1000; // en secondes
54
    private static final int MAX_DELAY = 6;// 120 * 1000;
55
    private long currentDelay = MIN_DELAY;
56
    private boolean stop = false;
57
    private final List<Integer> listIdListener = new Vector<Integer>(); // Contient des Integer, id
58
    // que l'on ecoute
59
    private JTable table = null;
60
    private List<ModelStateListener> stateListenerList = new Vector<ModelStateListener>(1);
144 ilm 61
    private final UserManager uMngr;
17 ilm 62
    protected List<UserTaskRight> rights;
63
    private boolean historyVisible = false;
144 ilm 64
    private List<TodoListElement> elements = new ArrayList<TodoListElement>();
17 ilm 65
 
144 ilm 66
    TodoListModel(final UserManager uMngr) {
67
        this.uMngr = uMngr;
17 ilm 68
        launchUpdaterThread();
69
        this.mode = SIMPLE_MODE;
70
    }
71
 
72
    private void launchUpdaterThread() {
73
        final Thread thread = new Thread(new Runnable() {
74
 
75
            public void run() {
76
                // Remplissage périodique
77
                while (!TodoListModel.this.stop) {
78
                    try {
79
                        Thread.sleep(TodoListModel.this.currentDelay * 1000);
80
                        if (!TodoListModel.this.stop) {
81
                            synchronousFill();
82
                        }
83
                    } catch (Exception e) {
84
                        e.printStackTrace();
85
                    }
86
                }
87
            }
88
        });
89
        // this only read data to be displayed, it can be safely interrupted at any moment
90
        thread.setDaemon(true);
91
        thread.setName("TodoListModel UpdaterThread");
92
        thread.start();
93
    }
94
 
95
    public void asynchronousFill() {
96
        final Thread thread = new Thread(new Runnable() {
73 ilm 97
            @Override
17 ilm 98
            public void run() {
99
                synchronousFill();
100
            }
101
        });
102
        thread.setName("TodoListModel asynchronousFill");
103
        thread.start();
104
    }
105
 
106
    /**
107
     *
108
     */
109
    private synchronized void synchronousFill() {
110
        if (this.table == null)
111
            return;
112
        SwingUtilities.invokeLater(new Runnable() {
113
            public void run() {
114
                fireModelStateChanged(ModelStateListener.STATE_RELOADING);
115
            }
116
        });
73 ilm 117
 
17 ilm 118
        final Map<Integer, TodoListElement> newDataVector = new LinkedHashMap<Integer, TodoListElement>();
119
        try {
120
            fillFromDatabase(newDataVector);
121
 
122
        } catch (Exception e) {
123
            e.printStackTrace();
124
            SwingUtilities.invokeLater(new Runnable() {
125
                public void run() {
126
                    fireModelStateChanged(ModelStateListener.STATE_DEAD);
127
                }
128
            });
129
            return;
130
        }
131
 
132
        final Vector<Integer> rowsModified = new Vector<Integer>();
133
        final Vector<TodoListElement> rowsDeleted = new Vector<TodoListElement>();
134
        // size before removing
135
        final int newSize = newDataVector.size();
136
        final int oldSize;
144 ilm 137
        synchronized (this.elements) {
138
            oldSize = this.elements.size();
67 ilm 139
            for (int i = 0; i < oldSize; i++) {
144 ilm 140
                final TodoListElement elt = this.elements.get(i);
73 ilm 141
                final TodoListElement eltN = newDataVector.remove(elt.getRowValues().getID());
17 ilm 142
                if (eltN == null) {
143
                    rowsDeleted.add(elt);
144
                } else {
145
                    if (!eltN.equals(elt)) {
146
                        rowsModified.add(i);
147
                        elt.reloadValues(eltN.getRowValues());
148
                    }
149
                }
150
            }
151
 
152
            for (TodoListElement elt : rowsDeleted) {
144 ilm 153
                int index = this.elements.indexOf(elt);
17 ilm 154
                if (index >= 0) {
156 ilm 155
                    elements.remove(index);
17 ilm 156
                }
157
            }
158
 
159
            for (Integer i : newDataVector.keySet()) {
144 ilm 160
                this.elements.add(newDataVector.get(i));
17 ilm 161
            }
162
        }
163
        SwingUtilities.invokeLater(new Runnable() {
164
            public void run() {
144 ilm 165
                if ((rowsModified.size() == newSize) && !rowsModified.isEmpty()) {
17 ilm 166
                    fireTableDataChanged();
167
                    fireModelStateChanged(ModelStateListener.CONTENT_MODIFIED);
168
                } else if (newSize != oldSize) {
169
                    fireTableDataChanged();
170
                    fireModelStateChanged(ModelStateListener.CONTENT_MODIFIED);
171
                } else {
172
                    for (int i = 0; i < rowsModified.size(); i++) {
173
                        Integer indexModified = rowsModified.get(i);
174
                        fireTableRowsUpdated(indexModified, indexModified);
175
                    }
144 ilm 176
                    if (!rowsModified.isEmpty()) {
17 ilm 177
                        fireModelStateChanged(ModelStateListener.CONTENT_MODIFIED);
178
                    }
179
                }
180
                fireModelStateChanged(ModelStateListener.STATE_OK);
181
            }
182
        });
183
 
184
    }
185
 
186
    private final Where getAuthorizedTaskTypes(final int userID, final SQLTable tableTache) {
187
        final SQLField typeF = tableTache.getFieldRaw("TYPE");
188
        if (typeF == null)
189
            return null;
190
 
191
        final Set<String> types = UserRightsManager.getInstance().getObjects(userID, "TASK", new IFactory<Set<String>>() {
192
            @SuppressWarnings("unchecked")
193
            @Override
194
            public Set<String> createChecked() {
144 ilm 195
                final SQLSelect sel = new SQLSelect();
17 ilm 196
                sel.addSelect(typeF);
197
                sel.addGroupBy(typeF);
198
                return new HashSet<String>(tableTache.getDBSystemRoot().getDataSource().executeCol(sel.asString()));
199
            }
200
        });
201
        return types == null ? Where.TRUE : new Where(typeF, types);
202
    }
203
 
204
    private static final int societeID = ((ComptaBasePropsConfiguration) Configuration.getInstance()).getSocieteID();
205
    private static final DBSystemRoot base = Configuration.getInstance().getSystemRoot();
206
    private static final SQLTable tableTache = base.getRoot("Common").getTable("TACHE_COMMON");
144 ilm 207
    private static final Where where2 = new Where(tableTache.getField("ID_SOCIETE_COMMON"), "=", tableTache.getUndefinedID()).or(new Where(tableTache.getField("ID_SOCIETE_COMMON"), "=", societeID));
17 ilm 208
 
209
    private synchronized void fillFromDatabase(final Map<Integer, TodoListElement> m) {
210
        long time1 = System.currentTimeMillis();
211
 
144 ilm 212
        final SQLSelect select = new SQLSelect();
17 ilm 213
        select.addSelectStar(tableTache);
214
        Where where = new Where(tableTache.getField("ID_USER_COMMON_TO"), this.listIdListener);
144 ilm 215
        final int userID = getCurrentUser().getId();
17 ilm 216
        where = where.or(new Where(tableTache.getField("ID_USER_COMMON_ASSIGN_BY"), "=", userID));
217
 
218
        where = where.or(getAuthorizedTaskTypes(userID, tableTache));
219
 
220
        if (!isHistoryVisible()) {
221
            Where w3 = new Where(tableTache.getField("FAIT"), "=", Boolean.FALSE);
222
            Calendar cal = Calendar.getInstance();
180 ilm 223
            // Voir les taches qui ont été faite les 15 dernières secondes
224
            cal.add(Calendar.SECOND, -15);
17 ilm 225
            Where w4 = new Where(tableTache.getField("DATE_FAIT"), "<>", (Object) null);
226
            w4 = w4.and(new Where(tableTache.getField("DATE_FAIT"), ">", cal.getTime()));
227
            w3 = w3.or(w4);
228
            where = where.and(w3);
229
        }
230
        select.setWhere(where.and(where2));
231
        select.addFieldOrder(tableTache.getField("ID_USER_COMMON_TO"));
232
        select.addFieldOrder(tableTache.getField("DATE_EXP"));
233
 
234
        this.rights = UserTaskRight.getUserTaskRight(getCurrentUser());
235
        // don't use the cache since by definition this table is shared by everyone, so we can't
236
        // rely on our modifications
144 ilm 237
        final List<SQLRow> l = SQLRowListRSH.execute(select, false, false);
17 ilm 238
        for (SQLRow row : l) {
144 ilm 239
            final TodoListElement t = new TodoListElement(getUserManager(), row.asRowValues());
17 ilm 240
            // add tasks that we created, we must do, or that we can read
241
            // plus for preventec, tasks with a type must visible to everybody
242
            boolean add = false;
243
            String type = row.getString("TYPE");
244
            if (type != null && type.trim().length() > 0) {
245
                add = true;
246
            } else if (row.getInt("ID_USER_COMMON_CREATE") == userID || row.getInt("ID_USER_COMMON_TO") == userID) {
247
                add = true;
248
            } else {
249
                for (int i = 0; i < TodoListModel.this.rights.size(); i++) {
144 ilm 250
                    final UserTaskRight element = TodoListModel.this.rights.get(i);
17 ilm 251
                    if (element.getIdToUser() == row.getInt("ID_USER_COMMON_TO") && element.canRead()) {
252
                        add = true;
253
                        break;
254
                    }
255
                }
256
            }
257
            if (add)
258
                m.put(row.getID(), t);
259
        }
260
 
261
        long time2 = System.currentTimeMillis();
262
        final long t = time2 - time1;
263
        // System.err.println("Time to fill from DB : " + t);
264
        long delay = 2 + t / 1000;
265
        if (delay > MAX_DELAY)
266
            delay = MAX_DELAY;
267
        if (delay < MIN_DELAY)
268
            delay = MIN_DELAY;
269
        this.currentDelay = delay;
270
    }
271
 
272
    public int getColumnCount() {
273
        if (this.mode == EXTENDED_MODE)
274
            return 7;
275
        return 5;
276
    }
277
 
144 ilm 278
    @Override
17 ilm 279
    public boolean isCellEditable(int rowIndex, int columnIndex) {
144 ilm 280
        synchronized (this.elements) {
17 ilm 281
            // Modifier la priorité de la tache
282
            if (columnIndex == 1) {
283
                return true;
284
            }
285
            if (this.mode == EXTENDED_MODE && columnIndex == 3) {
286
                // Impossible de modifier la date de creation
287
                return false;
288
            }
289
 
144 ilm 290
            if (this.elements.size() <= rowIndex) {
291
                System.err.println("Size error :" + this.elements.size() + " i:" + rowIndex);
17 ilm 292
                rowIndex = 0;
293
            }
144 ilm 294
            final TodoListElement task = this.elements.get(rowIndex);
17 ilm 295
            if (task == null)
296
                return false;
73 ilm 297
            final int size = this.rights.size();
17 ilm 298
            if (columnIndex == 0)
299
                // Validation
73 ilm 300
                for (int i = 0; i < size; i++) {
156 ilm 301
                    UserTaskRight right = this.rights.get(i);
302
                    if (right.getIdToUser() == task.getUserId() && right.canValidate()) {
303
                        return true;
304
                    }
17 ilm 305
                }
306
            else if (columnIndex == this.getColumnCount() - 1) {
307
                // Colonne d'assignement
144 ilm 308
                return (task.getCreatorId().equals(getCurrentUser().getId()));
17 ilm 309
            } else {
310
                // Modification
73 ilm 311
                for (int i = 0; i < size; i++) {
17 ilm 312
                    UserTaskRight right = this.rights.get(i);
313
                    // i.e. we can still modify tasks we created and assigned to another user, but
314
                    // we cannot change tasks assigned to us
315
                    if (right.getIdToUser() == task.getCreatorId() && right.canModify()) {
316
                        return true;
317
                    }
318
                }
319
            }
320
        }
321
        return false;
322
    }
323
 
144 ilm 324
    @Override
17 ilm 325
    public Class<?> getColumnClass(final int columnIndex) {
326
        switch (columnIndex) {
327
        case 0:
328
            return Boolean.class;
329
        case 1:
330
            return Integer.class;
331
        case 2:
332
            return String.class;
333
        case 3:
334
            return Timestamp.class;
335
        case 4:
144 ilm 336
            if (this.mode == EXTENDED_MODE) {
337
                return Timestamp.class;
17 ilm 338
            }
144 ilm 339
            return Integer.class;
17 ilm 340
        case 5:
341
            return Timestamp.class;
342
        case 6:
343
            return Integer.class;
344
        default:
345
            return String.class;
346
        }
347
    }
348
 
349
    public Object getValueAt(int rowIndex, int columnIndex) {
144 ilm 350
        synchronized (this.elements) {
351
            if (this.elements.size() <= rowIndex) {
352
                System.err.println("Size error :" + this.elements.size() + " i:" + rowIndex);
17 ilm 353
                rowIndex = 0;
354
            }
144 ilm 355
            final TodoListElement task = this.elements.get(rowIndex);
17 ilm 356
            switch (columnIndex) {
357
            case 0:
358
                return task.isDone();
359
            case 1:
360
                return task.getPriority();
361
            case 2:
362
                return task.getName();
363
            case 3:
364
                if (this.mode == EXTENDED_MODE) {
365
                    return task.getDate();
366
                }
367
                return task.getExpectedDate();
368
            case 4:
369
                if (this.mode == EXTENDED_MODE) {
370
                    return task.getDoneDate();
371
                }
372
                return task.getUserId();
373
            case 5:
374
                return task.getExpectedDate();
375
            case 6:
376
                return task.getUserId();
377
            default:
378
                return "????????";
379
            }
380
        }
381
    }
382
 
383
    public TodoListElement getTaskAtRow(int rowIndex) {
144 ilm 384
        return this.elements.get(rowIndex);
17 ilm 385
    }
386
 
144 ilm 387
    @Override
388
    public int getRowCount() {
389
        return this.elements.size();
390
    }
391
 
392
    public void removeRow(int row) {
393
        elements.remove(row);
394
        fireTableRowsDeleted(row, row);
395
    }
396
 
180 ilm 397
    public boolean isAutoRefreshing() {
398
        return !this.stop;
399
    }
400
 
401
    public void enableUpdate() {
402
        if (this.stop == true) {
403
            this.stop = false;
404
            launchUpdaterThread();
405
        }
406
    }
407
 
144 ilm 408
    @Override
17 ilm 409
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
144 ilm 410
        synchronized (this.elements) {
17 ilm 411
            if (rowIndex >= getRowCount()) {
412
                // Cas de la perte de l'edition de la derniere ligne supprimee
413
                return;
414
            }
144 ilm 415
            final TodoListElement task = this.elements.get(rowIndex);
17 ilm 416
            switch (columnIndex) {
417
            case 0:
418
                task.setDone((Boolean) aValue);
419
                break;
420
            case 1:
421
                task.setPriority((Integer) aValue);
422
                break;
423
            case 2:
424
                task.setName((String) aValue);
425
                break;
426
            case 3:
427
                if (this.mode == EXTENDED_MODE) {
428
                    task.setDate((Timestamp) aValue);
429
                }
430
                task.setExpectedDate((Timestamp) aValue);
431
                break;
432
            case 4:
433
                if (this.mode == EXTENDED_MODE) {
434
                    task.setDoneDate((Timestamp) aValue);
435
                    break;
436
                }
437
                task.setUserId((Integer) aValue);
438
                break;
439
            case 5:
440
                task.setExpectedDate((Timestamp) aValue);
441
                break;
442
            case 6:
443
                task.setUserId((Integer) aValue);
444
                break;
445
            default:
446
                break;
447
            }
448
            task.commitChanges();
449
        }
450
        fireTableRowsUpdated(rowIndex, rowIndex);
451
    }
452
 
144 ilm 453
    @Override
17 ilm 454
    public String getColumnName(int columnIndex) {
455
        switch (columnIndex) {
456
        case 0:
457
            return "";
458
        case 1:
459
            return "";
460
        case 2:
73 ilm 461
            return TM.tr("taskToDo");
17 ilm 462
        case 3:
463
            if (this.mode == EXTENDED_MODE) {
73 ilm 464
                return TM.tr("created");
17 ilm 465
            }
73 ilm 466
            return TM.tr("todoBefore.col");
17 ilm 467
        case 4:
468
            if (this.mode == EXTENDED_MODE) {
73 ilm 469
                return TM.tr("completed");
17 ilm 470
            }
73 ilm 471
            return TM.tr("assignedTo");
17 ilm 472
        case 5:
73 ilm 473
            return TM.tr("todoBefore.col");
17 ilm 474
        case 6:
73 ilm 475
            return TM.tr("assignedTo");
17 ilm 476
        default:
73 ilm 477
            return "?????";
17 ilm 478
 
479
        }
480
    }
481
 
482
    /**
483
     * Ajoute une nouvelle Tâche de manière asynchrone
484
     */
485
    public void addNewTask() {
486
        final SwingWorker<?, ?> worker = new SwingWorker<Object, Object>() {
487
 
488
            @Override
489
            public Object doInBackground() {
144 ilm 490
                final SQLRowValues rowV = new SQLRowValues(tableTache);
73 ilm 491
                final Calendar cal = Calendar.getInstance();
17 ilm 492
                rowV.put("DATE_ENTREE", new java.sql.Timestamp(cal.getTimeInMillis()));
493
                cal.add(Calendar.HOUR_OF_DAY, 1);
494
                rowV.put("DATE_EXP", new java.sql.Timestamp(cal.getTimeInMillis()));
495
                cal.set(Calendar.YEAR, 2000);
496
                cal.set(Calendar.DAY_OF_YEAR, 1);
497
                cal.set(Calendar.HOUR_OF_DAY, 0);
498
                cal.set(Calendar.MINUTE, 0);
499
                cal.set(Calendar.MILLISECOND, 0);
500
                rowV.put("DATE_FAIT", new java.sql.Timestamp(cal.getTimeInMillis()));
144 ilm 501
                final int currentUserId = getCurrentUser().getId();
17 ilm 502
                rowV.put("ID_USER_COMMON_ASSIGN_BY", currentUserId);
503
                rowV.put("ID_USER_COMMON_TO", currentUserId);
504
                try {
505
                    rowV.insert();
506
                } catch (SQLException e) {
507
                    fireModelStateChanged(ModelStateListener.STATE_DEAD);
508
                    e.printStackTrace();
509
                }
510
                return null;
511
            }
512
 
513
            @Override
514
            public void done() {
515
                // synchrone pour que le fire fonctionne bien
516
                synchronousFill();
517
                fireTableRowsInserted(getRowCount(), getRowCount());
518
            }
519
 
520
        };
521
        worker.execute();
522
 
523
    }
524
 
525
    synchronized void setMode(int mode) {
526
        this.mode = mode;
527
        fireTableStructureChanged();
528
    }
529
 
530
    public synchronized int getMode() {
531
        return this.mode;
532
    }
533
 
534
    public boolean deleteTaskAtIndex(int index) {
144 ilm 535
        synchronized (this.elements) {
536
            final TodoListElement t = this.elements.get(index);
537
            final int currentUserId = getCurrentUser().getId();
17 ilm 538
            if (t.getCreatorId() != currentUserId) {
73 ilm 539
                JOptionPane.showMessageDialog(this.table, TM.tr("deleteForbidden"));
17 ilm 540
                return false;
541
            }
542
            t.archive();
543
        }
544
        removeRow(index);
545
        return true;
546
    }
547
 
548
    public void addIdListener(Integer id) {
549
        this.listIdListener.add(id);
550
        asynchronousFill();
551
    }
552
 
553
    public void addIdListenerSilently(Integer id) {
554
        this.listIdListener.add(id);
555
    }
556
 
557
    public void removeIdListener(Integer id) {
558
        this.listIdListener.remove(id);
559
        asynchronousFill();
560
    }
561
 
562
    public boolean listenToId(Integer id) {
563
        return this.listIdListener.contains(id);
564
    }
565
 
566
    public void setTable(JTable t) {
567
        this.table = t;
568
    }
569
 
570
    public void stopUpdate() {
571
        this.stop = true;
572
    }
573
 
574
    public void addModelStateListener(ModelStateListener l) {
575
        if (!this.stateListenerList.contains(l)) {
576
            this.stateListenerList.add(l);
577
        }
578
    }
579
 
580
    public void removeModelStateListener(ModelStateListener l) {
581
        if (this.stateListenerList.contains(l)) {
582
            this.stateListenerList.remove(l);
583
        }
584
    }
585
 
586
    private void fireModelStateChanged(int state) {
73 ilm 587
        final int size = this.stateListenerList.size();
588
        for (int i = 0; i < size; i++) {
17 ilm 589
            this.stateListenerList.get(i).stateChanged(state);
590
        }
591
    }
592
 
144 ilm 593
    public final UserManager getUserManager() {
594
        return this.uMngr;
17 ilm 595
    }
596
 
144 ilm 597
    public final User getCurrentUser() {
598
        return this.getUserManager().getCurrentUser();
599
    }
600
 
17 ilm 601
    public synchronized boolean isHistoryVisible() {
602
        return this.historyVisible;
603
    }
604
 
605
    public synchronized void setHistoryVisible(boolean historyVisible) {
606
        this.historyVisible = historyVisible;
607
    }
144 ilm 608
 
17 ilm 609
}