Dépôt officiel du code source de l'ERP OpenConcerto
Rev 144 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.task;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.users.User;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.task.config.ComptaBasePropsConfiguration;
import org.openconcerto.utils.cc.IFactory;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
public class TodoListModel extends AbstractTableModel {
public static final int EXTENDED_MODE = 1;
public static final int SIMPLE_MODE = 2;
public int mode = SIMPLE_MODE;
private static final int MIN_DELAY = 30;// * 1000; // en secondes
private static final int MAX_DELAY = 6;// 120 * 1000;
private long currentDelay = MIN_DELAY;
private boolean stop = false;
private final List<Integer> listIdListener = new Vector<Integer>(); // Contient des Integer, id
// que l'on ecoute
private JTable table = null;
private List<ModelStateListener> stateListenerList = new Vector<ModelStateListener>(1);
private final UserManager uMngr;
protected List<UserTaskRight> rights;
private boolean historyVisible = false;
private List<TodoListElement> elements = new ArrayList<TodoListElement>();
TodoListModel(final UserManager uMngr) {
this.uMngr = uMngr;
launchUpdaterThread();
this.mode = SIMPLE_MODE;
}
private void launchUpdaterThread() {
final Thread thread = new Thread(new Runnable() {
public void run() {
// Remplissage périodique
while (!TodoListModel.this.stop) {
try {
Thread.sleep(TodoListModel.this.currentDelay * 1000);
if (!TodoListModel.this.stop) {
synchronousFill();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
// this only read data to be displayed, it can be safely interrupted at any moment
thread.setDaemon(true);
thread.setName("TodoListModel UpdaterThread");
thread.start();
}
public void asynchronousFill() {
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronousFill();
}
});
thread.setName("TodoListModel asynchronousFill");
thread.start();
}
/**
*
*/
private synchronized void synchronousFill() {
if (this.table == null)
return;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fireModelStateChanged(ModelStateListener.STATE_RELOADING);
}
});
final Map<Integer, TodoListElement> newDataVector = new LinkedHashMap<Integer, TodoListElement>();
try {
fillFromDatabase(newDataVector);
} catch (Exception e) {
e.printStackTrace();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fireModelStateChanged(ModelStateListener.STATE_DEAD);
}
});
return;
}
final Vector<Integer> rowsModified = new Vector<Integer>();
final Vector<TodoListElement> rowsDeleted = new Vector<TodoListElement>();
// size before removing
final int newSize = newDataVector.size();
final int oldSize;
synchronized (this.elements) {
oldSize = this.elements.size();
for (int i = 0; i < oldSize; i++) {
final TodoListElement elt = this.elements.get(i);
final TodoListElement eltN = newDataVector.remove(elt.getRowValues().getID());
if (eltN == null) {
rowsDeleted.add(elt);
} else {
if (!eltN.equals(elt)) {
rowsModified.add(i);
elt.reloadValues(eltN.getRowValues());
}
}
}
for (TodoListElement elt : rowsDeleted) {
int index = this.elements.indexOf(elt);
if (index >= 0) {
elements.remove(index);
}
}
for (Integer i : newDataVector.keySet()) {
this.elements.add(newDataVector.get(i));
}
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if ((rowsModified.size() == newSize) && !rowsModified.isEmpty()) {
fireTableDataChanged();
fireModelStateChanged(ModelStateListener.CONTENT_MODIFIED);
} else if (newSize != oldSize) {
fireTableDataChanged();
fireModelStateChanged(ModelStateListener.CONTENT_MODIFIED);
} else {
for (int i = 0; i < rowsModified.size(); i++) {
Integer indexModified = rowsModified.get(i);
fireTableRowsUpdated(indexModified, indexModified);
}
if (!rowsModified.isEmpty()) {
fireModelStateChanged(ModelStateListener.CONTENT_MODIFIED);
}
}
fireModelStateChanged(ModelStateListener.STATE_OK);
}
});
}
private final Where getAuthorizedTaskTypes(final int userID, final SQLTable tableTache) {
final SQLField typeF = tableTache.getFieldRaw("TYPE");
if (typeF == null)
return null;
final Set<String> types = UserRightsManager.getInstance().getObjects(userID, "TASK", new IFactory<Set<String>>() {
@SuppressWarnings("unchecked")
@Override
public Set<String> createChecked() {
final SQLSelect sel = new SQLSelect();
sel.addSelect(typeF);
sel.addGroupBy(typeF);
return new HashSet<String>(tableTache.getDBSystemRoot().getDataSource().executeCol(sel.asString()));
}
});
return types == null ? Where.TRUE : new Where(typeF, types);
}
private static final int societeID = ((ComptaBasePropsConfiguration) Configuration.getInstance()).getSocieteID();
private static final DBSystemRoot base = Configuration.getInstance().getSystemRoot();
private static final SQLTable tableTache = base.getRoot("Common").getTable("TACHE_COMMON");
private static final Where where2 = new Where(tableTache.getField("ID_SOCIETE_COMMON"), "=", tableTache.getUndefinedID()).or(new Where(tableTache.getField("ID_SOCIETE_COMMON"), "=", societeID));
private synchronized void fillFromDatabase(final Map<Integer, TodoListElement> m) {
long time1 = System.currentTimeMillis();
final SQLSelect select = new SQLSelect();
select.addSelectStar(tableTache);
Where where = new Where(tableTache.getField("ID_USER_COMMON_TO"), this.listIdListener);
final int userID = getCurrentUser().getId();
where = where.or(new Where(tableTache.getField("ID_USER_COMMON_ASSIGN_BY"), "=", userID));
where = where.or(getAuthorizedTaskTypes(userID, tableTache));
if (!isHistoryVisible()) {
Where w3 = new Where(tableTache.getField("FAIT"), "=", Boolean.FALSE);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
Where w4 = new Where(tableTache.getField("DATE_FAIT"), "<>", (Object) null);
w4 = w4.and(new Where(tableTache.getField("DATE_FAIT"), ">", cal.getTime()));
w3 = w3.or(w4);
where = where.and(w3);
}
select.setWhere(where.and(where2));
select.addFieldOrder(tableTache.getField("ID_USER_COMMON_TO"));
select.addFieldOrder(tableTache.getField("DATE_EXP"));
this.rights = UserTaskRight.getUserTaskRight(getCurrentUser());
// don't use the cache since by definition this table is shared by everyone, so we can't
// rely on our modifications
final List<SQLRow> l = SQLRowListRSH.execute(select, false, false);
for (SQLRow row : l) {
final TodoListElement t = new TodoListElement(getUserManager(), row.asRowValues());
// add tasks that we created, we must do, or that we can read
// plus for preventec, tasks with a type must visible to everybody
boolean add = false;
String type = row.getString("TYPE");
if (type != null && type.trim().length() > 0) {
add = true;
} else if (row.getInt("ID_USER_COMMON_CREATE") == userID || row.getInt("ID_USER_COMMON_TO") == userID) {
add = true;
} else {
for (int i = 0; i < TodoListModel.this.rights.size(); i++) {
final UserTaskRight element = TodoListModel.this.rights.get(i);
if (element.getIdToUser() == row.getInt("ID_USER_COMMON_TO") && element.canRead()) {
add = true;
break;
}
}
}
if (add)
m.put(row.getID(), t);
}
long time2 = System.currentTimeMillis();
final long t = time2 - time1;
// System.err.println("Time to fill from DB : " + t);
long delay = 2 + t / 1000;
if (delay > MAX_DELAY)
delay = MAX_DELAY;
if (delay < MIN_DELAY)
delay = MIN_DELAY;
this.currentDelay = delay;
}
public int getColumnCount() {
if (this.mode == EXTENDED_MODE)
return 7;
return 5;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
synchronized (this.elements) {
// Modifier la priorité de la tache
if (columnIndex == 1) {
return true;
}
if (this.mode == EXTENDED_MODE && columnIndex == 3) {
// Impossible de modifier la date de creation
return false;
}
if (this.elements.size() <= rowIndex) {
System.err.println("Size error :" + this.elements.size() + " i:" + rowIndex);
rowIndex = 0;
}
final TodoListElement task = this.elements.get(rowIndex);
if (task == null)
return false;
final int size = this.rights.size();
if (columnIndex == 0)
// Validation
for (int i = 0; i < size; i++) {
UserTaskRight right = this.rights.get(i);
if (right.getIdToUser() == task.getUserId() && right.canValidate()) {
return true;
}
}
else if (columnIndex == this.getColumnCount() - 1) {
// Colonne d'assignement
return (task.getCreatorId().equals(getCurrentUser().getId()));
} else {
// Modification
for (int i = 0; i < size; i++) {
UserTaskRight right = this.rights.get(i);
// i.e. we can still modify tasks we created and assigned to another user, but
// we cannot change tasks assigned to us
if (right.getIdToUser() == task.getCreatorId() && right.canModify()) {
return true;
}
}
}
}
return false;
}
@Override
public Class<?> getColumnClass(final int columnIndex) {
switch (columnIndex) {
case 0:
return Boolean.class;
case 1:
return Integer.class;
case 2:
return String.class;
case 3:
return Timestamp.class;
case 4:
if (this.mode == EXTENDED_MODE) {
return Timestamp.class;
}
return Integer.class;
case 5:
return Timestamp.class;
case 6:
return Integer.class;
default:
return String.class;
}
}
public Object getValueAt(int rowIndex, int columnIndex) {
synchronized (this.elements) {
if (this.elements.size() <= rowIndex) {
System.err.println("Size error :" + this.elements.size() + " i:" + rowIndex);
rowIndex = 0;
}
final TodoListElement task = this.elements.get(rowIndex);
switch (columnIndex) {
case 0:
return task.isDone();
case 1:
return task.getPriority();
case 2:
return task.getName();
case 3:
if (this.mode == EXTENDED_MODE) {
return task.getDate();
}
return task.getExpectedDate();
case 4:
if (this.mode == EXTENDED_MODE) {
return task.getDoneDate();
}
return task.getUserId();
case 5:
return task.getExpectedDate();
case 6:
return task.getUserId();
default:
return "????????";
}
}
}
public TodoListElement getTaskAtRow(int rowIndex) {
return this.elements.get(rowIndex);
}
@Override
public int getRowCount() {
return this.elements.size();
}
public void removeRow(int row) {
elements.remove(row);
fireTableRowsDeleted(row, row);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
synchronized (this.elements) {
if (rowIndex >= getRowCount()) {
// Cas de la perte de l'edition de la derniere ligne supprimee
return;
}
final TodoListElement task = this.elements.get(rowIndex);
switch (columnIndex) {
case 0:
task.setDone((Boolean) aValue);
break;
case 1:
task.setPriority((Integer) aValue);
break;
case 2:
task.setName((String) aValue);
break;
case 3:
if (this.mode == EXTENDED_MODE) {
task.setDate((Timestamp) aValue);
}
task.setExpectedDate((Timestamp) aValue);
break;
case 4:
if (this.mode == EXTENDED_MODE) {
task.setDoneDate((Timestamp) aValue);
break;
}
task.setUserId((Integer) aValue);
break;
case 5:
task.setExpectedDate((Timestamp) aValue);
break;
case 6:
task.setUserId((Integer) aValue);
break;
default:
break;
}
task.commitChanges();
}
fireTableRowsUpdated(rowIndex, rowIndex);
}
@Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0:
return "";
case 1:
return "";
case 2:
return TM.tr("taskToDo");
case 3:
if (this.mode == EXTENDED_MODE) {
return TM.tr("created");
}
return TM.tr("todoBefore.col");
case 4:
if (this.mode == EXTENDED_MODE) {
return TM.tr("completed");
}
return TM.tr("assignedTo");
case 5:
return TM.tr("todoBefore.col");
case 6:
return TM.tr("assignedTo");
default:
return "?????";
}
}
/**
* Ajoute une nouvelle Tâche de manière asynchrone
*/
public void addNewTask() {
final SwingWorker<?, ?> worker = new SwingWorker<Object, Object>() {
@Override
public Object doInBackground() {
final SQLRowValues rowV = new SQLRowValues(tableTache);
final Calendar cal = Calendar.getInstance();
rowV.put("DATE_ENTREE", new java.sql.Timestamp(cal.getTimeInMillis()));
cal.add(Calendar.HOUR_OF_DAY, 1);
rowV.put("DATE_EXP", new java.sql.Timestamp(cal.getTimeInMillis()));
cal.set(Calendar.YEAR, 2000);
cal.set(Calendar.DAY_OF_YEAR, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.MILLISECOND, 0);
rowV.put("DATE_FAIT", new java.sql.Timestamp(cal.getTimeInMillis()));
final int currentUserId = getCurrentUser().getId();
rowV.put("ID_USER_COMMON_ASSIGN_BY", currentUserId);
rowV.put("ID_USER_COMMON_TO", currentUserId);
try {
rowV.insert();
} catch (SQLException e) {
fireModelStateChanged(ModelStateListener.STATE_DEAD);
e.printStackTrace();
}
return null;
}
@Override
public void done() {
// synchrone pour que le fire fonctionne bien
synchronousFill();
fireTableRowsInserted(getRowCount(), getRowCount());
}
};
worker.execute();
}
synchronized void setMode(int mode) {
this.mode = mode;
fireTableStructureChanged();
}
public synchronized int getMode() {
return this.mode;
}
public boolean deleteTaskAtIndex(int index) {
synchronized (this.elements) {
final TodoListElement t = this.elements.get(index);
final int currentUserId = getCurrentUser().getId();
if (t.getCreatorId() != currentUserId) {
JOptionPane.showMessageDialog(this.table, TM.tr("deleteForbidden"));
return false;
}
t.archive();
}
removeRow(index);
return true;
}
public void addIdListener(Integer id) {
this.listIdListener.add(id);
asynchronousFill();
}
public void addIdListenerSilently(Integer id) {
this.listIdListener.add(id);
}
public void removeIdListener(Integer id) {
this.listIdListener.remove(id);
asynchronousFill();
}
public boolean listenToId(Integer id) {
return this.listIdListener.contains(id);
}
public void setTable(JTable t) {
this.table = t;
}
public void stopUpdate() {
this.stop = true;
}
public void addModelStateListener(ModelStateListener l) {
if (!this.stateListenerList.contains(l)) {
this.stateListenerList.add(l);
}
}
public void removeModelStateListener(ModelStateListener l) {
if (this.stateListenerList.contains(l)) {
this.stateListenerList.remove(l);
}
}
private void fireModelStateChanged(int state) {
final int size = this.stateListenerList.size();
for (int i = 0; i < size; i++) {
this.stateListenerList.get(i).stateChanged(state);
}
}
public final UserManager getUserManager() {
return this.uMngr;
}
public final User getCurrentUser() {
return this.getUserManager().getCurrentUser();
}
public synchronized boolean isHistoryVisible() {
return this.historyVisible;
}
public synchronized void setHistoryVisible(boolean historyVisible) {
this.historyVisible = historyVisible;
}
}