Dépôt officiel du code source de l'ERP OpenConcerto
Rev 151 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011-2019 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.sql.view.list;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.utils.Value;
import org.openconcerto.utils.cc.IPredicate;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Future;
// use SQLRowValues to allow graph
public abstract class SQLTableModelLinesSource {
private final ITableModel model;
private final PropertyChangeListener reqListener;
private final List<PropertyChangeListener> listeners;
private IPredicate<SQLRowValues> filter;
{
this.listeners = new ArrayList<PropertyChangeListener>();
this.filter = null;
}
protected SQLTableModelLinesSource(final ITableModel model) {
this.model = model;
this.reqListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
fireChanged(evt);
}
};
}
void live() {
this.getParent().getReq().addWhereListener(this.reqListener);
}
void die() {
this.getParent().getReq().rmWhereListener(this.reqListener);
}
public final ITableModel getModel() {
return this.model;
}
public abstract SQLTableModelSource getParent();
public final ListSQLRequest getUpdateQueueReq() {
return this.getModel().getUpdateQ().getState().getReq();
}
public final List<ListSQLLine> getAll() {
return this.get(null);
}
/**
* Fetch up to date values from the DB.
*
* @param ids which rows to fetch, <code>null</code> meaning all.
* @return the new values from the DB, some changes in the DB might be ignored if there's
* pending changes in this.
*/
public abstract List<ListSQLLine> get(final Collection<? extends Number> ids);
/**
* A row in the DB has been changed, fetch its current value.
*
* @param id a valid ID of a database row.
* @return if not {@link Value#hasValue()} the event should be ignored, otherwise the new value
* for the passed ID, <code>null</code> if it is not part of this.
*/
public abstract Value<ListSQLLine> get(final int id);
/**
* Implementations should only use state of the parameters, so that this method can be
* thread-safe (it is called both by the {@link UpdateQueue} and by the EDT in
* {@link ITableModel}). This implementation order lines like the source {@link ListSQLRequest
* request}.
*
* @param l1 the first line.
* @param l2 the second line.
* @return a negative integer, zero, or a positive integer as this object is less than, equal
* to, or greater than the specified object.
* @see Comparator#compare(Object, Object)
*/
public int compare(ListSQLLine l1, ListSQLLine l2) {
return ListSQLLine.compareLikeRequest(l1, l2);
}
public boolean isCellEditable(ListSQLLine line, int colIndex, SQLTableModelColumn col) {
return true;
}
public abstract Future<?> moveBy(final List<? extends SQLRowAccessor> rows, final int inc);
// take IDs :
// 1. no need to protect rows from modifications, just copy IDs
// 2. for non committed rows, i.e. without DB ID and thus without SQLRow, it's easier to handle
// (virtual) IDs than to use IdentitySet of SQLRowValues
public abstract Future<?> moveTo(final List<? extends Number> rows, final int rowIndex);
public final void setFilter(final IPredicate<SQLRowValues> filter) {
// always fire since for now there's no other way for the caller
// (ie if the meaning of filter change, it has to do setFilter(getFilter()) )
this.filter = filter;
this.fireChanged(new PropertyChangeEvent(this, "filter", null, this.filter));
}
public final IPredicate<SQLRowValues> getFilter() {
return this.filter;
}
/**
* Adds a listener to be notified when {@link #getAll()} change value.
*
* @param l the listener.
*/
public final void addListener(PropertyChangeListener l) {
this.listeners.add(l);
}
public final void rmListener(PropertyChangeListener l) {
this.listeners.remove(l);
}
protected final void fireChanged(PropertyChangeEvent evt) {
for (final PropertyChangeListener l : this.listeners)
l.propertyChange(evt);
}
protected final ListSQLLine createLine(final SQLRowValues v) {
return this.createLine(v, null);
}
/**
* Create a line with the passed row.
*
* @param v the values.
* @param passedID the {@link ListSQLLine#getID() ID} of the result, <code>null</code> meaning
* {@link SQLRowValues#getID()}.
* @return a new line.
* @throws IllegalArgumentException if <code>passedID</code> is <code>null</code> and
* <code>v</code> {@link SQLRowValues#hasID() has no ID}.
*/
protected final ListSQLLine createLine(final SQLRowValues v, final Number passedID) {
if (v == null || (this.filter != null && !this.filter.evaluateChecked(v)))
return null;
final int id;
if (passedID != null) {
id = passedID.intValue();
} else if (v.hasID()) {
id = v.getID();
} else {
throw new IllegalArgumentException("No ID for " + v);
}
final ListSQLLine res = new ListSQLLine(this, v, id, this.getModel().getUpdateQ().getState());
this.lineCreated(res);
return res;
}
/**
* A new line has been created. This implementation does nothing.
*
* @param res the newly created line.
*/
protected void lineCreated(ListSQLLine res) {
}
final void colsChanged(final SQLTableModelSourceState beforeState, final SQLTableModelSourceState afterState) {
this.model.getUpdateQ().stateChanged(beforeState, afterState);
}
/**
* Change the line <code>l</code> at the passed path with the passed values.
*
* @param l the line to change, eg RECEPTEUR[12].
* @param path the changing path, eg RECEPTEUR.ID_LIMITEUR.
* @param vals the new values, eg LIMITEUR{ID=4, DESIGNATION="dess"}.
* @throws SQLException if the values cannot be commited.
*/
public abstract void commit(ListSQLLine l, Path path, SQLRowValues vals) throws SQLException;
}