OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Comparer les révisions

Ignorer les espaces blanc Révision 155 → Révision 156

/trunk/OpenConcerto/src/META-INF/services/java.nio.file.spi.FileTypeDetector
Nouveau fichier
0,0 → 1,0
ilm.utils.mime.FreeDesktopMimeDetector
/trunk/OpenConcerto/src/org/jopenchart/DataModel1D.java
4,7 → 4,7
import java.util.List;
 
public class DataModel1D extends DataModel {
private final List<Number> l = new ArrayList<Number>();
private final List<Number> l = new ArrayList<>();
 
public DataModel1D() {
 
12,8 → 12,7
 
public DataModel1D(Number[] data) {
for (int i = 0; i < data.length; i++) {
Number number = data[i];
l.add(number);
l.add(data[i]);
}
}
 
21,15 → 20,15
this.addAll(list);
}
 
public void addAll(List<Number> data) {
public synchronized void addAll(List<Number> data) {
l.addAll(data);
}
 
public int getSize() {
public synchronized int getSize() {
return l.size();
}
 
public void setValueAt(int index, Number value) {
public synchronized void setValueAt(int index, Number value) {
ensureCapacity(index);
l.set(index, value);
}
40,37 → 39,34
}
}
 
public Number getValueAt(int index) {
public synchronized Number getValueAt(int index) {
ensureCapacity(index);
return l.get(index);
}
 
public Number getMaxValue() {
public synchronized Number getMaxValue() {
Number max = 0;
for (Number b : this.l) {
if (max == null) {
if (b != null && b.doubleValue() > max.doubleValue()) {
max = b;
} else if (b != null && b.doubleValue() > max.doubleValue()) {
max = b;
}
}
return max;
}
 
public Number getMinValue() {
public synchronized Number getMinValue() {
Number min = 0;
for (Number b : this.l) {
if (min == null) {
if (b != null && b.doubleValue() < min.doubleValue()) {
min = b;
} else if (b != null && b.doubleValue() < min.doubleValue()) {
min = b;
}
}
return min;
}
 
public void clear() {
for (int i = 0; i < this.getSize(); i++) {
public synchronized void clear() {
final int size = l.size();
for (int i = 0; i < size; i++) {
this.setValueAt(i, null);
}
}
/trunk/OpenConcerto/src/org/jopenchart/DataModel2D.java
7,10 → 7,10
public class DataModel2D extends DataModel {
 
private String[][] data;
private int rowCount;
private int colCount;
private List<String> rowLabels = new ArrayList<String>();
private List<String> colLabels = new ArrayList<String>();
private final int rowCount;
private final int colCount;
private List<String> rowLabels = new ArrayList<>();
private List<String> colLabels = new ArrayList<>();
 
public DataModel2D(int row, int col) {
this.rowCount = row;
27,24 → 27,24
this.rowLabels.add(String.valueOf((char) ('A' + i)));
}
for (int i = 0; i < col; i++) {
this.colLabels.add(String.valueOf(((1 + i))));
this.colLabels.add(String.valueOf(1 + i));
}
 
}
 
public String getValue(int row, int col) {
public synchronized String getValue(int row, int col) {
return data[row][col];
}
 
public void setValue(String value, int row, int col) {
public synchronized void setValue(String value, int row, int col) {
data[row][col] = value;
}
 
public String getColumnLabel(int col) {
public synchronized String getColumnLabel(int col) {
return this.colLabels.get(col);
}
 
public String getRowLabel(int row) {
public synchronized String getRowLabel(int row) {
return this.rowLabels.get(row);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/search/TextSearchSpec.java
85,6 → 85,18
return res;
}
 
private final String format(final Format fmt, final Object cell) {
try {
return fmt.format(cell);
} catch (Exception e) {
throw new IllegalStateException("Couldn't format " + cell + '(' + getClass(cell) + ") with " + fmt, e);
}
}
 
static private String getClass(Object cell) {
return cell == null ? "<null>" : cell.getClass().getName();
}
 
private final Double getDouble() {
if (!this.parsedFilterD_tried) {
try {
131,7 → 143,7
// which is better achieved with contains)
// PS: the date format is useful for parsing since "> 25/12/2010" means
// "> 25/12/2010 00:00" which is understandable and concise.
if (isContains && containsOrEquals(fmt.format(cell)))
if (isContains && containsOrEquals(format(fmt, cell)))
return true;
// e.g. test if "01/01/2006" is before "25 déc. 2010"
else if (!isContains && test(getParsed(fmt), cell))
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/UpdateQueue.java
140,7 → 140,7
this.put(new SetStateRunnable() {
@Override
public void run() {
getModel().getSearchQueue().start();
getModel().startSearchQueue();
}
});
}
244,7 → 244,8
}
// if the modified row isn't in the existing line, it might still affect it
// if it's a referent row insertion
if (!put && lastReferentField != null && r.exists()) {
if (!put && lastReferentField != null && r.exists() && !r.isForeignEmpty(lastReferentField)) {
// no NPE, even without an undefined ID since we tested isForeignEmpty()
final int foreignID = r.getInt(lastReferentField);
for (final SQLRowValues current : line.getRow().followPath(p.minusLast(), CreateMode.CREATE_NONE, false)) {
if (current.getID() == foreignID) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/TextTableCellEditorWithCompletion.java
17,6 → 17,8
import org.openconcerto.ui.TextAreaTableCellEditor;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
 
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
56,14 → 58,24
 
this.textWithCompl.hidePopup();
if (!getValidState().isValid()) {
JOptionPane.showMessageDialog(SwingUtilities.getRoot(this.getTextArea()), getValidState().getValidationText());
final Component root = SwingUtilities.getRoot(TextTableCellEditorWithCompletion.this.getTextArea());
final String validationText = getValidState().getValidationText();
// JOptionPane dans invokeLater pour éviter une boucle avec notre listener sur le focus
// de la table qui stoppe
// l'édition
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(root, validationText);
}
});
return false;
} else {
return super.stopCellEditing();
}
}
 
@Override
public void setLimitedSize(int nbChar) {
this.textWithCompl.setLimitedSize(nbChar);
}
73,5 → 85,3
}
 
}
 
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTextComboTableCellEditor.java
25,6 → 25,7
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.ui.list.selection.BaseListStateModel;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.convertor.NumberConvertor;
 
import java.awt.Color;
import java.awt.Component;
48,7 → 49,7
 
private Where w;
// Stock Value of Combo to fix problem with undefined
int val = 1;
Integer val = 1;
 
boolean addUndefined;
 
123,18 → 124,19
}
 
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value != null) {
this.val = (Integer) value;
this.comboBox.setValue(this.val);
}
 
this.val = (Integer) value;
this.comboBox.setValue(this.val);
 
this.comboBox.grabFocus();
 
this.comboBox.addModelListener("wantedID", new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
SQLTextComboTableCellEditor.this.val = comboBox.getWantedID();
SQLTextComboTableCellEditor.this.val = NumberConvertor.convertExact((Number) evt.getNewValue(), Integer.class);
}
});
 
// Filtre sur une valeur specifique
if (this.fieldWhere != null && table instanceof RowValuesTable) {
RowValuesTable rowVals = (RowValuesTable) table;
160,7 → 162,7
}
 
public int getComboSelectedId() {
return SQLTextComboTableCellEditor.this.comboBox.getSelectedId();
return SQLTextComboTableCellEditor.this.comboBox.getWantedID();
}
 
private SQLField fieldWhere;
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelLinesSourceOnline.java
49,7 → 49,7
assert SwingUtilities.isEventDispatchThread();
if (this.moveQ == null) {
this.moveQ = new MoveQueue(getModel());
this.moveQ.start();
getModel().startQueue(this.moveQ);
}
return this.moveQ;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableControlPanel.java
99,7 → 99,11
this.buttonInserer = new JButton(TM.tr("insertNewLine"));
this.buttonInserer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
RowValuesTableControlPanel.this.model.addNewRowAt(table.getSelectedRow());
int index = table.getSelectedRow();
if (index < 0 || index > table.getRowCount()) {
index = table.getRowCount();
}
RowValuesTableControlPanel.this.model.addNewRowAt(index);
}
});
this.buttonInserer.setEnabled(false);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ITableModel.java
38,6 → 38,7
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
67,6 → 68,7
* addTableModelListener()) it dies and cannot be used again.
*
* @author Sylvain CUAZ
* @see #start()
*/
public class ITableModel extends AbstractTableModel {
public static enum SleepState {
169,6 → 171,8
private boolean cellsEditable, orderEditable;
private boolean debug;
 
@GuardedBy("this")
private UncaughtExceptionHandler uncaughtExnHandler = null;
private DyingQueueExceptionHandler dyingQueueHandler = null;
 
public ITableModel(SQLTableModelSource src) {
880,7 → 884,14
super.addTableModelListener(l);
}
 
// TODO no longer leak this in our constructor
public synchronized final void setUncaughtExceptionHandler(UncaughtExceptionHandler uncaughtExnHandler) {
this.uncaughtExnHandler = uncaughtExnHandler;
}
 
public synchronized final UncaughtExceptionHandler getUncaughtExceptionHandler() {
return this.uncaughtExnHandler;
}
 
public final void start() {
final RunningState state = this.updateQ.getRunningState();
if (state.compareTo(RunningState.RUNNING) > 0)
888,10 → 899,20
if (state == RunningState.NEW) {
print("starting");
this.getLinesSource().live();
this.updateQ.start();
this.startQueue(this.updateQ);
}
}
 
final void startSearchQueue() {
this.startQueue(this.getSearchQueue());
}
 
final void startQueue(final SleepingQueue q) {
q.start((thr) -> {
thr.setUncaughtExceptionHandler(getUncaughtExceptionHandler());
});
}
 
@Override
public void removeTableModelListener(TableModelListener l) {
assert SwingUtilities.isEventDispatchThread();
928,6 → 949,7
* {@link SleepingQueue#die()}, <code>null</code> to reset default behavior.
*/
public void setDyingQueueExceptionHandler(final DyingQueueExceptionHandler h) {
assert SwingUtilities.isEventDispatchThread();
this.dyingQueueHandler = h;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
370,7 → 370,7
 
public String getLine(final boolean created, final SQLRowValues row, final SQLField userF, final SQLField dateF) {
final Calendar date = dateF == null ? null : row.getDate(dateF.getName());
final SQLRowAccessor user = userF == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName());
final SQLRowAccessor user = userF == null || row.getObject(userF.getName()) == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName());
if (user == null && date == null)
return null;
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ListSQLLine.java
275,8 → 275,8
}
if (toRemove != null)
toRemove.remove(lastField.getName());
// attach updated values
if (vals != null && vals.getLong(lastField.getName()) == target.getIDNumber().longValue())
// attach updated values, foreign ID is always present but can be null
if (vals != null && target.getIDNumber().equals(vals.getForeignIDNumberValue(lastField.getName()).getValue()))
vals.deepCopy().put(lastField.getName(), target);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/MoveQueue.java
18,17 → 18,19
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelect.LockStrength;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.ReOrder;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.SleepingQueue;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
131,20 → 133,13
// if only some rows are moved, update one by one (avoids refreshing the whole list)
// (getRowCount() is not thread-safe, so use getTotalRowCount())
if (rowCount < 5 && rowCount < (this.tableModel.getTotalRowCount() / 3)) {
final List<?> l;
if (after) {
// If we want to put X,Y after A in the list A,B,C
// we need to pass first Y : A,Y,B,C then X :
// A,X,Y,B,C
l = new ArrayList<Object>(srcRows);
Collections.reverse(l);
} else {
l = srcRows;
}
final SQLTable t = getTable();
final String orderName = t.getOrderField().getName();
final SQLRowValues vals = new SQLRowValues(t);
for (final Object src : l) {
vals.setOrder(destRow, after).update(getID(src, t).intValue());
final List<BigDecimal> orders = ReOrder.getFreeOrderValuesFor(rowCount, after, destRow).get0();
for (int i = 0; i < rowCount; i++) {
final Object src = srcRows.get(i);
vals.put(orderName, orders.get(i)).update(getID(src, t).intValue());
}
} else {
// update all rows at once and refresh the whole list
184,75 → 179,64
moveAtOnce(srcRows, srcRows.size(), after, destRow);
}
 
/**
* Move the passed rows just before or just after the destination row if needed.
*
* @param ids rows to order.
* @param after <code>true</code> if the rows should be placed after <code>destRow</code>,
* <code>false</code> otherwise.
* @param destRow <code>srcRows</code> will be placed relative to the order of this row.
* @param checkBefore if <code>true</code> the current DB order will be checked and if it
* matched the passed rows, no change will be made to the DB, <code>false</code> to
* always change the orders in the DB.
* @return if the DB was changed.
* @throws SQLException if an error occurs.
*/
static public boolean moveIDsAtOnce(final List<? extends Number> ids, final boolean after, final SQLRow destRow, final boolean checkBefore) throws SQLException {
final int size = ids.size();
if (checkBefore) {
final SQLTable table = destRow.getTable();
final SQLSelect sel = new SQLSelect(true);
sel.addSelect(table.getKey());
sel.addOrder(table);
sel.setWhere(new Where(table.getKey(), ids));
// needed since we might update them just after in moveAtOnce(), and it's safer to lock
// with the most restrictive mode first.
sel.setLockStrength(LockStrength.UPDATE);
final List<?> dbOrderedIDs = table.getDBSystemRoot().getDataSource().executeCol(sel.asString());
if (dbOrderedIDs.size() != size)
throw new IllegalStateException("Missing rows");
boolean orderOK = true;
for (int i = 0; i < size && orderOK; i++) {
final Number passedID = ids.get(i);
final Number dbID = (Number) dbOrderedIDs.get(i);
orderOK = NumberUtils.areNumericallyEqual(passedID, dbID);
}
if (orderOK)
return false;
}
moveAtOnce(ids, size, after, destRow);
return true;
}
 
static private void moveAtOnce(final List<?> srcRows, final int rowCount, final boolean after, final SQLRow destRow) throws SQLException {
if (rowCount == 0)
return;
final SQLTable t = destRow.getTable();
 
// ULP * 10 to give a little breathing room
final BigDecimal minDistance = t.getOrderULP().scaleByPowerOfTen(1);
assert minDistance.signum() > 0;
final BigDecimal places = BigDecimal.valueOf(rowCount + 1);
// the minimum room so that we can move all rows
final BigDecimal room = minDistance.multiply(places);
final List<BigDecimal> freeOrderValues = ReOrder.getFreeOrderValuesFor(rowCount, after, destRow).get0();
 
final BigDecimal destOrder = destRow.getOrder();
final SQLRow nextRow = destRow.getRow(true);
final BigDecimal inc;
final boolean destRowReordered;
if (nextRow == null) {
// if destRow is the last row, we can choose whatever increment we want
inc = ReOrder.DISTANCE;
// but we need to move destRow if we want to add before it
destRowReordered = false;
} else {
final BigDecimal nextOrder = nextRow.getOrder();
assert nextOrder.compareTo(destOrder) > 0;
final BigDecimal diff = nextOrder.subtract(destOrder);
assert diff.signum() > 0;
if (diff.compareTo(room) < 0) {
// if there's not enough room, reorder to squeeze rows upwards
// since we keep increasing count, we will eventually reorder all rows afterwards
int count = 100;
final int tableRowCount = t.getRowCount();
boolean reordered = false;
while (!reordered) {
// only push destRow upwards if we want to add before
reordered = ReOrder.create(t, destOrder, !after, count, destOrder.add(room)).exec();
if (!reordered && count > tableRowCount)
throw new IllegalStateException("Unable to reorder " + count + " rows in " + t);
count *= 10;
}
inc = minDistance;
destRowReordered = true;
} else {
// truncate
inc = DecimalUtils.round(diff.divide(places, DecimalUtils.HIGH_PRECISION), t.getOrderDecimalDigits(), RoundingMode.DOWN);
destRowReordered = false;
}
}
// i.e. inc > 0
assert inc.compareTo(minDistance) >= 0;
 
BigDecimal newOrder = destOrder;
// by definition if we want to add after, destOrder should remain unchanged
if (after) {
newOrder = newOrder.add(inc);
}
final List<List<String>> newOrdersAndIDs = new ArrayList<List<String>>(rowCount);
int i = 0;
final List<Number> ids = rowCount < 10 ? new ArrayList<Number>(rowCount) : null;
// we go from newOrder and up, so that the passed rows are in ascending order
for (final Object src : srcRows) {
final Number srcID = getID(src, t);
if (ids != null)
ids.add(srcID);
final BigDecimal newOrder = freeOrderValues.get(i++);
newOrdersAndIDs.add(Arrays.asList(srcID.toString(), newOrder.toPlainString()));
newOrder = newOrder.add(inc);
}
// move out before general request as most DB systems haven't got DEFERRABLE constraints
if (!after && !destRowReordered) {
final UpdateBuilder updateDestRow = new UpdateBuilder(t);
updateDestRow.setObject(t.getOrderField(), newOrder);
updateDestRow.setWhere(destRow.getWhere());
t.getDBSystemRoot().getDataSource().execute(updateDestRow.asString());
}
 
final SQLSyntax syntax = SQLSyntax.get(t);
final UpdateBuilder update = new UpdateBuilder(t);
261,6 → 245,12
update.setFromVirtualJoinField(t.getOrderField().getName(), constantTableAlias, "newOrder");
t.getDBSystemRoot().getDataSource().execute(update.asString());
 
t.fireTableModified(SQLRow.NONEXISTANT_ID, Collections.singletonList(t.getOrderField().getName()));
final List<String> fieldsChanged = Collections.singletonList(t.getOrderField().getName());
if (ids == null) {
t.fireTableModified(SQLRow.NONEXISTANT_ID, fieldsChanged);
} else {
for (final Number id : ids)
t.fireTableModified(id.intValue(), fieldsChanged);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/SQLMenuItemHelper.java
18,6 → 18,7
import org.openconcerto.utils.cc.IClosure;
 
import java.awt.event.ActionEvent;
import java.util.Objects;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
149,15 → 150,15
return menuItemAction;
}
 
public static abstract class AbstractSQLMenuItemAction extends AbstractAction {
public static abstract class AbstractSQLMenuItemAction<E extends SQLElement> extends AbstractAction {
 
private final SQLElement elem;
private final E elem;
private JFrame frame;
private boolean cacheFrame;
 
public AbstractSQLMenuItemAction(SQLElement elem, String name) {
public AbstractSQLMenuItemAction(E elem, String name) {
super(name);
this.elem = elem;
this.elem = Objects.requireNonNull(elem, "SQLElement");
this.frame = null;
this.cacheFrame = true;
this.putValue(Action.ACTION_COMMAND_KEY, getClass().getName() + " with " + getElem().getCode());
188,7 → 189,7
 
protected abstract JFrame createFrame();
 
public final SQLElement getElem() {
public final E getElem() {
return this.elem;
}
 
198,7 → 199,7
}
}
 
static abstract class GenericSQLElementAction<F extends JFrame> extends AbstractSQLMenuItemAction {
static abstract class GenericSQLElementAction<F extends JFrame> extends AbstractSQLMenuItemAction<SQLElement> {
 
public GenericSQLElementAction(SQLElement elem, String name) {
super(elem, name);
/trunk/OpenConcerto/src/org/openconcerto/sql/PropsConfiguration.java
14,6 → 14,7
package org.openconcerto.sql;
 
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.element.SQLElementNamesFromXML;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItem;
import org.openconcerto.sql.model.DBSystemRoot;
36,6 → 37,7
import org.openconcerto.utils.NetUtils;
import org.openconcerto.utils.ProductInfo;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.ReflectUtils;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Value;
372,6 → 374,13
return rootIsBase ? this.getRootName() : this.getSystemRootName();
}
 
private final String toClassName(final String rsrcName) {
if (rsrcName.charAt(0) == '/')
return rsrcName.substring(1).replace('/', '.');
else
return this.getResourceWD().getPackage().getName() + '.' + rsrcName.replace('/', '.');
}
 
/**
* Return the correct stream depending on file mode. If file mode is
* {@link FileMode#NORMAL_FILE} it will first check if a file named <code>name</code> exists,
383,7 → 392,7
public final InputStream getStream(final String name) {
final File f = getFile(name);
if (mustUseClassloader(f)) {
return this.getClass().getResourceAsStream(name);
return getResourceWD().getResourceAsStream(name);
} else
try {
return new FileInputStream(f);
392,6 → 401,11
}
}
 
// the "working directory" where relative names are resolved
protected Class<? extends PropsConfiguration> getResourceWD() {
return this.getClass();
}
 
private File getFile(final String name) {
return new File(name.startsWith("/") ? name.substring(1) : name);
}
403,7 → 417,7
public final String getResource(final String name) {
final File f = getFile(name);
if (mustUseClassloader(f)) {
return this.getClass().getResource(name).toExternalForm();
return this.getResourceWD().getResource(name).toExternalForm();
} else {
return f.getAbsolutePath();
}
967,7 → 981,8
return new SQLElementDirectory();
}
 
// items will be passed to #getStream(String)
// Use resource name to be able to use absolute (beginning with /) or relative path (to this
// class)
protected List<String> getMappings() {
return Arrays.asList("mapping", "mapping-" + this.getProperty("customer"));
}
977,7 → 992,7
if (mappings.size() == 0)
throw new IllegalStateException("empty mappings");
 
final SQLFieldTranslator trns = new SQLFieldTranslator(this.getRoot(), null, dir);
final SQLFieldTranslator trns = new SQLFieldTranslator(this.getRoot(), dir);
// perhaps listen to UserProps (as in TM)
return loadTranslations(trns, this.getRoot(), mappings);
}
995,9 → 1010,19
final ListIterator<Locale> listIterator = CollectionUtils.getListIterator(langs, true);
while (listIterator.hasNext()) {
final Locale lang = listIterator.next();
found |= loadTranslations(trns, PropsConfiguration.class.getResourceAsStream(cntrl.toBundleName("mapping", lang) + ".xml"), root);
final SQLElementNamesFromXML elemNames = new SQLElementNamesFromXML(lang);
found |= loadTranslations(trns, PropsConfiguration.class.getResourceAsStream(cntrl.toBundleName("mapping", lang) + ".xml"), root, elemNames);
for (final String m : mappings) {
found |= loadTranslations(trns, this.getStream(cntrl.toBundleName(m, lang) + ".xml"), root);
final String bundleName = cntrl.toBundleName(m, lang);
found |= loadTranslations(trns, this.getStream(bundleName + ".xml"), root, elemNames);
final Class<? extends TranslatorFiller> loadedClass = ReflectUtils.getSubclass(toClassName(bundleName), TranslatorFiller.class);
if (loadedClass != null) {
try {
ReflectUtils.createInstance(loadedClass, this).fill(trns);
} catch (Exception e) {
Log.get().log(Level.WARNING, "Couldn't use " + loadedClass, e);
}
}
}
}
}
1004,11 → 1029,28
return trns;
}
 
private final boolean loadTranslations(final SQLFieldTranslator trns, final InputStream in, final DBRoot root) {
@FunctionalInterface
static public interface TranslatorFiller {
void fill(final SQLFieldTranslator t);
}
 
static public abstract class AbstractTranslatorFiller implements TranslatorFiller {
private final PropsConfiguration conf;
 
public AbstractTranslatorFiller(final PropsConfiguration conf) {
this.conf = conf;
}
 
protected final PropsConfiguration getConf() {
return this.conf;
}
}
 
private final boolean loadTranslations(final SQLFieldTranslator trns, final InputStream in, final DBRoot root, final SQLElementNamesFromXML elemNames) {
final boolean res = in != null;
// do not force to have one mapping for each client and each locale
if (res)
trns.load(root, in);
trns.load(root, in, elemNames);
return res;
}
 
1294,11 → 1336,6
}
 
@Override
public final SQLFieldTranslator getTranslator() {
return this.getDirectory().getTranslator();
}
 
@Override
public final SQLElementDirectory getDirectory() {
return this.directory.get();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_en.xml
1,6 → 1,7
<?xml version="1.0" encoding="UTF-8" ?>
<ROOT>
<TABLE name="USER_COMMON">
<translations>
<element refid="sql.user">
<name base="user" />
<FIELD name="NOM" label="Last Name" />
<FIELD name="PRENOM" label="First name" />
<FIELD name="PASSWORD" label="Password" />
12,17 → 13,21
<FIELD name="MAIL" label="E-Mail" />
<FIELD name="DISABLED" label="Account disabled" />
<FIELD name="TEL" label="Phone" titlelabel="Phone" />
</TABLE>
<TABLE name="RIGHT">
</element>
<element refid="sql.right">
<name base="right" />
<FIELD name="CODE" label="Code" />
<FIELD name="NOM" label="Name" titlelabel="Name of right" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</TABLE>
<TABLE name="USER_RIGHT">
</element>
<element refid="sql.user-right">
<name base="user right">
<variant refids="plural" value="users rights" />
</name>
<FIELD name="ID_USER_COMMON" label="User" />
<FIELD name="ID_RIGHT" label="Right" />
<FIELD name="OBJECT" label="Object" />
<FIELD name="user.right.parameters.editor" label="Object" />
<FIELD name="HAVE_RIGHT" label="Right granted" titlelabel="Granted" />
</TABLE>
</ROOT>
</element>
</translations>
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightAutoCompleteComboBox.java
Fichier supprimé
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightUISQLComboRequest.java
Nouveau fichier
0,0 → 1,50
/*
* 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.sql.ui.light;
 
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.IComboSelectionItem;
import org.openconcerto.ui.light.LightUIComboBoxElement;
import org.openconcerto.ui.light.LightUIComboRequest;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Pattern;
 
public class LightUISQLComboRequest implements LightUIComboRequest {
 
private final static Pattern QUERY_SPLIT_PATTERN = Pattern.compile("\\s+");
 
private final ComboSQLRequest request;
 
public LightUISQLComboRequest(ComboSQLRequest request) {
super();
this.request = request;
}
 
@Override
public List<LightUIComboBoxElement> getItems(String filter, Optional<LightUIComboBoxElement> selection) {
final Where where = selection.isPresent() ? new Where(this.request.getPrimaryTable().getKey(), "=", selection.get().getId()) : null;
final List<IComboSelectionItem> items = this.request.getComboItems(true, Arrays.asList(QUERY_SPLIT_PATTERN.split(filter)), Locale.getDefault(), where);
final List<LightUIComboBoxElement> res = new ArrayList<>(items.size());
for (final IComboSelectionItem item : items) {
res.add(new LightUIComboBoxElement(item.getId(), item.getLabel()));
}
return res;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/GroupToLightUIConvertor.java
13,7 → 13,6
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldMapper;
25,6 → 24,7
import org.openconcerto.ui.group.Item;
import org.openconcerto.ui.group.LayoutHints;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.LightUIAutoCompleteComboBox;
import org.openconcerto.ui.light.LightUICheckBox;
import org.openconcerto.ui.light.LightUIDate;
import org.openconcerto.ui.light.LightUIElement;
32,8 → 32,9
import org.openconcerto.ui.light.LightUILabel;
import org.openconcerto.ui.light.LightUILine;
import org.openconcerto.ui.light.LightUIPanel;
import org.openconcerto.ui.light.LightUITextArea;
import org.openconcerto.ui.light.LightUITabbed;
import org.openconcerto.ui.light.LightUITextField;
import org.openconcerto.utils.Log;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.awt.Color;
78,8 → 79,10
 
final LightEditFrame editFrame = new LightEditFrame(this.configuration, group, defaultRow.asRowValues(), parentFrame, editMode);
final LightUIPanel framePanel = editFrame.getContentPanel();
append(sqlElement, framePanel, group);
 
Map<String, LightUITabbed> tabbedMap = new HashMap<>();
append(sqlElement, framePanel, group, tabbedMap);
 
String frameTitle = TranslationManager.getInstance().getTranslationForItem(group.getId());
if (frameTitle == null) {
frameTitle = group.getId();
91,41 → 94,72
return editFrame;
}
 
private void append(final SQLElement sqlElement, final LightUIPanel panel, final Item item) {
private void append(final SQLElement sqlElement, final LightUIPanel panel, final Item item, Map<String, LightUITabbed> tabbedMap) {
if (item instanceof Group) {
final Group gr = (Group) item;
int size = gr.getSize();
 
final String groupTitle = TranslationManager.getInstance().getTranslationForItem(gr.getId());
final LightUIPanel childPanel = new LightUIPanel(gr.getId());
childPanel.setFillWidth(true);
childPanel.setGridWidth(4);
if (gr.getTabId() == null) {
final String groupTitle = TranslationManager.getInstance().getTranslationForItem(gr.getId());
final LightUIPanel childPanel = new LightUIPanel(gr.getId());
childPanel.setFillWidth(true);
childPanel.setGridWidth(4);
 
if (gr.getLocalHint().isFoldable()) {
childPanel.setTitle(groupTitle);
childPanel.setFoldable(true);
if (gr.getLocalHint().isFoldable()) {
childPanel.setTitle(groupTitle);
childPanel.setFoldable(true);
} else {
if (groupTitle != null) {
final LightUILine titleLine = new LightUILine();
final LightUILabel titleLabel = new LightUILabel(gr.getId() + ".title.label");
titleLabel.setGridWidth(4);
titleLabel.setFontBold(true);
titleLabel.setLabel(groupTitle);
titleLabel.setFillWidth(true);
titleLine.addChild(titleLabel);
childPanel.addChild(titleLine);
final LightUILine line = new LightUILine();
childPanel.addChild(line);
}
}
 
for (int i = 0; i < size; i++) {
this.append(sqlElement, childPanel, gr.getItem(i), tabbedMap);
}
 
final LightUILine line = new LightUILine();
line.addChild(childPanel);
panel.addChild(line);
} else {
if (groupTitle != null) {
final LightUILine titleLine = new LightUILine();
final LightUILabel titleLabel = new LightUILabel(gr.getId() + ".title.label");
titleLabel.setGridWidth(4);
titleLabel.setFontBold(true);
titleLabel.setLabel(groupTitle);
titleLabel.setFillWidth(true);
titleLine.addChild(titleLabel);
childPanel.addChild(titleLine);
String tabId = gr.getTabId();
LightUITabbed tabbed = tabbedMap.get(tabId);
if (tabbed == null) {
tabbed = new LightUITabbed(tabId) {
 
@Override
public void loadTab(String tabId) {
// TODO Auto-generated method stub
 
}
};
final LightUILine line = new LightUILine();
childPanel.addChild(line);
line.addChild(tabbed);
panel.addChild(line);
tabbedMap.put(tabId, tabbed);
}
}
// add the group in the tabbed
final LightUIPanel childPanel = new LightUIPanel(gr.getId());
childPanel.setFillWidth(true);
childPanel.setGridWidth(4);
String title = TranslationManager.getInstance().getTranslationForItem(gr.getId());
childPanel.setTitle(title);
for (int i = 0; i < size; i++) {
this.append(sqlElement, childPanel, gr.getItem(i), tabbedMap);
}
 
for (int i = 0; i < size; i++) {
this.append(sqlElement, childPanel, gr.getItem(i));
tabbed.addChild(childPanel);
 
}
 
final LightUILine line = new LightUILine();
line.addChild(childPanel);
panel.addChild(line);
} else {
final LayoutHints localHint = item.getLocalHint();
LightUILine currentLine = panel.getLastLine();
156,7 → 190,10
panel.addChild(currentLine);
}
 
final SQLField field = this.mapper.getSQLFieldForItem(item.getId());
SQLField field = this.mapper.getSQLFieldForItem(item.getId());
if (field == null) {
field = sqlElement.getTable().getFieldRaw(item.getId());
}
LightUILabel elementLabel = null;
 
String label = this.getLabelForItem(field, item);
191,19 → 228,13
if (field != null) {
Class<?> javaType = field.getType().getJavaType();
if (field.isKey()) {
elementEditor = new LightAutoCompleteComboBox(item.getId());
elementEditor = new LightUIAutoCompleteComboBox(item.getId());
elementEditor.setMinInputSize(20);
elementEditor.setValueType(LightUIElement.VALUE_TYPE_REF);
} else if (javaType.equals(String.class)) {
if (field.getType().getSize() > 1000) {
elementEditor = new LightUITextArea(item.getId());
elementEditor.setValue("");
elementEditor.setMinInputSize(10);
} else {
elementEditor = new LightUITextField(item.getId());
elementEditor.setValue("");
elementEditor.setMinInputSize(10);
}
elementEditor = new LightUITextField(item.getId());
elementEditor.setValue("");
elementEditor.setMinInputSize(10);
elementEditor.setValueType(LightUIElement.VALUE_TYPE_STRING);
} else if (javaType.equals(Boolean.class)) {
elementEditor = new LightUICheckBox(item.getId(), "");
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTable.java
51,12 → 51,16
 
private int offset = 0;
 
private ITableModel model;
private transient ITableModel model;
 
private final ITransformer<SQLSelect, SQLSelect> orginTransformer;
private transient ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
private List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
private transient List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
 
public LightRowValuesTable() {
// Serialization
}
 
public LightRowValuesTable(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(id);
 
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java
27,7 → 27,6
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.group.Item;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.JSONToLightUIConvertor;
import org.openconcerto.ui.light.LightUICheckBox;
import org.openconcerto.ui.light.LightUIComboBox;
import org.openconcerto.ui.light.LightUIDate;
35,6 → 34,9
import org.openconcerto.ui.light.LightUIFrame;
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
52,6 → 54,10
 
private EditMode editMode = EditMode.READONLY;
 
public LightEditFrame() {
// Serialization
}
 
// Init from json constructor
public LightEditFrame(final JSONObject json) {
super(json);
176,18 → 182,20
}
}
 
final protected void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
protected final void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
final Map<String, CustomEditorProvider> customEditors) {
if (!uiElement.isNotSaved()) {
boolean useElementValue = true;
final Class<?> fieldType = sqlField.getType().getJavaType();
if (customEditors.containsKey(uiElement.getId())) {
final CustomEditorProvider customEditor = customEditors.get(uiElement.getId());
if (customEditor instanceof SavableCustomEditorProvider) {
((SavableCustomEditorProvider) customEditor).save(this.sqlRow, sqlField, uiElement);
} else {
throw new IllegalStateException(customEditor + " must implement SavableCustomEditorProvider for field " + sqlField.getFieldName() + " of tye " + fieldType);
useElementValue = false;
}
} else {
}
 
if (useElementValue) {
final String fieldName = sqlField.getFieldName();
if (sqlField.isKey()) {
if (!(uiElement instanceof LightUIComboBox)) {
297,12 → 305,16
final SQLTable sqlTable = this.sqlRow.getTable();
final Date now = new Date();
// FIXME only set those fields at insertion time
if (this.sqlRow.getObject(sqlTable.getCreationUserField().getName()) == null || this.sqlRow.getObject(sqlTable.getCreationDateField().getName()) == null) {
setFieldValue(this.sqlRow, sqlTable.getCreationUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getCreationDateField(), false, now);
if (sqlTable.getCreationUserField() != null) {
if (this.sqlRow.getObject(sqlTable.getCreationUserField().getName()) == null || this.sqlRow.getObject(sqlTable.getCreationDateField().getName()) == null) {
setFieldValue(this.sqlRow, sqlTable.getCreationUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getCreationDateField(), false, now);
}
}
setFieldValue(this.sqlRow, sqlTable.getModifUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getModifDateField(), false, now);
if (sqlTable.getModifUserField() != null) {
setFieldValue(this.sqlRow, sqlTable.getModifUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getModifDateField(), false, now);
}
}
 
static private boolean setFieldValue(final SQLRowValues vals, final SQLField f, final boolean remove, final Object val) {
321,17 → 333,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
 
@Override
public LightUIElement convert(JSONObject json) {
return new LightEditFrame(json);
}
};
}
 
@Override
public LightUIElement clone() {
return new LightEditFrame(this);
}
362,4 → 363,33
this.editMode = EditMode.READONLY;
}
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
if (this.editMode.equals(EditMode.CREATION)) {
out.writeByte(0);
} else if (this.editMode.equals(EditMode.MODIFICATION)) {
out.writeByte(1);
} else if (this.editMode.equals(EditMode.READONLY)) {
out.writeByte(2);
} else {
throw new IllegalStateException("unknown mode " + this.editMode);
}
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
int mode = in.readByte();
if (mode == 0) {
this.editMode = EditMode.CREATION;
} else if (mode == 1) {
this.editMode = EditMode.MODIFICATION;
} else if (mode == 2) {
this.editMode = EditMode.READONLY;
} else {
throw new IllegalStateException("unknown mode " + mode);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java
40,8 → 40,12
import net.minidev.json.JSONObject;
 
public class LightRowValuesTableOnline extends LightRowValuesTable {
private final ITransformer<SQLSelect, SQLSelect> orginTransformer;
private ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
public LightRowValuesTableOnline() {
// Serialization
}
 
public LightRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(configuration, userId, id, model);
 
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_fr.xml
1,6 → 1,7
<?xml version="1.0" encoding="UTF-8" ?>
<ROOT>
<TABLE name="USER_COMMON">
<translations>
<element refid="sql.user">
<name base="utilisateur" nounClass="masculine" />
<FIELD name="NOM" label="Nom" titlelabel="Nom" />
<FIELD name="PRENOM" label="Prénom" titlelabel="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" titlelabel="Mot de passe" />
11,18 → 12,22
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" titlelabel="Droits utilisateur" />
<FIELD name="MAIL" label="E-Mail" titlelabel="E-Mail" />
<FIELD name="DISABLED" label="Compte désactivé" />
<FIELD name="TEL" label="Téléphone" titlelabel="Téléphone" />
</TABLE>
<TABLE name="RIGHT">
<FIELD name="TEL" label="Téléphone" titlelabel="Téléphone" />
</element>
<element refid="sql.right">
<name base="droit" nounClass="masculine" />
<FIELD name="CODE" label="Code" titlelabel="Code" />
<FIELD name="NOM" label="Nom" titlelabel="Nom du droit" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</TABLE>
<TABLE name="USER_RIGHT">
</element>
<element refid="sql.user-right">
<name base="droit utilisateur" nounClass="masculine">
<variant refids="plural" value="droits utilisateurs" />
</name>
<FIELD name="ID_USER_COMMON" label="Utilisateur" titlelabel="Utilis." />
<FIELD name="ID_RIGHT" label="Droit" />
<FIELD name="OBJECT" label="Objet" />
<FIELD name="user.right.parameters.editor" label="Objet" />
<FIELD name="HAVE_RIGHT" label="Droit accordé" titlelabel="Accordé" />
</TABLE>
</ROOT>
</element>
</translations>
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_es.xml
Nouveau fichier
0,0 → 1,14
<?xml version="1.0" encoding="UTF-8" ?>
<translations>
<element refid="sql.user">
<name base="usuario" nounClass="masculine" />
</element>
<element refid="sql.right">
<name base="derecho" nounClass="masculine" />
</element>
<element refid="sql.user-right">
<name base="derecho de usuario" nounClass="masculine">
<variant refids="plural" value="derechos de usuarios" />
</name>
</element>
</translations>
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextArticleWithCompletionCellEditor.java
13,6 → 13,12
package org.openconcerto.sql.sqlobject;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.Component;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
23,12 → 29,6
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;
 
public class ITextArticleWithCompletionCellEditor extends AbstractCellEditor implements TableCellEditor {
 
private final ITextArticleWithCompletion text;
37,6 → 37,7
public ITextArticleWithCompletionCellEditor(SQLTable tableArticle, SQLTable tableARticleFournisseur) {
this.text = new ITextArticleWithCompletion(tableArticle, tableARticleFournisseur);
this.text.setBorder(BorderFactory.createEmptyBorder());
this.text.getTextComp().setBorder(BorderFactory.createEmptyBorder());
}
 
private void initListener(final JTable t) {
/trunk/OpenConcerto/src/org/openconcerto/sql/Configuration.java
126,7 → 126,9
 
public abstract SQLFilter getFilter();
 
public abstract SQLFieldTranslator getTranslator();
public final SQLFieldTranslator getTranslator() {
return this.getDirectory().getTranslator();
}
 
public abstract SQLElementDirectory getDirectory();
 
207,15 → 209,13
}
 
/**
* Add the translator and directory of <code>o</code> to this.
* Add the directory of <code>o</code> to this.
*
* @param o the configuration to add.
* @return this.
* @see SQLFieldTranslator#putAll(SQLFieldTranslator)
* @see SQLElementDirectory#putAll(SQLElementDirectory)
*/
public Configuration add(Configuration o) {
this.getTranslator().putAll(o.getTranslator());
this.getDirectory().putAll(o.getDirectory());
return this;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLFieldTranslator.java
17,6 → 17,7
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.element.SQLElementDirectory.DirectoryListener;
import org.openconcerto.sql.element.SQLElementNamesFromXML;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
34,10 → 35,10
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.i18n.Phrase;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
49,6 → 50,7
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.prefs.Preferences;
 
139,6 → 141,9
// { SQLTable -> { compCode, variant, item -> RowItemDesc }}
@GuardedBy("this")
private final Map<SQLTable, Map<List<String>, RowItemDesc>> translation;
// { element code -> { variant -> name }}
@GuardedBy("this")
private final Map<String, Map<String, Phrase>> elementNames;
private final SQLTable table;
private final SQLElementDirectory dir;
@GuardedBy("this")
146,6 → 151,7
 
{
this.translation = new HashMap<SQLTable, Map<List<String>, RowItemDesc>>();
this.elementNames = new HashMap<>();
this.unknownCodes = new HashSet<String>();
}
 
153,10 → 159,9
* Create a new instance.
*
* @param root the default root for tables.
* @param inputStream the XML, can be <code>null</code>.
* @param dir the directory where to look for tables not in <code>root</code>.
*/
public SQLFieldTranslator(DBRoot root, InputStream inputStream, SQLElementDirectory dir) {
public SQLFieldTranslator(DBRoot root, SQLElementDirectory dir) {
try {
this.table = getMetaTable(root);
} catch (SQLException e) {
180,8 → 185,6
}
}
});
if (inputStream != null)
this.load(root, inputStream);
fetchAndPut(this.table, null);
}
 
217,10 → 220,10
}
}
 
public void load(DBRoot b, File file) {
try {
load(b, new FileInputStream(file));
} catch (FileNotFoundException e) {
public void load(DBRoot b, File file, final SQLElementNamesFromXML elemNames) {
try (final InputStream ins = new FileInputStream(file)) {
this.load(b, ins, elemNames);
} catch (IOException e) {
e.printStackTrace();
}
}
229,14 → 232,8
return elem.getChildren();
}
 
/**
* Load more translations.
*
* @param b the default root for tables.
* @param inputStream the XML.
*/
public void load(DBRoot b, InputStream inputStream) {
this.load(b, CORE_VARIANT, inputStream);
public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, InputStream inputStream, final SQLElementNamesFromXML elemNames) {
return this.load(b, CORE_VARIANT, inputStream, elemNames);
}
 
/**
245,9 → 242,10
* @param b the default root for tables.
* @param variant the variant to use.
* @param inputStream the XML.
* @param elemNames how to load element names.
* @return the loaded tables and the names not found (and thus not loaded).
*/
public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, final String variant, InputStream inputStream) {
public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, final String variant, InputStream inputStream, final SQLElementNamesFromXML elemNames) {
if (inputStream == null)
throw new NullPointerException("inputStream is null");
final Set<SQLTable> res = new HashSet<SQLTable>();
259,19 → 257,19
final String elemName = elem.getName().toLowerCase();
final DBRoot root;
final List<Element> tableElems;
if (elemName.equals("table")) {
if (elemName.equals("table") || elemName.equals("element")) {
root = b;
tableElems = Collections.singletonList(elem);
} else if (elemName.equals("root")) {
root = b.getDBSystemRoot().getRoot(elem.getAttributeValue("name"));
tableElems = getChildren(elem);
} else {
if (elemName.equals("root")) {
Log.get().warning("Ignoring deprecated <root> element, use element code to refer to tables outside the default root");
}
root = null;
tableElems = null;
}
if (tableElems != null) {
for (final Element tableElem : tableElems) {
final Tuple2<String, SQLTable> t = load(root, variant, tableElem, true);
final Tuple2<String, SQLTable> t = load(root, variant, tableElem, elemNames, true);
if (t.get1() == null) {
notFound.add(t.get0());
} else {
290,11 → 288,19
return Tuple2.create(res, notFound);
}
 
private Tuple2<String, SQLTable> load(DBRoot b, final String variant, final Element tableElem, final boolean lenient) {
private Tuple2<String, SQLTable> load(DBRoot b, final String variant, final Element tableElem, final SQLElementNamesFromXML elemNames, final boolean lenient) {
final String tableName = tableElem.getAttributeValue("name");
SQLTable table = this.dir == null || this.dir.getElement(tableName) == null ? b.getTable(tableName) : this.dir.getElement(tableName).getTable();
if (table == null && this.dir != null && this.dir.getElementForCode(tableName) != null)
table = this.dir.getElementForCode(tableName).getTable();
String elemCode = tableElem.getAttributeValue("refid");
SQLTable table = null;
// compatibility mode for files without element names
final boolean compatMode = tableElem.getName().toLowerCase().equals("table");
if (compatMode) {
table = this.dir == null || this.dir.getElement(tableName) == null ? b.getTable(tableName) : this.dir.getElement(tableName).getTable();
if (elemCode == null)
elemCode = tableName;
}
if (table == null && this.dir != null && this.dir.getElementForCode(elemCode) != null)
table = this.dir.getElementForCode(elemCode).getTable();
if (table != null) {
for (final Element elem : getChildren(tableElem)) {
final String elemName = elem.getName().toLowerCase();
307,6 → 313,15
}
}
}
try {
if (!compatMode) {
final Entry<String, Phrase> phrase = elemNames.createPhrase(tableElem);
if (phrase != null)
this.putElementName(this.dir.getElement(table), phrase.getValue(), variant);
}
} catch (IOException e) {
throw new IllegalStateException("Couldn't parse phrase for " + table, e);
}
} else if (lenient) {
// allow to supply the union all tables and ignore those that aren't in a given base
Log.get().config("Ignore loading of inexistent table " + tableName);
568,4 → 583,45
}
this.removeTranslation(elemTable, componentCode, DB_VARIANT, name);
}
 
// ** element names
 
public final Phrase putElementName(final Class<? extends SQLElement> elemCl, final Phrase phr) {
return this.putElementName(this.getDirectory().getElement(elemCl), phr);
}
 
public final Phrase putElementName(final SQLElement elem, final Phrase phr) {
return this.putElementName(elem, phr, CORE_VARIANT);
}
 
public synchronized final Phrase putElementName(final SQLElement elem, final Phrase phr, final String variant) {
return this.getElementNameMap(elem, true).put(variant, phr);
}
 
private synchronized final Map<String, Phrase> getElementNameMap(final SQLElement elem, final boolean create) {
Map<String, Phrase> elemMap = this.elementNames.get(elem.getCode());
if (elemMap == null && create) {
elemMap = new HashMap<>();
this.elementNames.put(elem.getCode(), elemMap);
}
return elemMap;
}
 
public final Phrase getElementName(final SQLElement elem) {
return this.getElementName(elem, elem.getMDPath());
}
 
public final Phrase getElementName(final SQLElement elem, final List<String> variantPath) {
for (final String variant : variantPath) {
final Phrase res = this.getElementName(elem, variant);
if (res != null)
return res;
}
return this.getElementName(elem, CORE_VARIANT);
}
 
private synchronized final Phrase getElementName(final SQLElement elem, final String variant) {
final Map<String, Phrase> map = this.getElementNameMap(elem, false);
return map == null ? null : map.get(variant);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementNamesMap.java
Fichier supprimé
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementNames.java
Fichier supprimé
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
159,8 → 159,8
}
final Phrase res = new Phrase(Grammar_fr.getInstance(), base, nounClass);
if (nounClass != null)
res.putVariant(Grammar.INDEFINITE_ARTICLE_SINGULAR, singular);
res.putVariant(Grammar.PLURAL, plural);
res.putVariantIfDifferent(Grammar.INDEFINITE_ARTICLE_SINGULAR, singular);
res.putVariantIfDifferent(Grammar.PLURAL, plural);
return res;
}
 
184,9 → 184,7
 
@GuardedBy("this")
private SQLElementDirectory directory;
private String l18nPkgName;
private Class<?> l18nClass;
private Phrase name;
private Phrase defaultName;
private final SQLTable primaryTable;
// used as a key in SQLElementDirectory so it should be immutable
private String code;
233,7 → 231,6
throw new DBStructureItemNotFound("table is null for " + this.getClass());
}
this.primaryTable = primaryTable;
this.setL18nPackageName(null);
this.setDefaultName(name);
this.code = code == null ? createCode() : code;
this.combo = null;
256,7 → 253,11
 
/**
* Should return the code for this element. This method is only called if the <code>code</code>
* parameter of the constructor is <code>null</code>.
* parameter of the constructor is <code>null</code>. This implementation returns a string
* containing the {@link Class#getName() full name} of the class and the {@link #getTable()
* table} name to handle a single class being used for multiple tables. NOTE: this method is
* also needed, since a subclass constructor cannot pass <code>this.getClass().getName()</code>
* as the code parameter to <code>super</code>.
*
* @return the default code for this element.
*/
598,7 → 599,10
 
// return Path from owner to owned
private final Set<Path> createPaths(final boolean wantedOwned) {
assert !(this instanceof JoinSQLElement) : "joins cannot have SQLElementLink : " + this;
// joins cannot have SQLElementLink
if (this instanceof JoinSQLElement)
return Collections.emptySet();
 
final SQLTable thisTable = this.getTable();
final Set<Link> allLinks = thisTable.getDBSystemRoot().getGraph().getAllLinks(getTable());
final Set<Path> res = new HashSet<Path>();
754,21 → 758,26
private synchronized void initRF() {
if (this.otherLinks != null)
return;
 
final Set<Path> otherPaths = this.createPaths(false);
final SetMap<LinkType, SQLElementLink> tmp = new SetMap<LinkType, SQLElementLink>();
for (final Path p : otherPaths) {
final SQLElement refElem = this.getElementLenient(p.getFirst());
final SQLElementLink elementLink;
if (refElem == null) {
// RESTRICT : play it safe
elementLink = new SQLElementLink(null, p, this, LinkType.ASSOCIATION, null, ReferenceAction.RESTRICT);
} else {
elementLink = refElem.getOwnedLinks().getByPath(p);
assert elementLink.getOwned() == this;
if (otherPaths.isEmpty()) {
this.otherLinks = SQLElementLinks.empty();
} else {
final SetMap<LinkType, SQLElementLink> tmp = new SetMap<LinkType, SQLElementLink>();
for (final Path p : otherPaths) {
final SQLElement refElem = this.getElementLenient(p.getFirst());
final SQLElementLink elementLink;
if (refElem == null) {
// RESTRICT : play it safe
elementLink = new SQLElementLink(null, p, this, LinkType.ASSOCIATION, null, ReferenceAction.RESTRICT);
} else {
elementLink = refElem.getOwnedLinks().getByPath(p);
assert elementLink.getOwned() == this;
}
tmp.add(elementLink.getLinkType(), elementLink);
}
tmp.add(elementLink.getLinkType(), elementLink);
this.otherLinks = new SQLElementLinks(tmp);
}
this.otherLinks = new SQLElementLinks(tmp);
}
 
final void setDirectory(final SQLElementDirectory directory) {
812,36 → 821,7
return this.getTable().getBase().getGraph().getForeignTable(this.getTable().getField(foreignField));
}
 
public final synchronized String getL18nPackageName() {
return this.l18nPkgName;
}
 
public final synchronized Class<?> getL18nClass() {
return this.l18nClass;
}
 
public final void setL18nLocation(Class<?> clazz) {
this.setL18nLocation(clazz.getPackage().getName(), clazz);
}
 
public final void setL18nPackageName(String name) {
this.setL18nLocation(name, null);
}
 
/**
* Set the location for the localized name.
*
* @param name a package name, can be <code>null</code> :
* {@link SQLElementDirectory#getL18nPackageName()} will be used.
* @param ctxt the class loader to load the resource, <code>null</code> meaning this class.
* @see SQLElementDirectory#getName(SQLElement)
*/
public final synchronized void setL18nLocation(final String name, final Class<?> ctxt) {
this.l18nPkgName = name;
this.l18nClass = ctxt == null ? this.getClass() : ctxt;
}
 
/**
* Set the default name, used if no translations could be found.
*
* @param name the default name, if <code>null</code> the {@link #getTable() table} name will be
848,7 → 828,7
* used.
*/
public final synchronized void setDefaultName(Phrase name) {
this.name = name != null ? name : Phrase.getInvariant(getTable().getName());
this.defaultName = name != null ? name : Phrase.getInvariant(getTable().getName());
}
 
/**
857,7 → 837,7
* @return the default name, never <code>null</code>.
*/
public final synchronized Phrase getDefaultName() {
return this.name;
return this.defaultName;
}
 
/**
869,7 → 849,8
*/
public final Phrase getName() {
final SQLElementDirectory dir = this.getDirectory();
final Phrase res = dir == null ? null : dir.getName(this);
final SQLFieldTranslator trns = dir == null ? null : dir.getTranslator();
final Phrase res = trns == null ? null : trns.getElementName(this);
return res == null ? this.getDefaultName() : res;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/ConfSQLElement.java
25,21 → 25,6
*/
public class ConfSQLElement extends SQLElement {
 
@Deprecated
public ConfSQLElement(String tableName, String singular, String plural) {
this(Configuration.getInstance(), tableName, singular, plural);
}
 
@Deprecated
public ConfSQLElement(Configuration conf, String tableName, String singular, String plural) {
this(conf.getRoot().findTable(tableName), singular, plural);
}
 
@Deprecated
public ConfSQLElement(SQLTable table, String singular, String plural) {
super(singular, plural, table);
}
 
public ConfSQLElement(String tableName) {
this(tableName, null);
}
48,22 → 33,30
this(conf, tableName, null);
}
 
public ConfSQLElement(SQLTable table) {
this(table, null);
}
 
public ConfSQLElement(String tableName, final Phrase name) {
this(Configuration.getInstance(), tableName, name);
}
 
public ConfSQLElement(Configuration conf, String tableName, final Phrase name) {
this(conf.getRoot().findTable(tableName), name);
this(conf, tableName, name, null);
}
 
public ConfSQLElement(Configuration conf, String tableName, final Phrase name, final String code) {
this(conf.getRoot().findTable(tableName), name, code);
}
 
public ConfSQLElement(final SQLTable table) {
this(table, null);
}
 
public ConfSQLElement(final SQLTable primaryTable, final Phrase name) {
super(primaryTable, name);
this(primaryTable, name, null);
}
 
public ConfSQLElement(final SQLTable primaryTable, final Phrase name, final String code) {
super(primaryTable, name, code);
}
 
@Override
protected List<String> getComboFields() {
return Collections.emptyList();
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
15,7 → 15,6
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.ShowAs;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItemNotFound;
import org.openconcerto.sql.model.SQLName;
25,12 → 24,7
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.i18n.LocalizedInstances;
import org.openconcerto.utils.i18n.Phrase;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
37,13 → 31,10
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
 
import org.jdom2.JDOMException;
 
import net.jcip.annotations.GuardedBy;
 
/**
53,29 → 44,6
*/
public final class SQLElementDirectory {
 
public static final String BASENAME = SQLElementNames.class.getSimpleName();
private static final LocalizedInstances<SQLElementNames> LOCALIZED_INSTANCES = new LocalizedInstances<SQLElementNames>(SQLElementNames.class, TranslationManager.getControl()) {
@Override
protected SQLElementNames createInstance(String bundleName, Locale candidate, Class<?> cl) throws IOException {
final InputStream ins = cl.getResourceAsStream('/' + getControl().toResourceName(bundleName, "xml"));
if (ins == null)
return null;
final SQLElementNamesFromXML res = new SQLElementNamesFromXML(candidate);
try {
res.load(ins);
} catch (JDOMException e) {
throw new IOException("Invalid XML", e);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
} finally {
ins.close();
}
return res;
}
};
 
private final Map<SQLTable, SQLElement> elements;
private final SetMap<String, SQLTable> tableNames;
private final SetMap<String, SQLTable> byCode;
83,7 → 51,6
private final List<DirectoryListener> listeners;
 
private String phrasesPkgName;
private final Map<String, SQLElementNames> elementNames;
 
@GuardedBy("this")
private SQLFieldTranslator translator;
100,7 → 67,6
this.listeners = new ArrayList<DirectoryListener>();
 
this.phrasesPkgName = null;
this.elementNames = new HashMap<String, SQLElementNames>();
 
this.showAs = new ShowAs((DBRoot) null);
}
152,17 → 118,26
* @param element the element to add.
*/
public final void addSQLElement(final Class<? extends SQLElement> element) {
this.addSQLElement(element, null);
}
 
public final void addSQLElement(final Class<? extends SQLElement> element, final DBRoot root) {
final SQLElement newInstance;
try {
this.addSQLElement(element.getConstructor().newInstance());
if (root == null)
newInstance = element.getConstructor().newInstance();
else
newInstance = element.getConstructor(DBRoot.class).newInstance(root);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof DBStructureItemNotFound) {
Log.get().config("ignore inexistent tables: " + e.getCause().getLocalizedMessage());
return;
}
throw new IllegalArgumentException("ctor failed", e);
throw new IllegalArgumentException("Constructor failed", e);
} catch (Exception e) {
throw new IllegalArgumentException("no-arg ctor failed", e);
throw new IllegalArgumentException("Couldn't use constructor", e);
}
this.addSQLElement(newInstance);
}
 
/**
293,43 → 268,6
return this.phrasesPkgName;
}
 
protected synchronized final SQLElementNames getElementNames(final String pkgName, final Locale locale, final Class<?> cl) {
if (pkgName == null)
return null;
final char sep = ' ';
final String key = pkgName + sep + locale.toString();
assert pkgName.indexOf(sep) < 0 : "ambiguous key : " + key;
SQLElementNames res = this.elementNames.get(key);
if (res == null) {
final List<SQLElementNames> l = LOCALIZED_INSTANCES.createInstances(pkgName + "." + BASENAME, locale, cl).get1();
if (!l.isEmpty()) {
for (int i = 1; i < l.size(); i++) {
l.get(i - 1).setParent(l.get(i));
}
res = l.get(0);
}
this.elementNames.put(key, res);
}
return res;
}
 
/**
* Search a name for the passed instance and the {@link TM#getTranslationsLocale() current
* locale}. Search for {@link SQLElementNames} using {@link LocalizedInstances} and
* {@link SQLElementNamesFromXML} first in {@link SQLElement#getL18nPackageName()} then in
* {@link #getL18nPackageName()}. E.g. this could load SQLElementNames_en.class and
* SQLElementNames_en_UK.xml.
*
* @param elem the element.
* @return the name if found, <code>null</code> otherwise.
*/
public final Phrase getName(final SQLElement elem) {
final String elemBaseName = elem.getL18nPackageName();
final String pkgName = elemBaseName == null ? getL18nPackageName() : elemBaseName;
final SQLElementNames elementNames = getElementNames(pkgName, TM.getInstance().getTranslationsLocale(), elem.getL18nClass());
return elementNames == null ? null : elementNames.getName(elem);
}
 
public synchronized final void addListener(DirectoryListener dl) {
this.listeners.add(dl);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SharedSQLElement.java
13,6 → 13,7
package org.openconcerto.sql.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLTable;
 
/**
26,10 → 27,18
super(tableName);
}
 
public SharedSQLElement(final Configuration conf, String tableName, final String code) {
super(conf, tableName, null, code);
}
 
public SharedSQLElement(SQLTable table) {
super(table);
this(table, null);
}
 
public SharedSQLElement(final SQLTable table, final String code) {
super(table, null, code);
}
 
@Override
public final boolean isShared() {
return true;
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementNamesFromXML.java
23,8 → 23,13
import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Pattern;
 
import org.jdom2.Document;
50,27 → 55,61
*
*/
@ThreadSafe
public class SQLElementNamesFromXML extends SQLElementNamesMap.ByCode {
public class SQLElementNamesFromXML {
 
static public final Pattern SPLIT_PATTERN = Pattern.compile("\\s*,\\s*");
static private final Set<Object> SHORT_VARIANTS = Collections.singleton(Grammar.PLURAL);
 
private static final String ELEMENT_ELEM_NAME = "element";
private static final String NAME_ID_ATTR = "refid";
private static final String VARIANT_ATTR = "variant";
private static final String VARIANT_REFIDS_ATTR = "refids";
private static final String VARIANT_VALUE_ATTR = "value";
private static final String NAME_PLURAL_ATTR = "namePlural";
 
static private final String getNounClassAttrName(final boolean shortForm) {
return shortForm ? "nameClass" : "nounClass";
}
 
// <element nameClass="masculine" name="contact fournisseur">
// <name nounClass="masculine" base="droit utilisateur">
static final private void setNounClassAndBase(final Element elem, final Phrase phrase, final boolean shortForm) {
elem.setAttribute(getNounClassAttrName(shortForm), phrase.getNounClass().getName());
elem.setAttribute(shortForm ? "name" : "base", phrase.getBase());
}
 
private final Locale locale;
 
public SQLElementNamesFromXML(Locale locale) {
super(locale);
this.locale = locale;
}
 
public final void load(final InputStream ins) throws JDOMException, IOException {
final Grammar gr = Grammar.getInstance(getLocale());
public final Locale getLocale() {
return this.locale;
}
 
public final Map<String, Phrase> load(final InputStream ins) throws JDOMException, IOException {
final Document doc = new SAXBuilder().build(ins);
for (final Element elem : doc.getRootElement().getChildren("element"))
this.load(gr, elem);
return load(doc.getRootElement());
}
 
public final Map<String, Phrase> load(final Element root) throws IOException {
final Grammar gr = Grammar.getInstance(getLocale());
final Map<String, Phrase> res = new HashMap<>();
for (final Element elem : root.getChildren(ELEMENT_ELEM_NAME)) {
final Entry<String, Phrase> e = this.createPhrase(gr, elem);
if (e != null)
res.put(e.getKey(), e.getValue());
}
return res;
}
 
public final Entry<String, Phrase> createPhrase(final Element elem) throws IOException {
return this.createPhrase(Grammar.getInstance(getLocale()), elem);
}
 
private Entry<String, Phrase> createPhrase(final Grammar gr, final Element elem) throws IOException {
final String refid = elem.getAttributeValue("refid");
final String refid = elem.getAttributeValue(NAME_ID_ATTR);
if (refid == null)
throw new IOException("No refid attribute");
 
78,7 → 117,8
final boolean hasChild = nameElem != null;
final String nameAttr = elem.getAttributeValue("name");
if (!hasChild && nameAttr == null) {
Log.get().warning("No name for code : " + refid);
// perhaps elem is just used to change item names
Log.get().log(Level.FINER, "No name for code : {0}", refid);
return null;
}
if (hasChild && nameAttr != null) {
88,23 → 128,23
final String base = hasChild ? nameElem.getAttributeValue("base") : nameAttr;
if (base == null)
throw new IOException("No base for the name of " + refid);
final String nounClassName = hasChild ? nameElem.getAttributeValue("nounClass") : elem.getAttributeValue("nameClass");
final String nounClassName = (hasChild ? nameElem : elem).getAttributeValue(getNounClassAttrName(!hasChild));
final NounClass nounClass = nounClassName == null ? null : gr.getNounClass(nounClassName);
 
final Phrase res = new Phrase(gr, base, nounClass);
if (!hasChild) {
// most languages have at most 2 grammatical number
final String plural = elem.getAttributeValue("namePlural");
final String plural = elem.getAttributeValue(NAME_PLURAL_ATTR);
if (plural != null)
res.putVariant(Grammar.PLURAL, plural);
} else {
for (final Element variantElem : nameElem.getChildren("variant")) {
final String value = variantElem.getAttributeValue("value");
for (final Element variantElem : nameElem.getChildren(VARIANT_ATTR)) {
final String value = variantElem.getAttributeValue(VARIANT_VALUE_ATTR);
if (value == null) {
warning(refid, variantElem, "No value");
continue;
}
final String variantIDs = variantElem.getAttributeValue("refids");
final String variantIDs = variantElem.getAttributeValue(VARIANT_REFIDS_ATTR);
final String variantPattern = variantElem.getAttributeValue("idPattern");
if (variantIDs == null && variantPattern == null) {
warning(refid, variantElem, "No ID");
134,13 → 174,35
return new SimpleEntry<String, Phrase>(refid, res);
}
 
private void load(final Grammar gr, final Element elem) throws IOException {
final Entry<String, Phrase> entry = this.createPhrase(gr, elem);
if (entry != null)
this.put(entry.getKey(), entry.getValue());
}
 
private void warning(final String refid, final Element variantElem, final String msg) {
Log.get().warning(msg + " for variant of " + refid + " : " + JDOM2Utils.output(variantElem));
}
 
public final Element createElement(final String refID, final Phrase phrase) {
final Element elem = new Element(ELEMENT_ELEM_NAME);
elem.setAttribute(NAME_ID_ATTR, refID);
final Set<VariantKey> explicitVariants = phrase.getExplicitVariants();
final boolean shortForm = SHORT_VARIANTS.containsAll(explicitVariants);
final Element nameElem;
if (shortForm) {
nameElem = elem;
} else {
nameElem = new Element("name");
elem.addContent(nameElem);
}
setNounClassAndBase(nameElem, phrase, shortForm);
if (!shortForm) {
// <variant refids="plural" value="droits utilisateurs"
for (final VariantKey explicitVariant : explicitVariants) {
final Element variantElem = new Element(VARIANT_ATTR);
variantElem.setAttribute(VARIANT_REFIDS_ATTR, explicitVariant.getID());
variantElem.setAttribute(VARIANT_VALUE_ATTR, phrase.getVariant(explicitVariant));
nameElem.addContent(variantElem);
}
} else if (explicitVariants.contains(Grammar.PLURAL)) {
elem.setAttribute(NAME_PLURAL_ATTR, phrase.getVariant(Grammar.PLURAL));
}
return elem;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/SQLElementNames_en.xml
Fichier supprimé
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/SQLElementNames_fr.xml
Fichier supprimé
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_en.properties
69,7 → 69,18
editFrame.look=Details of {element__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html>
listPanel.cloneRows=Do you want to clone {rowCount, plural, one {this row{rec, select, true { and its content} other {}}} other {these # rows{rec, select, true { and their contents} other {}}}} ?
listPanel.cloneRows=Do you want to clone {rec, select,\
true {\
{rowCount, plural,\
one {this row and its content ?}\
other {these # rows and their content ?}\
}}\
other {\
{rowCount, plural,\
one {this row ?}\
other {these # rows ?}\
}}\
}
listPanel.noSelectionOrSort=No selection or list sorted
listPanel.export=List export
listPanel.save=Save the list
87,8 → 98,10
ilist.unlockRows=Unlock rows
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}}
 
sqlComp.stringValueTooLong=The value is {0} character{0,choice,1#|1<s} too long
sqlComp.bdTooHigh=Number too high, it must have at most {0} digit{0,choice,1#|1<s} before the decimal point ({1} after)
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}}
sqlComp.bdTooHigh=Number too high, {0, plural,\
one {it must have at most # digit before the decimal point ({1} after)}\
other {it must have at most # digits before the decimal point ({1} after)}}
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} is empty
sqlComp.insertError=Error while inserting
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_es.properties
Nouveau fichier
0,0 → 1,199
init.error=Error de inicialización
add=Añadir
saveModifications=Guardar cambios
display=Ver
modify=Editar
delete=Limpiar
remove=Borrar
close=Cerrar
cancel=Cancelar
search=Buscar
open=Abrir
save=Guardar
backup=Hacer la copia de seguridad
export=Exportar
noSelection=Sin selección
duplicate=Duplicar
duplication=Duplicación
location=Ubicación
choose=Elige
toApply=Aplicar
 
all=Todo
toReverse=Revertir
 
contains=Contiene
contains.exactly=Contiene exactamente
isLessThan=Es menos de
isLessThanOrEqualTo=Es menor o igual a
isEqualTo=Es igual a
isExactlyEqualTo=Es exactamente igual a
isGreaterThan=Es más de
isGreaterThanOrEqualTo=Es más o igual a
isEmpty=Esta vacio
 
clone.newPlace=Nueva ubicación (opcional) :
 
saveError=Error al guardar
 
loginPanel.storePass=Almacenar contraseña
loginPanel.loginAction=Iniciar sesión
loginPanel.adminLogin=Administrador
loginPanel.loginLabel=Nombre de usuario
loginPanel.passLabel=Contraseña
loginPanel.companyLabel=Empresa
loginPanel.disabledUser=Cuenta de usuario deshabilitada
loginPanel.unknownUser=Usuario desconocido
loginPanel.multipleUser=Múltiples usuarios nombrados "{0}"
loginPanel.wrongPass=Contraseña incorrecta
 
noRightToAdd=No puedes agregar
noRightToModify=No puedes editar
noRightToDel=No puedes borrar
noRightToClone=No puedes duplicar
noRightToReorder=No puedes cambiar la orden
 
 
editPanel.keepOpen=No cerrar ventana
editPanel.readOnlySelection=This row is read only
editPanel.localPrivateSelection=This row is used by another item
editPanel.inexistentElement=this item doesn't exist
editPanel.cancelError=Error while canceling
editPanel.modifyError=Error while modifying
editPanel.addError=Error while adding
editPanel.deleteError=Error while deleting
editPanel.invalidContent=Input fields aren''t filled correctly.\n\nYou cannot save modifications :
editPanel.invalidContent.unknownReason= they aren''t valid
 
editAction.name=Crear {element__singularIndefiniteArticle}
editFrame.create=Crear {element__singularIndefiniteArticle}
editFrame.modify=Modificar {element__singularIndefiniteArticle}
editFrame.look=Detalles de {element__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html>
listPanel.cloneRows=listPanel.cloneRows=Do you want to clone {rec, select,\
true {\
{rowCount, plural,\
one {this row and its content ?}\
other {these # rows and their content ?}\
}}\
other {\
{rowCount, plural,\
one {this row ?}\
other {these # rows ?}\
}}\
}
listPanel.clone.collectingData=Collecting data for {0,plural,one{# row} other{# rows}}\u2026
listPanel.clone.storingData=Storing {0,plural,one{# row} other{# rows}}\u2026
listPanel.noSelectionOrSort=No selection or list sorted
listPanel.export=List export
listPanel.save=Save the list
listPanel.wholeList=the whole list
listPanel.selection=the selection
listPanel.duplicationError=Couldn''t duplicate {0}
 
listAction.name=Manage {element__pluralDefiniteArticle}
element.list=Lista de {element__plural}
 
ilist.setColumnsWidth=Ajustar ancho columnas
ilist.showAllColumns=Ver todas las columnas
ilist.lastCol=Cannot hide the last column
ilist.lockRows=Lock rows
ilist.unlockRows=Unlock rows
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}}
 
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}}
sqlComp.bdTooHigh=Number too high, {0, plural,\
one {it must have at most # digit before the decimal point ({1} after)}\
other {it must have at most # digits before the decimal point ({1} after)}}
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} is empty
sqlComp.insertError=Error while inserting
sqlComp.insertCancelled=Insertion cancelled
sqlComp.selectError=Error while displaying {0}
sqlComp.updateError=Error while updating
sqlComp.updateCancelled=Update cancelled
sqlComp.updateCancelled.archived=The row was archived
sqlComp.updateCancelled.moreArchivedRows=The database was modified (there are more rows to be archived)
sqlComp.rowsToArchiveError=Error while searching data to archive {0}
sqlComp.archiveError=Error while archiving
sqlComp.archiveCancelled=Archive cancelled
sqlComp.saveDocError=Error while saving documentation of {0}
sqlComp.modifyDoc=Modify the documentation
sqlComp.deletedRow=The row is no longer in the database : {0}
 
sqlElement.archive.computingRows=Computing rows to archive\u2026
sqlElement.archiveError=Error while archiving {0} IDs {1}
sqlElement.confirmDelete=Confirm deletion
sqlElement.deleteNoRef=Do you want to delete {rowCount, plural, one {this row} other {these # rows}} ?
sqlElement.deleteRef.details= {descsSize, plural, =0 {} other\
{{rowCount, plural, one {This row is used} other {These rows are used}} by :\n\
{descs}}}\
{externsSize, plural, =0 {} other {{descsSize, plural, =0 {The} other {\n\nFurther the}} following links will be IRRETRIEVABLY cut : \n\
{externs}}}\n\n
sqlElement.deleteRef.details2=The following links will be IRRETRIEVABLY cut, they couldn\u2019t be 'unarchived' :\n\
{externs}\n\n
sqlElement.deleteRef=Do you{times, select, once {} other { REALLY}} want to delete {rowCount, plural, one {this row} other {these # rows}} and all linked ones ?
sqlElement.noLinesDeleted=No lines deleted.
sqlElement.noLinesDeletedTitle=Information
sqlElement.linksWillBeCut=- {elementName__indefiniteNumeral} {count, plural, one {will lose its} other {will lose their}} "{linkName}"
sqlElement.linkCantBeCut={rowDesc} cannot lose its field "{fieldLabel}"
 
sqlElement.deletePrivateNoRef={elementName__indefiniteNumeral} {elementNameCount, plural, one {is to be deleted} other {are to be deleted}}.
 
sqlElement.deletePrivateRef.details=The removal of {elementName__indefiniteNumeral} will cause :\n\
{descsSize, plural, =0 {} other {{descs}\n}}\
{externs}
sqlElement.deletePrivateRef.desc=- the removal of {elementName__indefiniteNumeral}
sqlElement.deletePrivateRef.linksWillBeCut=- the permanent deletion of the field "{linkName}" for {elementName__indefiniteNumeral}
 
sqlElement.modify.deletePrivate=\n\nModify {elementName__singularDemonstrative} and delete the informations listed above ?
 
user.passwordsDontMatch=Passwords don\u2019t match
user.passwordsDontMatch.short=Passwords don\u2019t match
 
infoPanel.rights=Rights enabled
infoPanel.appName=Application name
infoPanel.noAppName=unknown
infoPanel.version=Application version
infoPanel.noVersion=unknown
infoPanel.secureLink=Secure link
infoPanel.dbURL=Database URL
infoPanel.dirs=Folders
infoPanel.logs=Logs
infoPanel.docs=Documents
infoPanel.dataDir=Data
infoPanel.prefsDir=Preferences
infoPanel.cacheDir=Cache
 
infoPanel.softwareTitle=Software
infoPanel.systemTitle=System information
infoPanel.refresh=Click to refresh
 
backupPanel.backup=Backup
backupPanel.createFolderError=Couldn't create destination folder. Backup canceled !
backupPanel.folderRightsError=Insufficient rights on destination folder. Backup canceled !
backupPanel.errorsOnLastBackup=Errors occurred on last backup. Please contact IT.
backupPanel.lastBackup=Last backup {date, date, long} at {date, time, short}\non {destination}
backupPanel.differentDisks=Please backup on different disks !
backupPanel.progress=Backup progress
backupPanel.inProgress=Backup in progress
backupPanel.closingIn=Closing in {0}s
backupPanel.endFail=Backup ended with errors !
backupPanel.endSuccess=Backup ended successfully
backupPanel.failed=Backup failed
 
rights=Rights
rightsPanel.defaultRights=Default rights
rights.allTables=All tables
 
combo.list=List {element__pluralDefiniteArticle}
 
joinComp.usedBy=Cannot delete selection, it is used by "{0}"
 
browserCol.content=Content of {element__pluralDefiniteArticle}
 
addNewLine=Añadir nueva línea
insertNewLine=Insertar línea
duplicateLine=Duplicar líneas seleccionadas
deleteLine=Eliminar líneas seleccionadas
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_fr.properties
69,8 → 69,18
editFrame.look=Détail {element__de__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Permet de dupliquer une ligne.<br>Maintenir CTRL enfoncé pour dupliquer également le contenu<br>Maintenir Maj. enfoncé pour changer d'emplacement.</html>
listPanel.cloneRows=Voulez-vous cloner {rowCount, plural, one {cette ligne{rec, select, true { et son contenu} other {}}}\
other {ces # lignes{rec, select, true { et leurs contenus} other {}}}} ?
listPanel.cloneRows=Voulez-vous cloner {rec, select,\
true {\
{rowCount, plural,\
one {cette ligne et son contenu ?}\
other {ces # lignes et leurs contenus ?}\
}}\
other {\
{rowCount, plural,\
one {cette ligne ?}\
other {ces # lignes ?}\
}}\
}
listPanel.noSelectionOrSort=Pas de sélection ou liste triée
listPanel.export=Export de la liste
listPanel.save=Sauver la liste
88,8 → 98,10
ilist.unlockRows=Déverrouiller les lignes
ilist.metadata={0,choice,0#Modifiée|1#Créée}{1,choice,0#|1# par {2} {3}}{4,choice,0#|1# le {5,date,long} à {5,time,medium}}
 
sqlComp.stringValueTooLong=La valeur fait {0} caractère{0,choice,1#|1<s} de trop
sqlComp.bdTooHigh=Nombre trop grand, il doit faire moins de {0} chiffre{0,choice,1#|1<s} avant la virgule ({1} après)
sqlComp.stringValueTooLong=La valeur fait {0, plural, one {# caractère de trop} other {# caractères de trop}}
sqlComp.bdTooHigh=Nombre trop grand, {0, plural,\
one {il doit faire moins d\u2019un chiffre avant la virgule ({1} après)}\
other {il doit faire moins de # chiffres avant la virgule ({1} après)}}
sqlComp.invalidItem={0} n''est pas valide{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} est vide
sqlComp.insertError=Impossible d''insérer
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_pl.properties
Nouveau fichier
0,0 → 1,198
init.error=Initialization error
add=Add
saveModifications=Save modifications
display=Display
modify=Modify
delete=Delete
remove=Remove
close=Close
cancel=Cancel
search=Search
open=Open
save=Save
backup=Backup
export=Export
noSelection=No selection
duplicate=Duplicate
duplication=Duplication
location=Location
choose=Choose
toApply=Apply
 
all=All
toReverse=Reverse
 
contains=Contains
contains.exactly=Contains exactly
isLessThan=Is less than
isLessThanOrEqualTo=Is less than or equal to
isEqualTo=Is equal to
isExactlyEqualTo=Is exactly equal to
isGreaterThan=Is greater than
isGreaterThanOrEqualTo=Is greater than or equal to
isEmpty=Is empty
 
clone.newPlace=New location (optional) :
 
saveError=Error while saving
 
loginPanel.storePass=Store password
loginPanel.loginAction=Log in
loginPanel.adminLogin=Administrator
loginPanel.loginLabel=Login
loginPanel.passLabel=Password
loginPanel.companyLabel=Company
loginPanel.disabledUser=Disabled user account
loginPanel.unknownUser=Unknown user
loginPanel.multipleUser=Multiple users named "{0}"
loginPanel.wrongPass=Wrong password
 
noRightToAdd=You''re not allowed to add
noRightToModify=You''re not allowed to modify
noRightToDel=You''re not allowed to delete
noRightToClone=You''re not allowed to duplicate
noRightToReorder=You''re not allowed to change order
 
editPanel.keepOpen=don''t close the window
editPanel.readOnlySelection=This row is read only
editPanel.localPrivateSelection=This row is used by another item
editPanel.inexistentElement=this item doesn't exist
editPanel.cancelError=Error while canceling
editPanel.modifyError=Error while modifying
editPanel.addError=Error while adding
editPanel.deleteError=Error while deleting
editPanel.invalidContent=Input fields aren''t filled correctly.\n\nYou cannot save modifications :
editPanel.invalidContent.unknownReason= they aren''t valid
 
editAction.name=Create {element__singularIndefiniteArticle}
editFrame.create=Create {element__singularIndefiniteArticle}
editFrame.modify=Modify {element__singularIndefiniteArticle}
editFrame.look=Details of {element__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html>
listPanel.cloneRows=Do you want to clone {rec, select,\
true {\
{rowCount, plural,\
one {this row and its content ?}\
other {these # rows and their content ?}\
}}\
other {\
{rowCount, plural,\
one {this row ?}\
other {these # rows ?}\
}}\
}
listPanel.clone.collectingData=Collecting data for {0,plural,one{# row} other{# rows}}\u2026
listPanel.clone.storingData=Storing {0,plural,one{# row} other{# rows}}\u2026
listPanel.noSelectionOrSort=No selection or list sorted
listPanel.export=List export
listPanel.save=Save the list
listPanel.wholeList=the whole list
listPanel.selection=the selection
listPanel.duplicationError=Couldn''t duplicate {0}
 
listAction.name=Manage {element__pluralDefiniteArticle}
element.list=List of {element__plural}
 
ilist.setColumnsWidth=Adjust columns widths
ilist.showAllColumns=Show all columns
ilist.lastCol=Cannot hide the last column
ilist.lockRows=Lock rows
ilist.unlockRows=Unlock rows
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}}
 
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}}
sqlComp.bdTooHigh=Number too high, {0, plural,\
one {it must have at most # digit before the decimal point ({1} after)}\
other {it must have at most # digits before the decimal point ({1} after)}}
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} is empty
sqlComp.insertError=Error while inserting
sqlComp.insertCancelled=Insertion cancelled
sqlComp.selectError=Error while displaying {0}
sqlComp.updateError=Error while updating
sqlComp.updateCancelled=Update cancelled
sqlComp.updateCancelled.archived=The row was archived
sqlComp.updateCancelled.moreArchivedRows=The database was modified (there are more rows to be archived)
sqlComp.rowsToArchiveError=Error while searching data to archive {0}
sqlComp.archiveError=Error while archiving
sqlComp.archiveCancelled=Archive cancelled
sqlComp.saveDocError=Error while saving documentation of {0}
sqlComp.modifyDoc=Modify the documentation
sqlComp.deletedRow=The row is no longer in the database : {0}
 
sqlElement.archive.computingRows=Computing rows to archive\u2026
sqlElement.archiveError=Error while archiving {0} IDs {1}
sqlElement.confirmDelete=Confirm deletion
sqlElement.deleteNoRef=Do you want to delete {rowCount, plural, one {this row} other {these # rows}} ?
sqlElement.deleteRef.details= {descsSize, plural, =0 {} other\
{{rowCount, plural, one {This row is used} other {These rows are used}} by :\n\
{descs}}}\
{externsSize, plural, =0 {} other {{descsSize, plural, =0 {The} other {\n\nFurther the}} following links will be IRRETRIEVABLY cut : \n\
{externs}}}\n\n
sqlElement.deleteRef.details2=The following links will be IRRETRIEVABLY cut, they couldn\u2019t be 'unarchived' :\n\
{externs}\n\n
sqlElement.deleteRef=Do you{times, select, once {} other { REALLY}} want to delete {rowCount, plural, one {this row} other {these # rows}} and all linked ones ?
sqlElement.noLinesDeleted=No lines deleted.
sqlElement.noLinesDeletedTitle=Information
sqlElement.linksWillBeCut=- {elementName__indefiniteNumeral} {count, plural, one {will lose its} other {will lose their}} "{linkName}"
sqlElement.linkCantBeCut={rowDesc} cannot lose its field "{fieldLabel}"
 
sqlElement.deletePrivateNoRef={elementName__indefiniteNumeral} {elementNameCount, plural, one {is to be deleted} other {are to be deleted}}.
 
sqlElement.deletePrivateRef.details=The removal of {elementName__indefiniteNumeral} will cause :\n\
{descsSize, plural, =0 {} other {{descs}\n}}\
{externs}
sqlElement.deletePrivateRef.desc=- the removal of {elementName__indefiniteNumeral}
sqlElement.deletePrivateRef.linksWillBeCut=- the permanent deletion of the field "{linkName}" for {elementName__indefiniteNumeral}
 
sqlElement.modify.deletePrivate=\n\nModify {elementName__singularDemonstrative} and delete the informations listed above ?
 
user.passwordsDontMatch=Passwords don\u2019t match
user.passwordsDontMatch.short=Passwords don\u2019t match
 
infoPanel.rights=Rights enabled
infoPanel.appName=Application name
infoPanel.noAppName=unknown
infoPanel.version=Application version
infoPanel.noVersion=unknown
infoPanel.secureLink=Secure link
infoPanel.dbURL=Database URL
infoPanel.dirs=Folders
infoPanel.logs=Logs
infoPanel.docs=Documents
infoPanel.dataDir=Data
infoPanel.prefsDir=Preferences
infoPanel.cacheDir=Cache
 
infoPanel.softwareTitle=Software
infoPanel.systemTitle=System information
infoPanel.refresh=Click to refresh
 
backupPanel.backup=Backup
backupPanel.createFolderError=Couldn't create destination folder. Backup canceled !
backupPanel.folderRightsError=Insufficient rights on destination folder. Backup canceled !
backupPanel.errorsOnLastBackup=Errors occurred on last backup. Please contact IT.
backupPanel.lastBackup=Last backup {date, date, long} at {date, time, short}\non {destination}
backupPanel.differentDisks=Please backup on different disks !
backupPanel.progress=Backup progress
backupPanel.inProgress=Backup in progress
backupPanel.closingIn=Closing in {0}s
backupPanel.endFail=Backup ended with errors !
backupPanel.endSuccess=Backup ended successfully
backupPanel.failed=Backup failed
 
rights=Rights
rightsPanel.defaultRights=Default rights
rights.allTables=All tables
 
combo.list=List {element__pluralDefiniteArticle}
 
joinComp.usedBy=Cannot delete selection, it is used by "{0}"
 
browserCol.content=Content of {element__pluralDefiniteArticle}
 
addNewLine=Add a new line
insertNewLine=Insert a line
duplicateLine=Duplicate selected lines
deleteLine=Remove selected lines
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrder.java
13,11 → 13,13
package org.openconcerto.sql.utils;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLSystem;
24,6 → 26,9
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple2.List2;
import org.openconcerto.utils.convertor.NumberConvertor;
 
import java.math.BigDecimal;
30,9 → 35,13
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
 
import net.jcip.annotations.GuardedBy;
 
/**
* Reorder some or all rows of a table.
*
40,6 → 49,161
*/
public abstract class ReOrder {
 
@GuardedBy("this")
private static boolean AUTO_FIX_NULLS = false;
 
public static synchronized void setAutoFixNulls(boolean b) {
AUTO_FIX_NULLS = b;
}
 
public static synchronized boolean isAutoFixNulls() {
return AUTO_FIX_NULLS;
}
 
public static BigDecimal makeRoom(final SQLTable t, final BigDecimal roomNeeded, final boolean after, final BigDecimal destOrder) throws SQLException {
return makeRoom(t, roomNeeded, after, destOrder, 100);
}
 
/**
* Make sure that there's no rows with order in the passed range. This method accomplishes this
* by re-ordering an increasing number of rows. This method only changes orders greater than or
* equal to <code>destOrder</code> and the first row re-ordered (<code>destOrder</code> if
* <code>!after</code> the next one otherwise) always has <code>destOrder + roomNeeded</code> as
* order :
*
* <pre>
* "row foo" 1.0
* "row bar" 2.0
* "row baz" 3.0
* "row qux" 4.0
* If <code>roomNeeded</code> is 2 after order 2.0, then the new values will be :
* "row foo" 1.0
* "row bar" 2.0
* "row baz" 4.0
* "row qux" 5.0
* If on the other hand, one wants the room before 2.0, then :
* "row foo" 1.0
* "row bar" 4.0
* "row baz" 5.0
* "row qux" 6.0
* </pre>
*
* @param t the table.
* @param roomNeeded the size of the requested free range, e.g 10.
* @param after <code>true</code> if the free range should begin after <code>destOrder</code>,
* <code>false</code> if it should end before <code>destOrder</code>.
* @param destOrder the start or end of the range.
* @param initialCount the initial size of the range to re-order if there's no room.
* @return the smallest possibly used order <code>>=</code> destOrder.
* @throws SQLException if an error occurs.
*/
public static BigDecimal makeRoom(final SQLTable t, final BigDecimal roomNeeded, final boolean after, final BigDecimal destOrder, final int initialCount) throws SQLException {
if (roomNeeded.signum() <= 0)
throw new IllegalArgumentException("Negative roomNeeded");
if (initialCount < 1)
throw new IllegalArgumentException("Initial count too small");
final BigDecimal newFirst = destOrder.add(roomNeeded);
// reorder to squeeze rows upwards
// since we keep increasing count, we will eventually reorder all rows afterwards
// NOTE since we only go in one direction (from destOrder and upwards), there shouldn't be
// any DB deadlocks
int count = Math.max(initialCount, roomNeeded.intValue() + 1);
final int tableRowCount = t.getRowCount();
boolean reordered = false;
while (!reordered) {
// only push destRow upwards if we want to add before
reordered = ReOrder.create(t, destOrder, !after, count, newFirst).exec();
if (!reordered && count > tableRowCount)
throw new IllegalStateException("Unable to reorder " + count + " rows in " + t);
count *= 10;
}
return after ? destOrder : newFirst;
}
 
/**
* Get a number of free order values after/before the passed row,
* {@link #makeRoom(SQLTable, BigDecimal, boolean, BigDecimal, int) making room} if needed.
*
* @param rowCount the number of order values needed.
* @param after <code>true</code> if the free values should begin after <code>r</code>,
* <code>false</code> if they should end before <code>r</code>.
* @param r the row that is before or after the returned orders.
* @return a list of <code>rowCount</code> free orders and the new order for the passed row
* (only changed if there was not enough free values).
* @throws SQLException if an error occurs.
*/
public static Tuple2<List<BigDecimal>, BigDecimal> getFreeOrderValuesFor(final int rowCount, final boolean after, final SQLRow r) throws SQLException {
return getFreeOrderValuesFor(rowCount, after, r, isAutoFixNulls());
}
 
public static Tuple2<List<BigDecimal>, BigDecimal> getFreeOrderValuesFor(final int rowCount, final boolean after, final SQLRow r, final boolean autoFixNulls) throws SQLException {
if (rowCount == 0)
return Tuple2.<List<BigDecimal>, BigDecimal> create(Collections.<BigDecimal> emptyList(), null);
// both rows are locked FOR UPDATE, so there shouldn't be any row that can get between them
// in this transaction, as the only way to do that is to call fetchThisAndSequentialRow()
List2<SQLRow> seqRows = r.fetchThisAndSequentialRow(after);
if (seqRows == null)
throw new IllegalStateException("Couldn't find " + r);
assert seqRows.get0().equals(r) : "fetchThisAndSequentialRow() failed";
if (seqRows.get0().getOrder() == null) {
if (autoFixNulls)
Log.get().log(Level.WARNING, "Re-order table with null orders : " + r);
else
throw new IllegalStateException("Row with null order : " + r);
if (!ReOrder.create(r.getTable()).exec())
throw new IllegalStateException("Couldn't re-order table with null orders : " + r.getTable());
seqRows = r.fetchThisAndSequentialRow(after);
if (seqRows == null || seqRows.get0().getOrder() == null)
throw new IllegalStateException("Re-order table with null orders failed : " + seqRows);
}
final BigDecimal destOrder = seqRows.get0().getOrder();
if (destOrder.compareTo(ReOrder.MIN_ORDER) < 0)
throw new IllegalStateException(seqRows.get0() + " has invalid order : " + destOrder);
BigDecimal newRowOrder = destOrder;
final SQLRow otherRow = seqRows.get1();
final BigDecimal inc;
BigDecimal newOrder;
if (after && otherRow == null) {
// dernière ligne de la table
inc = ReOrder.DISTANCE;
newOrder = destOrder.add(inc);
} else {
final BigDecimal otherOrder;
if (otherRow != null) {
otherOrder = otherRow.getOrder();
} else {
// première ligne
otherOrder = ReOrder.MIN_ORDER;
}
if (otherOrder.compareTo(ReOrder.MIN_ORDER) < 0)
throw new IllegalStateException(otherRow + " has invalid order : " + otherOrder);
 
// ULP * 10 to give a little breathing room
final BigDecimal minDistance = r.getTable().getOrderULP().scaleByPowerOfTen(1);
final BigDecimal places = BigDecimal.valueOf(rowCount + 1);
// the minimum room to fit rowCount
final BigDecimal roomNeeded = minDistance.multiply(places);
final BigDecimal roomAvailable = otherOrder.subtract(destOrder).abs();
 
if (roomAvailable.compareTo(roomNeeded) < 0) {
newRowOrder = makeRoom(r.getTable(), roomNeeded, after, destOrder);
inc = minDistance;
newOrder = after ? destOrder.add(inc) : destOrder;
} else {
inc = roomAvailable.divide(places, DecimalUtils.HIGH_PRECISION);
newOrder = (after ? destOrder : otherOrder).add(inc);
}
}
assert inc.signum() > 0;
final List<BigDecimal> orders = new ArrayList<>(rowCount);
for (int i = 0; i < rowCount; i++) {
orders.add(DecimalUtils.round(newOrder, r.getTable().getOrderDecimalDigits()));
newOrder = newOrder.add(inc);
}
assert after && newRowOrder.compareTo(orders.get(0)) < 0 || !after && orders.get(rowCount - 1).compareTo(newRowOrder) < 0;
return Tuple2.create(orders, newRowOrder);
}
 
// must be zero so that we can work on negative numbers without breaking the unique constraint
public static final BigDecimal MIN_ORDER = BigDecimal.ZERO;
// preferred distance
123,15 → 287,16
 
// MAYBE return affected IDs
public final boolean exec() throws SQLException {
final UpdateBuilder updateUndef = new UpdateBuilder(this.t).setObject(this.t.getOrderField(), MIN_ORDER);
updateUndef.setWhere(new Where(this.t.getKey(), "=", this.t.getUndefinedID()));
return (Boolean) SQLUtils.executeAtomic(this.t.getBase().getDataSource(), new ConnectionHandlerNoSetup<Object, SQLException>() {
final SQLTable t = this.t;
return SQLUtils.executeAtomic(this.t.getBase().getDataSource(), new ConnectionHandlerNoSetup<Boolean, SQLException>() {
@Override
public Object handle(SQLDataSource ds) throws SQLException, SQLException {
public Boolean handle(SQLDataSource ds) throws SQLException, SQLException {
final Connection conn = ds.getConnection();
final Statement stmt = conn.createStatement();
if (isAll()) {
// reorder all, undef must be at 0
// reorder all, undef must be at 0
if (isAll() && t.getUndefinedIDNumber() != null) {
final UpdateBuilder updateUndef = new UpdateBuilder(t).setObject(t.getOrderField(), MIN_ORDER);
updateUndef.setWhere(new Where(t.getKey(), "=", t.getUndefinedID()));
stmt.execute(updateUndef.asString());
}
stmt.execute("SELECT " + ReOrder.this.spec.getInc());
138,13 → 303,13
final BigDecimal inc = NumberConvertor.toBigDecimal((Number) SQLDataSource.SCALAR_HANDLER.handle(stmt.getResultSet()));
// needed since the cast in getInc() rounds so if the real increment is 0.006 it
// might get rounded to 0.01 and thus the last rows will overlap non moved rows
if (inc.compareTo(ReOrder.this.t.getOrderULP().scaleByPowerOfTen(1)) < 0)
if (inc.compareTo(t.getOrderULP().scaleByPowerOfTen(1)) < 0)
return false;
for (final String s : getSQL(conn, inc)) {
stmt.execute(s);
}
// MAYBE fire only changed IDs
ReOrder.this.t.fireTableModified(-1, Collections.singletonList(ReOrder.this.t.getOrderField().getName()));
t.fireTableModified(SQLRow.NONEXISTANT_ID, Collections.singletonList(t.getOrderField().getName()));
return true;
}
});
174,7 → 339,7
if (first.compareTo(MIN_ORDER) <= 0) {
this.firstToReorder = MIN_ORDER;
this.firstToReorderInclusive = false;
// make some room before the first non MIN_ORDER row so that another on can came
// make some room before the first non MIN_ORDER row so that another one can came
// before it
this.first = MIN_ORDER.add(DISTANCE).max(newFirst);
// try to keep asked value
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxPG.java
107,7 → 107,9
this.typeNames.addAll(java.sql.Date.class, "date");
this.typeNames.addAll(java.sql.Time.class, "time", "time without time zone");
this.typeNames.addAll(Blob.class, "bytea");
this.typeNames.addAll(Clob.class, "varchar", "char", "character varying", "character", "text");
// even though PG treats all Character Types equally, unbounded varchar is not standard, so
// prefer "text" which is supported by all systems
this.typeNames.addAll(Clob.class, "text", "varchar", "char", "character varying", "character");
this.typeNames.addAll(String.class, "varchar", "char", "character varying", "character", "text");
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
1218,26 → 1218,22
* @return this.
*/
public SQLRowValues setOrder(SQLRow r, boolean after) {
return this.setOrder(r, after, ReOrder.DISTANCE.movePointRight(2).intValue(), 0);
setOrder(Collections.singletonList(this), r, after);
return this;
}
 
private SQLRowValues setOrder(SQLRow r, boolean after, int nbToReOrder, int nbReOrdered) {
final BigDecimal freeOrder = r.getOrder(after);
final String orderName = this.getTable().getOrderField().getName();
if (freeOrder != null)
return this.put(orderName, freeOrder);
else if (nbReOrdered > r.getTable().getRowCount()) {
throw new IllegalStateException("cannot reorder " + r.getTable().getSQLName());
} else {
// make room
try {
ReOrder.create(this.getTable(), r.getOrder().intValue() - (nbToReOrder / 2), nbToReOrder).exec();
} catch (SQLException e) {
throw ExceptionUtils.createExn(IllegalStateException.class, "reorder failed for " + this.getTable() + " at " + r.getOrder(), e);
}
r.fetchValues();
return this.setOrder(r, after, nbToReOrder * 10, nbToReOrder);
public static void setOrder(final List<SQLRowValues> values, final SQLRow r, boolean after) {
final int valuesCount = values.size();
final List<BigDecimal> orders;
try {
orders = ReOrder.getFreeOrderValuesFor(valuesCount, after, r).get0();
} catch (SQLException e) {
throw ExceptionUtils.createExn(IllegalStateException.class, "reorder failed for " + r.getTable() + " at " + r.getOrder(), e);
}
final String orderName = r.getTable().getOrderField().getName();
for (int i = 0; i < valuesCount; i++) {
values.get(i).put(orderName, orders.get(i));
}
}
 
public final SQLRowValues setID(Number id) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
872,11 → 872,38
*
* @return the key, <code>null</code> for a simple field.
*/
public final SQLKey getKey() {
public final SQLKey getRawKey() {
return this.key;
}
 
/**
* The key for this group.
*
* @return the key, never <code>null</code>.
* @throws IllegalStateException for a simple field.
*/
public final SQLKey getKey() throws IllegalStateException {
if (this.key == null)
throw new IllegalStateException("Not a key : " + this);
return this.key;
}
 
/**
* The foreign link for this group.
*
* @return the foreign link, never <code>null</code>.
* @throws IllegalStateException for a simple field or a primary key.
*/
public final Link getForeignLink() throws IllegalStateException {
if (this.key != null) {
final Link foreignLink = this.key.getForeignLink();
if (foreignLink != null)
return foreignLink;
}
throw new IllegalStateException("Not a foreign key : " + this);
}
 
/**
* The one and only field of this group.
*
* @return the only field of this group, only <code>null</code> if this group is a
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntax.java
710,8 → 710,9
sqlType = type + "(" + size + ")";
} else {
Log.get().warning("Unbounded varchar for " + f.getSQLName());
if (this.getSystem() == SQLSystem.MYSQL)
throw new IllegalStateException("MySQL doesn't support unbounded varchar and might truncate data if reducing size of " + f.getSQLName());
// if (this.getSystem() == SQLSystem.MYSQL)
// throw new IllegalStateException("MySQL doesn't support unbounded varchar and
// might truncate data if reducing size of " + f.getSQLName());
// don't specify size
sqlType = type;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowAccessor.java
402,9 → 402,13
}
 
public final <T> T getObjectAs(String field, Class<T> clazz) {
return this.getObjectAs(field, false, clazz);
}
 
public final <T> T getObjectAs(final String field, final boolean mustBePresent, final Class<T> clazz) {
T res = null;
try {
res = clazz.cast(this.getObject(field));
res = clazz.cast(this.getObject(field, mustBePresent));
} catch (ClassCastException e) {
throw new IllegalArgumentException("Impossible d'accéder au champ " + field + " de la ligne " + this + " en tant que " + clazz.getSimpleName(), e);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/OrderComparator.java
15,6 → 15,7
 
import org.openconcerto.utils.CompareUtils;
 
import java.math.BigDecimal;
import java.util.Comparator;
 
/**
24,11 → 25,14
*/
public class OrderComparator implements Comparator<SQLRowAccessor> {
 
public static final Comparator<BigDecimal> BD_NULLS_FIRST = Comparator.nullsFirst(Comparator.naturalOrder());
public static final Comparator<BigDecimal> BD_NULLS_LAST = Comparator.nullsLast(Comparator.naturalOrder());
 
/**
* Order rows by {@link SQLTable#getOrderField()}.
*/
public static final OrderComparator INSTANCE = new OrderComparator(false);
private static final OrderComparator INSTANCE_FALLBACK_TO_PK = new OrderComparator(true);
public static final OrderComparator INSTANCE = new OrderComparator(false, BD_NULLS_LAST);
private static final OrderComparator INSTANCE_FALLBACK_TO_PK = new OrderComparator(true, BD_NULLS_LAST);
 
/**
* Order rows by {@link SQLTable#getOrderField()}, or if the table is not
41,11 → 45,12
}
 
private final boolean fallbackToPK;
private final Comparator<BigDecimal> bdComparator;
 
// singleton
private OrderComparator(boolean fallbackToPK) {
public OrderComparator(final boolean fallbackToPK, final Comparator<BigDecimal> bdComparator) {
super();
this.fallbackToPK = fallbackToPK;
this.bdComparator = bdComparator;
}
 
@Override
57,8 → 62,11
final SQLTable t = r1.getTable();
if (!t.equals(r2.getTable()))
throw new IllegalArgumentException(r1 + " and " + r2 + " are not of the same table");
if (t.isOrdered()) {
return r1.getOrder().compareTo(r2.getOrder());
final SQLField orderField = t.getTable().getOrderField();
if (orderField != null) {
final BigDecimal order1 = r1.getObjectAs(orderField.getName(), true, BigDecimal.class);
final BigDecimal order2 = r2.getObjectAs(orderField.getName(), true, BigDecimal.class);
return this.bdComparator.compare(order1, order2);
} else if (this.fallbackToPK) {
if (!t.isRowable())
throw new IllegalArgumentException(t + " neither ordered nor rowable");
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLField.java
391,7 → 391,7
* @see #getFieldGroup()
*/
public boolean isForeignKey() {
final FieldGroup fieldGroup = getFieldGroup();
final FieldGroup fieldGroup = getContainingFieldGroup();
return fieldGroup.getKeyType() == Type.FOREIGN_KEY && fieldGroup.getSingleField() != null;
}
 
401,10 → 401,23
* @return the group of this field.
* @see SQLTable#getFieldGroups()
*/
public FieldGroup getFieldGroup() {
public FieldGroup getContainingFieldGroup() {
return this.getTable().getFieldGroups().get(this.getName());
}
 
/**
* The group consisting of this single field.
*
* @return the group consisting of this single field.
* @throws IllegalStateException if this field is part of a multi-field group.
*/
public FieldGroup getFieldGroup() throws IllegalStateException {
final FieldGroup fg = this.getTable().getFieldGroups().get(this.getName());
if (fg.getSingleField() == null)
throw new IllegalStateException(this + " is part of a group with others : " + fg);
return fg;
}
 
public final SQLTable getForeignTable() {
return this.getDBSystemRoot().getGraph().getForeignTable(this);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java
23,12 → 23,10
import org.openconcerto.sql.model.graph.Link;
import org.openconcerto.sql.model.graph.Link.Direction;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.utils.ReOrder;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.Tuple2.List2;
 
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
298,10 → 296,26
this.fetchValues(true);
}
 
/**
* Fetch up-to-date values from the DB.
*
* @param useCache <code>true</code> to use the {@link SQLDataSource#isCacheEnabled() cache}.
* @return this.
*/
public final SQLRow fetchValues(final boolean useCache) {
return this.fetchValues(useCache, useCache);
}
 
/**
* Return a new instance with up-to-date values.
*
* @param useCache <code>true</code> to use the {@link SQLDataSource#isCacheEnabled() cache}.
* @return a new instance.
*/
public final SQLRow fetchNew(final boolean useCache) {
return new SQLRow(this.getTable(), this.getIDNumber()).fetchValues(useCache);
}
 
@SuppressWarnings("unchecked")
SQLRow fetchValues(final boolean readCache, final boolean writeCache) {
final IResultSetHandler handler = new IResultSetHandler(SQLDataSource.MAP_HANDLER, readCache, writeCache) {
397,14 → 411,44
return this.getValues().get(field);
}
 
public final SQLRow getRow(boolean after) {
/**
* Fetch from the DB this row and the next/previous one. ATTN the rows are locked
* {@link LockStrength#UPDATE for update}, but if this method is not called from within a
* transaction, they will immediately be obsolete.
*
* @param after <code>true</code> to return the next row, <code>false</code> to return the
* previous.
* @return {@link List2#get0() this row} and the next/previous one with only
* {@link SQLTable#getOrderField()} and {@link SQLTable#getArchiveField()} fetched,
* <code>null</code> if this row doesn't exist, the {@link List2#get1() next/previous
* row} is <code>null</code> if this is the last/first row of the table or has
* <code>null</code> order.
* @throws IllegalStateException if this is the {@link #isUndefined() undefined} row.
*/
public final List2<SQLRow> fetchThisAndSequentialRow(boolean after) throws IllegalStateException {
if (this.isUndefined())
throw new IllegalStateException("Cannot order against the undefined");
final SQLTable t = this.getTable();
final BigDecimal destOrder = this.getOrder();
final int diff = (!after) ? -1 : 1;
 
// this is one statement (subquery included) and thus atomic : the inner FOR UPDATE ensures
// that the ORDER doesn't change by the time the outer query is executed
// SELECT * FROM "test"."BATIMENT"
// WHERE "ORDRE" >= (SELECT "ORDRE" FROM "test"."BATIMENT" WHERE "ID" = 3 FOR UPDATE)
// ORDER BY "ORDRE"
// LIMIT 2
// FOR UPDATE;
 
final SQLSelect selOrder = new SQLSelect();
// OK to order against an archived
selOrder.setArchivedPolicy(SQLSelect.BOTH);
selOrder.addSelect(t.getOrderField());
selOrder.setWhere(this.getWhere());
selOrder.setLockStrength(LockStrength.UPDATE);
 
final SQLSelect sel = new SQLSelect();
// undefined must not move
sel.setExcludeUndefined(true);
// don't ignore undefined or the caller might want to use its order
sel.setExcludeUndefined(false);
// unique index prend aussi en compte les archivés
sel.setArchivedPolicy(SQLSelect.BOTH);
sel.addSelect(t.getKey());
411,49 → 455,21
sel.addSelect(t.getOrderField());
if (t.isArchivable())
sel.addSelect(t.getArchiveField());
sel.setWhere(new Where(t.getOrderField(), diff < 0 ? "<" : ">", destOrder));
final Where orderWhere = Where.createRaw(t.getOrderField().getFieldRef() + (diff < 0 ? "<=" : ">=") + "(" + selOrder + ")", t.getOrderField());
// this.getWhere() needed when ORDER is null
sel.setWhere(orderWhere.or(this.getWhere()));
sel.addFieldOrder(t.getOrderField(), diff < 0 ? Order.desc() : Order.asc());
sel.setLimit(1);
sel.setLimit(2);
sel.setLockStrength(LockStrength.UPDATE);
 
final SQLDataSource ds = t.getBase().getDataSource();
@SuppressWarnings("unchecked")
final Map<String, Object> otherMap = ds.execute1(sel.asString());
if (otherMap != null) {
return new SQLRow(t, otherMap);
} else {
final List<SQLRow> rows = SQLRowListRSH.execute(sel);
assert rows.size() <= 2;
if (rows.isEmpty()) {
return null;
}
}
 
/**
* The free order just after or before this row.
*
* @param after whether to look before or after this row.
* @return a free order, or <code>null</code> if there's no room left.
*/
public final BigDecimal getOrder(boolean after) {
final BigDecimal destOrder = this.getOrder();
final SQLRow otherRow = this.getRow(after);
final BigDecimal otherOrder;
if (otherRow != null) {
otherOrder = otherRow.getOrder();
} else if (after) {
// dernière ligne de la table
otherOrder = destOrder.add(ReOrder.DISTANCE);
} else {
// première ligne
otherOrder = ReOrder.MIN_ORDER;
assert rows.get(0).equals(this);
return new List2<>(rows.get(0), rows.size() == 1 ? null : rows.get(1));
}
 
final int decDigits = this.getTable().getOrderDecimalDigits();
final BigDecimal least = BigDecimal.ONE.scaleByPowerOfTen(-decDigits);
final BigDecimal distance = destOrder.subtract(otherOrder).abs();
if (distance.compareTo(least) <= 0)
return null;
else {
final BigDecimal mean = destOrder.add(otherOrder).divide(BigDecimal.valueOf(2));
return DecimalUtils.round(mean, decDigits);
}
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/users/CompanyAccessSQLElement.java
Fichier supprimé
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightSQLElement.java
14,14 → 14,13
package org.openconcerto.sql.users.rights;
 
import static java.util.Arrays.asList;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.ConfSQLElement;
 
import org.openconcerto.sql.element.GlobalMapper;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.utils.i18n.I18nUtils;
 
import java.util.ArrayList;
import java.util.Collections;
28,7 → 27,7
import java.util.List;
import java.util.Set;
 
public class UserRightSQLElement extends ConfSQLElement {
public class UserRightSQLElement extends SQLElement {
public static final String TABLE_NAME = "USER_RIGHT";
 
static public List<SQLCreateTable> getCreateTables(final SQLTable userT) {
56,9 → 55,8
return res;
}
 
public UserRightSQLElement() {
super(TABLE_NAME);
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
public UserRightSQLElement(final DBRoot r) {
super(r.findTable(TABLE_NAME), null, "sql.user-right");
final UserRightGroup group = new UserRightGroup();
GlobalMapper.getInstance().map(UserRightSQLComponent.ID, group);
setDefaultGroup(group);
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/RightSQLElement.java
13,20 → 13,18
package org.openconcerto.sql.users.rights;
 
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.i18n.I18nUtils;
 
import java.util.Arrays;
import java.util.List;
 
public class RightSQLElement extends ConfSQLElement {
public class RightSQLElement extends SQLElement {
 
public static final String TABLE_NAME = "RIGHT";
 
38,9 → 36,8
return res;
}
 
public RightSQLElement() {
super(TABLE_NAME);
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
public RightSQLElement(final DBRoot root) {
super(root.findTable(TABLE_NAME), null, "sql.right");
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightsManager.java
289,7 → 289,7
};
this.javaRights = new JavaRights();
this.table = t;
this.toUserLink = t.getFieldGroups().get("ID_USER_COMMON").getKey().getForeignLink();
this.toUserLink = t.getField("ID_USER_COMMON").getFieldGroup().getForeignLink();
defaultRegister();
this.userRights = new HashMap<Integer, UserRights>();
this.exec = Executors.newSingleThreadExecutor(new ThreadFactory(this.getClass().getSimpleName() + " executor for " + t.getSQLName(), true).setPriority(Thread.MIN_PRIORITY));
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java
16,7 → 16,6
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.DBRoot;
47,7 → 46,6
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.i18n.I18nUtils;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.Component;
75,7 → 73,7
import javax.swing.table.DefaultTableCellRenderer;
 
// FIXME Login user unique ?
public class UserCommonSQLElement extends ConfSQLElement {
public class UserCommonSQLElement extends SQLElement {
 
/**
* Set this system property to "true" if this should generate old style passwords.
82,19 → 80,15
*/
public static final String LEGACY_PASSWORDS = "org.openconcerto.sql.legacyPasswords";
 
{
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
}
 
private final boolean familyNameFirst;
 
public UserCommonSQLElement() {
super("USER_COMMON");
this.familyNameFirst = false;
public UserCommonSQLElement(final DBRoot root) {
this(root, false);
}
 
public UserCommonSQLElement(final DBRoot root, final boolean familyNameFirst) {
super(root.findTable("USER_COMMON"));
// allow subclass to keep same code
super(root.findTable("USER_COMMON"), null, "sql.user");
this.familyNameFirst = familyNameFirst;
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/ProcessStreams.java
19,6 → 19,7
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.ProcessBuilder.Redirect;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
35,6 → 36,10
static public enum Action {
/**
* Redirect process streams to ours.
*
* @deprecated use {@link ProcessStreams#redirect(ProcessBuilder)} (or
* {@link Redirect#INHERIT} directly) as it makes sure that
* {@link Process#waitFor()} only returns once all streams are flushed.
*/
REDIRECT,
/**
52,6 → 57,10
DO_NOTHING
}
 
static public final ProcessBuilder redirect(final ProcessBuilder pb) throws IOException {
return pb.redirectErrorStream(true).redirectOutput(Redirect.INHERIT);
}
 
static public final Process handle(final Process p, final Action action) throws IOException {
if (action == Action.CLOSE) {
p.getInputStream().close();
/trunk/OpenConcerto/src/org/openconcerto/utils/TableSorter.java
37,6 → 37,8
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
45,6 → 47,8
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
 
import net.jcip.annotations.Immutable;
 
/**
* TableSorter is a decorator for TableModels; adding sorting functionality to a supplied
* TableModel. TableSorter does not store or copy the data in its TableModel; instead it maintains a
51,16 → 55,18
* map from the row indexes of the view to the row indexes of the model. As requests are made of the
* sorter (like getValueAt(row, col)) they are passed to the underlying model after the row numbers
* have been translated via the internal mapping array. This way, the TableSorter appears to hold
* another copy of the table with the rows in a different order. <p/>TableSorter registers itself as
* a listener to the underlying model, just as the JTable itself would. Events recieved from the
* model are examined, sometimes manipulated (typically widened), and then passed on to the
* TableSorter's listeners (typically the JTable). If a change to the model has invalidated the
* order of TableSorter's rows, a note of this is made and the sorter will resort the rows the next
* time a value is requested. <p/>When the tableHeader property is set, either by using the
* setTableHeader() method or the two argument constructor, the table header may be used as a
* complete UI for TableSorter. The default renderer of the tableHeader is decorated with a renderer
* that indicates the sorting status of each column. In addition, a mouse listener is installed with
* the following behavior:
* another copy of the table with the rows in a different order.
* <p/>
* TableSorter registers itself as a listener to the underlying model, just as the JTable itself
* would. Events recieved from the model are examined, sometimes manipulated (typically widened),
* and then passed on to the TableSorter's listeners (typically the JTable). If a change to the
* model has invalidated the order of TableSorter's rows, a note of this is made and the sorter will
* resort the rows the next time a value is requested.
* <p/>
* When the tableHeader property is set, either by using the setTableHeader() method or the two
* argument constructor, the table header may be used as a complete UI for TableSorter. The default
* renderer of the tableHeader is decorated with a renderer that indicates the sorting status of
* each column. In addition, a mouse listener is installed with the following behavior:
* <ul>
* <li>Mouse-click: Clears the sorting status of all other columns and advances the sorting status
* of that column through three values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to NOT_SORTED
72,8 → 78,9
* column do not cancel the statuses of columns that are already sorting - giving a way to initiate
* a compound sort.
* </ul>
* <p/>This is a long overdue rewrite of a class of the same name that first appeared in the swing
* table demos in 1997.
* <p/>
* This is a long overdue rewrite of a class of the same name that first appeared in the swing table
* demos in 1997.
*
* @author Philip Milne
* @author Brendon McLean
92,11 → 99,13
private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
 
public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((Comparable) o1).compareTo(o2);
}
};
public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
public static final Comparator<Object> LEXICAL_COMPARATOR = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
108,8 → 117,8
private JTableHeader tableHeader;
private MouseListener mouseListener;
private TableModelListener tableModelListener;
private Map columnComparators = new HashMap();
private List sortingColumns = new ArrayList();
private Map<Class<?>, Comparator<?>> columnComparators = new HashMap<>();
private final List<Directive> sortingColumns = new ArrayList<>();
 
private boolean enabled;
private boolean sorting;
144,6 → 153,9
}
 
public void setTableModel(TableModel tableModel) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (this.tableModel != null) {
this.tableModel.removeTableModelListener(tableModelListener);
}
188,6 → 200,9
}
 
public void setTableHeader(JTableHeader tableHeader) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (this.tableHeader != null) {
this.tableHeader.removeMouseListener(mouseListener);
TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
207,9 → 222,22
return sortingColumns.size() != 0;
}
 
public final List<Directive> getSortingColumns() {
return Collections.unmodifiableList(this.sortingColumns);
}
 
public void setSortingColumns(List<Directive> sortingColumns) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
this.sortingColumns.clear();
this.sortingColumns.addAll(sortingColumns);
sortingStatusChanged();
}
 
private Directive getDirective(int column) {
for (int i = 0; i < sortingColumns.size(); i++) {
Directive directive = (Directive) sortingColumns.get(i);
Directive directive = sortingColumns.get(i);
if (directive.column == column) {
return directive;
}
234,6 → 262,9
}
 
private synchronized void sortingStatusChanged() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
this.sortingStatusChanged(true);
}
 
271,7 → 302,7
sortingStatusChanged(fire);
}
 
public void setColumnComparator(Class type, Comparator comparator) {
public void setColumnComparator(Class<?> type, Comparator<?> comparator) {
if (comparator == null) {
columnComparators.remove(type);
} else {
280,8 → 311,8
}
 
protected Comparator getComparator(int column) {
Class columnType = tableModel.getColumnClass(column);
Comparator comparator = (Comparator) columnComparators.get(columnType);
Class<?> columnType = tableModel.getColumnClass(column);
Comparator<?> comparator = columnComparators.get(columnType);
if (comparator != null) {
return comparator;
}
292,6 → 323,9
}
 
private Row[] getViewToModel() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (viewToModel == null) {
int tableModelRowCount = tableModel.getRowCount();
viewToModel = new Row[tableModelRowCount];
318,6 → 352,9
}
 
private int[] getModelToView() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (modelToView == null) {
int n = getViewToModel().length;
modelToView = new int[n];
334,31 → 371,50
 
// TableModel interface methods
 
@Override
public int getRowCount() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
return (tableModel == null) ? 0 : tableModel.getRowCount();
}
 
@Override
public int getColumnCount() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
return (tableModel == null) ? 0 : tableModel.getColumnCount();
}
 
@Override
public String getColumnName(int column) {
return tableModel.getColumnName(column);
}
 
public Class getColumnClass(int column) {
@Override
public Class<?> getColumnClass(int column) {
return tableModel.getColumnClass(column);
}
 
@Override
public boolean isCellEditable(int row, int column) {
return tableModel.isCellEditable(modelIndex(row), column);
}
 
@Override
public Object getValueAt(int row, int column) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
return tableModel.getValueAt(modelIndex(row), column);
}
 
@Override
public void setValueAt(Object aValue, int row, int column) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
tableModel.setValueAt(aValue, modelIndex(row), column);
}
 
376,7 → 432,7
 
// Helper classes
 
private class Row implements Comparable {
private class Row implements Comparable<Row> {
private int modelIndex;
 
public Row(int index) {
383,12 → 439,13
this.modelIndex = index;
}
 
public int compareTo(Object o) {
@Override
public int compareTo(Row o) {
int row1 = modelIndex;
int row2 = ((Row) o).modelIndex;
int row2 = o.modelIndex;
 
for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
Directive directive = (Directive) it.next();
for (Iterator<Directive> it = sortingColumns.iterator(); it.hasNext();) {
Directive directive = it.next();
int column = directive.column;
Object o1 = tableModel.getValueAt(row1, column);
Object o2 = tableModel.getValueAt(row2, column);
413,6 → 470,7
}
 
private class TableModelHandler implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
// If we're not sorting by anything, just pass the event along.
if (!isSorting()) {
487,6 → 545,7
}
 
private class MouseHandler extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
JTableHeader h = (JTableHeader) e.getSource();
TableColumnModel columnModel = h.getColumnModel();
523,6 → 582,7
this.priority = priority;
}
 
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
Color color = c == null ? Color.GRAY : c.getBackground();
// In a compound sort, make each succesive triangle 20%
556,10 → 616,12
g.translate(-x, -y);
}
 
@Override
public int getIconWidth() {
return size;
}
 
@Override
public int getIconHeight() {
return size;
}
572,11 → 634,12
this.tableCellRenderer = tableCellRenderer;
}
 
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = tableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
l.setHorizontalTextPosition(JLabel.LEFT);
l.setHorizontalTextPosition(SwingConstants.LEFT);
int modelColumn = table.convertColumnIndexToModel(column);
l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));
}
584,13 → 647,27
}
}
 
private static class Directive {
private int column;
private int direction;
@Immutable
public static class Directive {
private final int column;
private final int direction;
 
public Directive(int column, int direction) {
this.column = column;
this.direction = direction;
}
 
public final int getColumn() {
return this.column;
}
 
public final int getDirection() {
return this.direction;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + this.getDirection() + " on column " + this.getColumn();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/FileUtils.java
38,6 → 38,7
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryStream;
import java.nio.file.DirectoryStream.Filter;
97,6 → 98,9
}
 
public static void openFile(File f) throws IOException {
if (!f.exists()) {
throw new FileNotFoundException(f.getAbsolutePath() + " not found");
}
if (Desktop.isDesktopSupported()) {
Desktop d = Desktop.getDesktop();
if (d.isSupported(Desktop.Action.OPEN)) {
616,6 → 620,10
return readUTF8(new FileInputStream(f));
}
 
public static final String readUTF8(Path p) throws IOException {
return new String(Files.readAllBytes(p), StandardCharsets.UTF_8);
}
 
public static final String readUTF8(InputStream ins) throws IOException {
return read(ins, StringUtils.UTF8);
}
900,6 → 908,9
* @throws IOException if the file can't be opened.
*/
public static final void open(File f, String[] executables) throws IOException {
if (!f.exists()) {
throw new FileNotFoundException(f.getAbsolutePath() + " not found");
}
try {
openNative(f);
} catch (IOException exn) {
/trunk/OpenConcerto/src/org/openconcerto/utils/ReflectUtils.java
13,6 → 13,7
package org.openconcerto.utils;
 
import java.beans.Expression;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericArrayType;
29,7 → 30,10
public final class ReflectUtils {
 
/**
* Find a constructor with compatible parameters.
* Find a constructor with compatible parameters. NOTE: This follow a simpler algorithm than the
* one in the JLS (<a href=
* "https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2.5">15.12.2.5.
* Choosing the Most Specific Method</a>).
*
* @param cls the class to find a constructor for, not <code>null</code>.
* @param parameterTypes types of parameters the constructor must accept.
58,6 → 62,35
}
}
 
@SuppressWarnings("unchecked")
static public final <T> T createInstance(final Class<T> clazz, Object... args) throws Exception {
// too difficult to order superclasses and all implemented interfaces of args in order to
// find the most specific constructor
return (T) new Expression(clazz, "new", args).getValue();
}
 
/**
* Return the class with the passed name if it is a subclass of <code>clazz</code>.
*
* @param name the name of the class, not <code>null</code>.
* @param clazz the superclass, not <code>null</code>.
* @return the requested class, <code>null</code> if {@link ClassNotFoundException not found} or
* not a {@link Class#asSubclass(Class) subclass} of <code>clazz</code>.
*/
static public final <T> Class<? extends T> getSubclass(final String name, final Class<T> clazz) {
return getSubclass(name, clazz, clazz.getClassLoader());
}
 
static public final <T> Class<? extends T> getSubclass(final String name, final Class<T> clazz, final ClassLoader cl) {
final Class<?> res;
try {
res = Class.forName(name, true, cl);
} catch (ClassNotFoundException e) {
return null;
}
return clazz.isAssignableFrom(res) ? res.asSubclass(clazz) : null;
}
 
static private Map<Type, Type> resolveTypes(Class<?> c, Class<?> raw) {
final Map<Type, Type> res = new HashMap<Type, Type>();
if (!raw.isAssignableFrom(c))
/trunk/OpenConcerto/src/org/openconcerto/utils/ntp/SNTPClient.java
Nouveau fichier
0,0 → 1,116
/*
* 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.utils.ntp;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
 
public class SNTPClient {
 
protected final DatagramSocket socket;
 
/**
* The SNTP time is referenced to 01/01/1900-00:00. On the other hand, Unix systems and Java
* reference time to 01/01/1970-00:00. This means that convertion is necessary.
*/
private static final long SECS_1900_1970 = 2208988800L;
 
/**
* Constructor.
*
* @param timeout the response timeout (in milliseconds).
* @throws IllegalArgumentException if the timeout is invalid.
* @throws SocketException if an error occurs while creating the socket.
*/
public SNTPClient() throws SocketException {
this.socket = new DatagramSocket();
// 10s timeout
socket.setSoTimeout(10000);
}
 
/**
* Retrieves the network time offset from an SNTP server.
*
* @param host the server host address (IP or DNS).
* @param port the server port.
* @return the network time offset (in milliseconds).
*
* @throws IOException if an error occurs while contacting the server.
*/
public long getOffsetInMillis(final String host, final int port) throws IOException {
final InetAddress addr = InetAddress.getByName(host);
// Send
final Message smessage = new Message();
smessage.setTransmitTimestamp(toTimestamp(System.currentTimeMillis()));
final ByteArrayOutputStream output = new ByteArrayOutputStream();
smessage.encodeMessage(output);
final byte[] data = output.toByteArray();
output.close();
 
DatagramPacket rpacket = new DatagramPacket(data, data.length, addr, port);
socket.send(rpacket);
 
// Receive
final DatagramPacket packet = new DatagramPacket(new byte[Message.MAXIMUM_LENGTH], Message.MAXIMUM_LENGTH);
socket.receive(packet);
final long destinationTime = System.currentTimeMillis();
final Message rmessage = Message.decodeMessage(new ByteArrayInputStream(packet.getData()));
final long originalTime = fromTimestamp(rmessage.getOriginateTimestamp());
final long receiveTime = fromTimestamp(rmessage.getReceiveTimestamp());
final long transmitTime = fromTimestamp(rmessage.getTransmitTimestamp());
return ((receiveTime - originalTime) + (transmitTime - destinationTime)) / 2;
 
}
 
public void close() {
socket.close();
}
 
/**
* Converts Java time to an SNTP timestamp.
*
* @param time the Java time (in milliseconds).
* @return the SNTP timestamp.
*/
private static Timestamp toTimestamp(final long time) {
final double temp = ((double) time) / 1000D;
final long integer = (long) Math.floor(temp);
final long fraction = (long) ((temp - (double) integer) * 0x100000000L);
return new Timestamp(integer + SECS_1900_1970, fraction);
}
 
/**
* Converts an SNTP timestamp to Java time.
*
* @param timestamp the timestamp.
* @return the Java time (in milliseconds).
*/
private static final long fromTimestamp(final Timestamp timestamp) {
long time = (timestamp.getInteger() - SECS_1900_1970) * 1000L;
time += (timestamp.getFraction() * 1000L) / 0x100000000L;
return time;
}
 
public static void main(String[] args) throws IOException {
final SNTPClient client = new SNTPClient();
final long offset = client.getOffsetInMillis("fr.pool.ntp.org", 123);
client.close();
System.out.println(offset);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ntp/Timestamp.java
Nouveau fichier
0,0 → 1,36
/*
* 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.utils.ntp;
 
public final class Timestamp {
 
public static final Timestamp ZERO = new Timestamp(0, 0);
 
private final long integer;
private final long fraction;
 
public Timestamp(final long integer, final long fraction) {
this.integer = integer;
this.fraction = fraction;
}
 
public long getInteger() {
return integer;
}
 
public long getFraction() {
return fraction;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ntp/Message.java
Nouveau fichier
0,0 → 1,448
/*
* 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.utils.ntp;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
public final class Message {
 
/** Maximum message length (in bytes), without authentication */
public static final int MAXIMUM_LENGTH = 384;
 
/** Leap Indicator. */
private byte byLeapIndicator;
 
/** Version Number. */
private byte byVersionNumber = 0x04;
 
/** Client mode. */
private byte byMode = 0x03;
 
/** Stratum. */
private byte byStratum;
 
/** Poll Interval. */
private byte byPollInterval;
 
/** Precision. */
private byte byPrecision;
 
/** Rood Delay. */
private double dRootDelay;
 
/** Root Dispersion. */
private double dRootDispersion;
 
/** Reference Identifier. */
private byte[] sReferenceIdentifier = "LOCL".getBytes();
 
/** Reference Timestamp. */
private Timestamp tReferenceTimestamp = Timestamp.ZERO;
 
/** Originate Timestamp. */
private Timestamp tOriginateTimestamp = Timestamp.ZERO;
 
/** Receive Timestamp. */
private Timestamp tReceiveTimestamp = Timestamp.ZERO;
 
/** Transmit Timestamp. */
private Timestamp tTransmitTimestamp = Timestamp.ZERO;
 
/**
* Returns the Leap Indicator.
*
* @return the Leap Indicator.
*/
public byte getLeapIndicator() {
return byLeapIndicator;
}
 
/**
* Sets the Leap Indicator.
*
* @param byLeapIndicator the Leap Indicator.
*/
public void setLeapIndicator(final byte byLeapIndicator) {
this.byLeapIndicator = byLeapIndicator;
}
 
/**
* Returns the Version Number.
*
* @return the Version Number.
*/
public byte getVersionNumber() {
return byVersionNumber;
}
 
/**
* Sets the Version Number.
*
* @param byVersionNumber the Version Number.
*/
public void setVersionNumber(final byte byVersionNumber) {
this.byVersionNumber = byVersionNumber;
}
 
/**
* Returns the Mode.
*
* @return the Mode.
*/
public byte getMode() {
return byMode;
}
 
/**
* Sets the Mode.
*
* @param byMode the Mode.
*/
public void setMode(final byte byMode) {
this.byMode = byMode;
}
 
/**
* Returns the Stratum.
*
* @return the Stratum.
*/
public byte getStratum() {
return byStratum;
}
 
/**
* Sets the Stratum.
*
* @param byStratum the Stratum.
*/
public void setStratum(final byte byStratum) {
this.byStratum = byStratum;
}
 
/**
* Returns the Poll Interval.
*
* @return the Poll Interval.
*/
public byte getPollInterval() {
return byPollInterval;
}
 
/**
* Sets the Poll Interval.
*
* @param byPollInterval the Poll Interval.
*/
public void setPollInterval(final byte byPollInterval) {
this.byPollInterval = byPollInterval;
}
 
/**
* Returns the Precision.
*
* @return the Precision.
*/
public byte getPrecision() {
return byPrecision;
}
 
/**
* Sets the Precision.
*
* @param byPrecision the Precision.
*/
public void setPrecision(final byte byPrecision) {
this.byPrecision = byPrecision;
}
 
/**
* Returns the Root Delay.
*
* @return the Root Delay.
*/
public double getRootDelay() {
return dRootDelay;
}
 
/**
* Sets the Root Delay.
*
* @param dRootDelay the Root Delay.
*/
public void setRootDelay(final double dRootDelay) {
this.dRootDelay = dRootDelay;
}
 
/**
* Returns the Root Dispersion.
*
* @return the Root Dispersion.
*/
public double getRootDispersion() {
return dRootDispersion;
}
 
/**
* Sets the Root Dispersion.
*
* @param dRootDispersion the Root Dispersion.
*/
public void setRootDispersion(final double dRootDispersion) {
this.dRootDispersion = dRootDispersion;
}
 
/**
* Returns the Reference Identifier.
*
* @return the Reference Identifier.
*/
public byte[] getReferenceIdentifier() {
return sReferenceIdentifier;
}
 
/**
* Sets the Reference Identifier.
*
* @param sReferenceIdentifier the Reference Identifier.
*/
public void setReferenceIdentifier(final byte[] sReferenceIdentifier) {
this.sReferenceIdentifier = sReferenceIdentifier;
}
 
/**
* Returns the Reference Timestamp.
*
* @return the Reference Timestamp.
*/
public Timestamp getReferenceTimestamp() {
return tReferenceTimestamp;
}
 
/**
* Sets the Reference Timestamp.
*
* @param tReferenceTimestamp the Reference Timestamp.
*/
public void setReferenceTimestamp(final Timestamp tReferenceTimestamp) {
this.tReferenceTimestamp = tReferenceTimestamp;
}
 
/**
* Returns the Originate Timestamp.
*
* @return the Originate Timestamp.
*/
public Timestamp getOriginateTimestamp() {
return tOriginateTimestamp;
}
 
/**
* Sets the Originate Timestamp.
*
* @param tOriginateTimestamp the Originate Timestamp.
*/
public void setOriginateTimestamp(final Timestamp tOriginateTimestamp) {
this.tOriginateTimestamp = tOriginateTimestamp;
}
 
/**
* Returns the Receive Timestamp.
*
* @return the Receive Timestamp.
*/
public Timestamp getReceiveTimestamp() {
return tReceiveTimestamp;
}
 
/**
* Sets the Receive Timestamp.
*
* @param tReceiveTimestamp the Receive Timestamp.
*/
public void setReceiveTimestamp(final Timestamp tReceiveTimestamp) {
this.tReceiveTimestamp = tReceiveTimestamp;
}
 
/**
* Returns the Transmit Timestamp.
*
* @return the Transmit Timestamp.
*/
public Timestamp getTransmitTimestamp() {
return tTransmitTimestamp;
}
 
/**
* Sets the Transmit Timestamp.
*
* @param tTransmitTimestamp the Transmit Timestamp.
*/
public void setTransmitTimestamp(final Timestamp tTransmitTimestamp) {
this.tTransmitTimestamp = tTransmitTimestamp;
}
 
/**
* Encodes an SNTP message to a byte stream.
*
* @param output the byte stream.
*/
public void encodeMessage(final OutputStream output) throws IOException {
byte flags = (byte) (this.getLeapIndicator() << 6);
flags += (byte) (this.getVersionNumber() << 3);
flags += this.getMode();
output.write(flags);
output.write(this.getStratum());
output.write(this.getPollInterval());
output.write(this.getPrecision());
encodeFixedPoint(this.getRootDelay(), output);
encodeFixedPoint(this.getRootDispersion(), output);
encodeBitstring(this.getReferenceIdentifier(), output);
encodeTimestamp(this.getReferenceTimestamp(), output);
encodeTimestamp(this.getOriginateTimestamp(), output);
encodeTimestamp(this.getReceiveTimestamp(), output);
encodeTimestamp(this.getTransmitTimestamp(), output);
}
 
/**
* Decodes an SNTP message from a byte stream.
*
* @param input the byte stream.
* @return the message.
*/
public static Message decodeMessage(final InputStream input) throws IOException {
final Message message = new Message();
final byte flags = (byte) input.read();
message.setLeapIndicator((byte) (flags >> 6));
message.setVersionNumber((byte) ((flags >> 3) & 0x07));
message.setMode((byte) (flags & 0x07));
message.setStratum((byte) input.read());
message.setPollInterval((byte) input.read());
message.setPrecision((byte) input.read());
message.setRootDelay(decodeFixedPoint(input));
message.setRootDispersion(decodeFixedPoint(input));
message.setReferenceIdentifier(decodeBitstring(input));
message.setReferenceTimestamp(decodeTimestamp(input));
message.setOriginateTimestamp(decodeTimestamp(input));
message.setReceiveTimestamp(decodeTimestamp(input));
message.setTransmitTimestamp(decodeTimestamp(input));
 
return message;
}
 
/**
* Encodes a 32 bit number to a byte stream.
*
* @param number the number to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encode32(final long number, final OutputStream output) throws IOException {
for (int i = 3; i >= 0; i--) {
output.write((int) ((number >> (8 * i)) & 0xFF));
}
}
 
/**
* Decodes a 32 bit number from a byte stream.
*
* @param input the byte stream.
* @return the decoded number.
* @throws IOException if an error occurs while reading from the stream.
*/
private static long decode32(final InputStream input) throws IOException {
long number = 0;
for (int i = 0; i < 4; i++) {
number = (number << 8) + input.read();
}
return number;
}
 
/**
* Encodes a 32-bit bitstring to a byte stream.
*
* @param bitstring the bitstring to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encodeBitstring(final byte[] bitstring, final OutputStream output) throws IOException {
final byte[] temp = { 0, 0, 0, 0 };
System.arraycopy(bitstring, 0, temp, 0, bitstring.length);
output.write(temp);
}
 
/**
* Decodes a 32-bit bitstring from a byte stream.
*
* @param input the byte stream.
* @return the decoded string.
* @throws IOException if an error occurs while reading from the stream.
*/
private static byte[] decodeBitstring(final InputStream input) throws IOException {
final byte[] bitstring = new byte[4];
input.read(bitstring, 0, 4);
 
return bitstring;
}
 
/**
* Encodes a 32 bit fixed-point number to a byte stream.
*
* @param number the fixed-point number to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encodeFixedPoint(final double number, final OutputStream output) throws IOException {
encode32((long) (number * 0x10000L), output);
}
 
/**
* Decodes a 32 bit fixed-point number from a byte stream. The binary point is between bits 15
* and 16.
*
* @param input the byte stream.
* @return the decoded fixed-point number.
* @throws IOException if an error occurs while reading from the stream.
*/
private static double decodeFixedPoint(final InputStream input) throws IOException {
return ((double) decode32(input)) / 0x10000L;
}
 
/**
* Encodes a timestamp to a byte stream.
*
* @param timestamp the timestamp to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encodeTimestamp(final Timestamp timestamp, final OutputStream output) throws IOException {
encode32(timestamp.getInteger(), output);
encode32(timestamp.getFraction(), output);
}
 
/**
* Decodes a timestamp from a byte stream.
*
* @param input the byte stream.
* @return the decoded timestamp.
* @throws IOException if an error occurs while reading from the stream.
*/
private static Timestamp decodeTimestamp(final InputStream input) throws IOException {
final long integer = decode32(input);
final long fraction = decode32(input);
return new Timestamp(integer, fraction);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/SleepingQueue.java
18,6 → 18,7
 
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Collection;
import java.util.Deque;
import java.util.concurrent.Callable;
227,6 → 228,13
}
 
public final void start() {
this.start(null);
}
 
public final void start(final IClosure<Thread> customizeThread) {
customizeThread(this.tasksQueue);
if (customizeThread != null)
customizeThread.executeChecked(this.tasksQueue);
synchronized (this) {
this.tasksQueue.start();
this.setState(RunningState.RUNNING);
338,13 → 346,24
}
 
/**
* An exception was thrown by a task. This implementation merely
* {@link Exception#printStackTrace()}.
* An exception was thrown by a task. This implementation uses
* {@link Thread#getUncaughtExceptionHandler()} or
* {@link Thread#getDefaultUncaughtExceptionHandler()} if available, otherwise falls back to
* just {@link Exception#printStackTrace()}. To set the handler, {@link #start(IClosure)} can be
* used.
*
* @param exn the exception thrown.
*/
protected void exceptionThrown(final ExecutionException exn) {
exn.printStackTrace();
final Thread thr = this.tasksQueue;
UncaughtExceptionHandler h = thr.getUncaughtExceptionHandler();
if (h == null)
h = Thread.getDefaultUncaughtExceptionHandler();
if (h != null) {
h.uncaughtException(thr, exn);
} else {
exn.printStackTrace();
}
}
 
/**
617,7 → 636,6
private final class SingleThreadedExecutor extends DropperQueue<FutureTask<?>> {
private SingleThreadedExecutor() {
super(SleepingQueue.this.name + System.currentTimeMillis());
customizeThread(this);
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/utils/ExceptionUtils.java
81,7 → 81,7
}
 
static public String getStackTrace(Throwable cause) {
final StringWriter res = new StringWriter(128);
final StringWriter res = new StringWriter(8192);
final PrintWriter pw = new PrintWriter(res);
try {
cause.printStackTrace(pw);
/trunk/OpenConcerto/src/org/openconcerto/utils/ExceptionHandler.java
25,6 → 25,7
import java.awt.Desktop.Action;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
47,8 → 48,10
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
66,7 → 69,6
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.JTextComponent;
 
/**
* Allow to display an exception both on the GUI and on the console.
81,6 → 83,9
private static boolean showProbably = false;
private static IFactory<String> softwareInfos = null;
private static ThrowableHandler tHandler = null;
private static boolean safeToExit = false;
private static final CompletableFuture<Boolean> FALSE_FUTURE = CompletableFuture.completedFuture(Boolean.FALSE);
private static final CompletableFuture<Boolean> TRUE_FUTURE = CompletableFuture.completedFuture(Boolean.TRUE);
 
public static void setThrowableHandler(ThrowableHandler handler) {
tHandler = handler;
90,11 → 95,19
forumURL = url;
}
 
public synchronized static void setShowProbably(boolean showProbably) {
public static void setSafeToExit(boolean b) {
safeToExit = b;
}
 
public static void setSubmitErrorAutoEnabled(boolean b) {
submitErrorAuto = b;
}
 
public static synchronized void setShowProbably(boolean showProbably) {
ExceptionHandler.showProbably = showProbably;
}
 
public synchronized static boolean isShowProbably() {
public static synchronized boolean isShowProbably() {
return ExceptionHandler.showProbably;
}
 
120,21 → 133,25
* @param comp the modal parent of the error window.
* @param msg the message to display.
* @param originalExn the cause, can be <code>null</code>.
* @return an exception.
* @return a future completed when the error is handled (e.g. the user clicked on the dialog),
* <code>false</code> if the error couldn't be displayed to the user.
*/
static public ExceptionHandler handle(Component comp, String msg, Throwable originalExn) {
static public Future<Boolean> handle(Component comp, String msg, Throwable originalExn) {
final Future<Boolean> res;
if (tHandler != null && tHandler.handle(msg, originalExn)) {
return new ExceptionHandler(msg, originalExn);
res = TRUE_FUTURE;
} else {
res = new ExceptionHandler(comp, msg, originalExn, false).display();
}
return new ExceptionHandler(comp, msg, originalExn, false);
 
assert res != null;
return res;
}
 
static public RuntimeException handle(String msg, Throwable originalExn) {
static public Future<Boolean> handle(String msg, Throwable originalExn) {
return handle(null, msg, originalExn);
}
 
static public RuntimeException handle(String msg) {
static public Future<Boolean> handle(String msg) {
return handle(msg, null);
}
 
147,7 → 164,9
* @return an exception.
*/
static public RuntimeException die(String msg, Throwable originalExn) {
return new ExceptionHandler(null, msg, originalExn);
final ExceptionHandler res = new ExceptionHandler(null, msg, originalExn);
res.display();
return res;
}
 
static public RuntimeException die(String msg) {
160,27 → 179,31
 
// the comp on which to display the popup, may be null
private final Component comp;
private final Future<?> future;
private final boolean quit;
protected static AtomicInteger openedWindows = new AtomicInteger(0);
private static boolean forceUI;
private static boolean submitErrorAuto = false;
 
public static void setForceUI(boolean forceUI) {
ExceptionHandler.forceUI = forceUI;
}
 
private Future<?> display(final boolean error) {
private Future<Boolean> display() {
final boolean error = this.quit;
final String msg = this.getMessage();
// write out the message as soon as possible
getLogger().log(error ? Level.SEVERE : Level.INFO, null, this);
// then show it to the user
if (!GraphicsEnvironment.isHeadless() || forceUI) {
if (openedWindows.get() > 3) {
return FALSE_FUTURE;
}
final FutureTask<Boolean> run = new FutureTask<>(() -> {
return showMsgHardened(msg, error);
});
if (SwingUtilities.isEventDispatchThread()) {
showMsgHardened(msg, error);
run.run();
} else {
final FutureTask<?> run = new FutureTask<Object>(new Runnable() {
public void run() {
showMsgHardened(msg, error);
}
}, null);
if (error) {
try {
SwingUtilities.invokeAndWait(run);
191,19 → 214,16
} else {
SwingUtilities.invokeLater(run);
}
return run;
}
return run;
}
return null;
return TRUE_FUTURE;
}
 
public final Future<?> getDialogFuture() {
return this.future;
}
 
protected final void showMsgHardened(final String msg, final boolean error) {
protected final Boolean showMsgHardened(final String msg, final boolean error) {
try {
showMsg(msg, error);
return Boolean.TRUE;
} catch (Throwable e) {
// sometimes the VM cannot display the dialog, in that case don't crash the EDT as the
// message has already been logged. Further if this class is used in
217,6 → 237,7
// nothing
}
}
return Boolean.FALSE;
}
 
protected final void showMsg(final String msg, final boolean quit) {
320,62 → 341,6
}
}));
 
final javax.swing.Action submitAction = new AbstractAction("Soumettre l'erreur") {
@Override
public void actionPerformed(ActionEvent e) {
submitError(p, textArea);
}
 
private void submitError(final JPanel p, final JTextComponent textArea) {
final Charset cs = StringUtils.UTF8;
try {
ProductInfo productInfo = ProductInfo.getInstance();
 
String name = "", version = "";
if (productInfo != null) {
name = productInfo.getName();
version = productInfo.getProperty(ProductInfo.VERSION, version);
}
 
final Map<Info, String> systemInfos = SystemInfo.get(false);
final String os = systemInfos.remove(Info.OS);
final String java = systemInfos.toString();
final String encodedData = "java=" + PercentEncoder.encode(java, cs) + "&os=" + PercentEncoder.encode(os, cs) + "&software=" + PercentEncoder.encode(name + version, cs) + "&stack="
+ PercentEncoder.encode(computeSoftwareInformations() + "\n\n" + textArea.getText(), cs);
final String request = "http://bugreport.ilm-informatique.fr:5000/bugreport";
final URL url = new URL(request);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", cs.name());
final byte[] bytes = encodedData.getBytes(cs);
connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
 
final OutputStream outputStream = connection.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
 
// Get the response
final StringBuilder answer = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
answer.append(line);
}
outputStream.close();
reader.close();
connection.disconnect();
 
JOptionPane.showMessageDialog(p, "Merci d'avoir envoyé le rapport d'erreur au service technique.\nIl sera analysé prochainement.");
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
 
btnPanel.add(new JButton(submitAction));
 
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.EAST;
p.add(btnPanel, c);
400,9 → 365,10
message = msg + "\n\n" + message;
}
message += "\n";
message +=
 
getTrace();
message += getTrace();
if (submitErrorAuto) {
submitError(message);
}
textArea.setText(message);
textArea.setEditable(false);
 
420,9 → 386,22
c.fill = GridBagConstraints.NONE;
c.weighty = 0;
c.insets = new Insets(2, 4, 2, 4);
JPanel closePanel = new JPanel();
closePanel.setLayout(new FlowLayout());
if (safeToExit) {
closePanel.add(new JButton(new AbstractAction("Quitter") {
 
@Override
public void actionPerformed(ActionEvent e) {
System.exit(2);
}
}));
}
final JButton buttonClose = new JButton("Fermer");
p.add(buttonClose, c);
closePanel.add(buttonClose);
 
p.add(closePanel, c);
 
final Window window = this.comp == null ? null : SwingUtilities.getWindowAncestor(this.comp);
final JDialog f;
if (window instanceof Frame) {
432,7 → 411,7
}
f.setContentPane(p);
f.pack();
f.setSize(580, 680);
f.setSize(780, 580);
f.setMinimumSize(new Dimension(380, 380));
f.setLocationRelativeTo(this.comp);
final ActionListener al = new ActionListener() {
439,12 → 418,12
 
@Override
public void actionPerformed(ActionEvent e) {
openedWindows.decrementAndGet();
if (quit) {
System.exit(1);
} else {
f.dispose();
}
 
}
};
buttonClose.addActionListener(al);
453,10 → 432,13
@Override
public void windowClosing(WindowEvent e) {
al.actionPerformed(null);
 
}
});
openedWindows.incrementAndGet();
 
f.setVisible(true);
 
}
 
private String getTrace() {
485,13 → 467,65
private ExceptionHandler(Component comp, String msg, Throwable cause, boolean quit) {
super(msg, cause);
this.comp = comp;
this.future = this.display(quit);
this.quit = quit;
}
 
public ExceptionHandler(String msg, Throwable cause) {
super(msg, cause);
this.comp = null;
this.future = null;
private void submitError(String error) {
final Charset cs = StringUtils.UTF8;
try {
ProductInfo productInfo = ProductInfo.getInstance();
 
String name = "", version = "";
if (productInfo != null) {
name = productInfo.getName();
version = productInfo.getProperty(ProductInfo.VERSION, version);
}
 
final Map<Info, String> systemInfos = SystemInfo.get(false);
final String os = systemInfos.remove(Info.OS);
final String java = systemInfos.toString();
final String encodedData = "java=" + PercentEncoder.encode(java, cs) + "&os=" + PercentEncoder.encode(os, cs) + "&software=" + PercentEncoder.encode(name + version, cs) + "&stack="
+ PercentEncoder.encode(computeSoftwareInformations() + "\n\n" + error, cs);
Thread t = new Thread(new Runnable() {
 
@Override
public void run() {
final String request = "http://bugreport.ilm-informatique.fr:5000/bugreport";
try {
System.err.println("ExceptionHandler.submitError");
final URL url = new URL(request);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", cs.name());
final byte[] bytes = encodedData.getBytes(cs);
connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
 
final OutputStream outputStream = connection.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
 
// Get the response
final StringBuilder answer = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
answer.append(line);
}
outputStream.close();
reader.close();
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
 
} catch (Exception ex) {
ex.printStackTrace();
}
}
 
public static void main(String[] args) throws Exception {
498,4 → 532,5
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
ExceptionHandler.handle("Fichier de configuration corrompu\n\nmulti\nline", new IllegalStateException("Id manquant"));
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Grammar_pl.java
Nouveau fichier
0,0 → 1,55
/*
* 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.utils.i18n;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
 
import net.jcip.annotations.Immutable;
 
@Immutable
public class Grammar_pl extends Grammar {
 
static private final Grammar_pl INSTANCE = new Grammar_pl();
 
public static Grammar_pl getInstance() {
return INSTANCE;
}
 
private Grammar_pl() {
this(Locale.forLanguageTag("pl"));
}
 
protected Grammar_pl(final Locale l) {
super(l);
}
 
@Override
protected Collection<? extends VariantKey> createVariantKeys() {
return Arrays.asList(SINGULAR, PLURAL, INDEFINITE_ARTICLE_SINGULAR, INDEFINITE_ARTICLE_PLURAL, DEFINITE_ARTICLE_SINGULAR, DEFINITE_ARTICLE_PLURAL, DEMONSTRATIVE_SINGULAR, DEMONSTRATIVE_PLURAL,
INDEFINITE_NUMERAL, DEFINITE_NUMERAL, DEMONSTRATIVE_NUMERAL, INDEFINITE_ORDINAL, DEFINITE_ORDINAL);
}
 
@Override
protected Collection<? extends NounClass> createNounClasses() {
return Arrays.asList(NounClass.FEMININE, NounClass.MASCULINE, NounClass.NEUTER);
}
 
@Override
public String getVariant(Phrase noun, VariantKey key) {
// TODO
return noun.getBase();
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Phrase.java
18,17 → 18,18
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
 
import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.MessagePattern;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.MessagePattern;
 
/**
* A phrase and its declension. E.g. "light bulb or electrical outlet" and
* "light bulbs or electrical outlets".
* A phrase and its declension. E.g. "light bulb or electrical outlet" and "light bulbs or
* electrical outlets".
*
* @author Sylvain
* @see <a href="Wikipedia">http://en.wikipedia.org/wiki/Declension</a>
46,7 → 47,7
@GuardedBy("this")
private final Map<Object, String> variants;
@GuardedBy("this")
private final Set<Object> explicitVariants;
private final Set<VariantKey> explicitVariants;
 
public Phrase(Grammar grammar, String base, NounClass nounClass) {
super();
61,7 → 62,7
} else {
this.variants = new HashMap<Object, String>();
this.variants.put(null, this.getBase());
this.explicitVariants = new HashSet<Object>();
this.explicitVariants = new HashSet<>();
}
}
 
88,6 → 89,22
return this.putVariant(key, variant, true);
}
 
/**
* Put a variant only if needed, i.e. if {@link #getVariant(VariantKey)} doesn't already return
* <code>variant</code>. This is useful to keep {@link #getExplicitVariants()} to a minimum.
*
* @param key which variant, e.g. plural.
* @param variant the value, e.g. feet.
* @return <code>true</code> if the variant was put.
*/
public final synchronized boolean putVariantIfDifferent(final VariantKey key, final String variant) {
final boolean diff = !variant.equals(this.getVariant(key));
if (diff) {
this.putVariant(key, variant);
}
return diff;
}
 
private final synchronized String putVariant(final VariantKey key, final String variant, final boolean explicit) {
final String res = this.variants.put(key, variant);
if (explicit) {
99,6 → 116,16
}
 
/**
* The variants that have been explicitly set by {@link #putVariant(VariantKey, String)}, as
* opposed to variants computed automatically by the {@link #getGrammar() grammar}.
*
* @return all explicit variants.
*/
public synchronized Set<VariantKey> getExplicitVariants() {
return this.explicitVariants == null ? null : new HashSet<>(this.explicitVariants);
}
 
/**
* Get a variant. If the asked variant wasn't put by {@link #putVariant(VariantKey, String)},
* the {@link #getGrammar() grammar} is {@link Grammar#getVariant(Phrase, VariantKey) used}.
*
140,6 → 167,31
}
 
@Override
public synchronized int hashCode() {
return Objects.hash(this.base, this.explicitVariants, this.grammar, this.nounClass);
}
 
@Override
public synchronized boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Phrase o = (Phrase) obj;
final boolean fast = Objects.equals(this.base, o.base) && Objects.equals(this.explicitVariants, o.explicitVariants) && Objects.equals(this.grammar, o.grammar)
&& Objects.equals(this.nounClass, o.nounClass);
if (!fast || this.variants == null)
return fast;
for (final VariantKey e : this.explicitVariants) {
if (!Objects.equals(this.variants.get(e), o.variants.get(e)))
return false;
}
return true;
}
 
@Override
public String toString() {
final String cl = this.getNounClass() == null ? " " : " (" + this.getNounClass().getName() + ") ";
final String gr = this.getGrammar() == null ? "" : " with " + this.getGrammar();
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/MessageArgs.java
13,15 → 13,15
package org.openconcerto.utils.i18n;
 
import java.util.HashMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeSet;
 
import com.ibm.icu.text.MessageFormat;
 
import net.jcip.annotations.ThreadSafe;
 
import com.ibm.icu.text.MessageFormat;
 
/**
* {@link MessageFormat} can take numbered or named arguments, this class unifies both. This class
* is thread safe if the array or map isn't modified.
33,6 → 33,16
return m instanceof LinkedHashMap;
}
 
static private final MessageArgs EMPTY = new MessageArgs(new Object[0]);
 
public final static MessageArgs getEmpty() {
return EMPTY;
}
 
public final static MessageArgs create(final String key, final Object value) {
return new MessageArgs(Collections.singletonMap(key, value));
}
 
private final boolean mapPrimary;
private Object[] array;
private Map<String, ?> map;
58,7 → 68,7
public final boolean isMapPrimary() {
return this.mapPrimary;
}
 
public final synchronized Object getAll() {
return this.mapPrimary ? this.map : this.array;
}
82,11 → 92,15
protected synchronized Map<String, ?> getMap() {
if (this.map == null) {
final int stop = this.array.length;
final Map<String, Object> res = new HashMap<String, Object>(stop);
for (int i = 0; i < stop; i++) {
res.put(String.valueOf(i), this.array[i]);
if (stop == 0) {
this.map = Collections.emptyMap();
} else {
final Map<String, Object> res = new LinkedHashMap<>(stop);
for (int i = 0; i < stop; i++) {
res.put(String.valueOf(i), this.array[i]);
}
this.map = Collections.unmodifiableMap(res);
}
this.map = res;
}
return this.map;
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Grammar_es.java
Nouveau fichier
0,0 → 1,123
/*
* 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.utils.i18n;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
 
import net.jcip.annotations.Immutable;
 
@Immutable
public class Grammar_es extends Grammar {
 
static private final Grammar_es INSTANCE = new Grammar_es();
 
public static Grammar_es getInstance() {
return INSTANCE;
}
 
private Grammar_es() {
this(Locale.forLanguageTag("es"));
}
 
protected Grammar_es(final Locale l) {
super(l);
}
 
@Override
protected Collection<? extends VariantKey> createVariantKeys() {
return Arrays.asList(SINGULAR, PLURAL, INDEFINITE_ARTICLE_SINGULAR, INDEFINITE_ARTICLE_PLURAL, DEFINITE_ARTICLE_SINGULAR, DEFINITE_ARTICLE_PLURAL, DEMONSTRATIVE_SINGULAR, DEMONSTRATIVE_PLURAL,
INDEFINITE_NUMERAL, DEFINITE_NUMERAL, DEMONSTRATIVE_NUMERAL, INDEFINITE_ORDINAL, DEFINITE_ORDINAL);
}
 
@Override
protected Collection<? extends NounClass> createNounClasses() {
return Arrays.asList(NounClass.FEMININE, NounClass.MASCULINE);
}
 
public final Phrase createPhrase(final String singular) {
return this.createPhrase(singular, null);
}
 
public final Phrase createPhrase(final String singular, final String plural) {
final Phrase res = new Phrase(this, singular, null);
if (plural != null)
res.putVariant(PLURAL, plural);
return res;
}
 
@Override
public String getVariant(Phrase noun, VariantKey key) {
final String res;
if (key.equals(SINGULAR)) {
res = noun.getBase();
} else if (key.equals(INDEFINITE_ARTICLE_SINGULAR)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "una " : "un ") + getSingular(noun);
} else if (key.equals(DEFINITE_ARTICLE_SINGULAR)) {
res = getDefiniteArticle(noun) + getSingular(noun);
} else if (key.equals(DEMONSTRATIVE_SINGULAR)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "esta " : "este ") + getSingular(noun);
} else if (key.equals(PLURAL)) {
res = getPlural(noun.getBase());
} else if (key.equals(INDEFINITE_ARTICLE_PLURAL)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "unas " : "unos ") + getPlural(noun);
} else if (key.equals(DEFINITE_ARTICLE_PLURAL)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "las " : "los ") + getPlural(noun);
} else if (key.equals(DEMONSTRATIVE_PLURAL)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "estas " : "estos ") + getPlural(noun);
} else if (key.equals(INDEFINITE_NUMERAL)) {
res = "{0, plural, =0 {" + getZero(noun) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_NUMERAL)) {
res = "{0, plural, =0 {" + getZero(noun) + "} one {" + getVariant(noun, DEFINITE_ARTICLE_SINGULAR) + "} other {" + (noun.getNounClass() == NounClass.FEMININE ? "las " : "los ") + " # "
+ getPlural(noun) + "}}";
} else if (key.equals(DEMONSTRATIVE_NUMERAL)) {
res = "{0, plural, =0 {" + getZero(noun) + "} one {" + getVariant(noun, DEMONSTRATIVE_SINGULAR) + "} other {" + (noun.getNounClass() == NounClass.FEMININE ? "estas " : "estos ") + " # "
+ getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_ORDINAL) || key.equals(INDEFINITE_ORDINAL)) {
final boolean estFéminin = noun.getNounClass() == NounClass.FEMININE;
final String article = key.equals(DEFINITE_ORDINAL) ? (estFéminin ? "la " : "el ") : "";
res = article + "{0, ordinal, %digits-ordinal" + (estFéminin ? "-feminine" : "") + "} " + getSingular(noun);
} else {
res = null;
}
 
return res;
}
 
protected String getZero(Phrase noun) {
return (noun.getNounClass() == NounClass.MASCULINE ? "ningún " : "ninguna ") + noun.getBase();
}
 
protected String getDefiniteArticle(Phrase noun) {
if (noun.getNounClass() == NounClass.MASCULINE || noun.getBase().startsWith("a") || noun.getBase().startsWith("ha"))
return "el ";
else
return "la ";
}
 
protected String getSingular(Phrase noun) {
final String res = noun.getVariant(SINGULAR);
return res == null ? noun.getBase() : res;
}
 
protected String getPlural(Phrase noun) {
final String res = noun.getVariant(PLURAL);
return res == null ? getPlural(noun.getBase()) : res;
}
 
protected String getPlural(String noun) {
return noun + 's';
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Grammar_fr.java
84,11 → 84,11
} else if (key.equals(DEMONSTRATIVE_PLURAL)) {
res = "ces " + getPlural(noun);
} else if (key.equals(INDEFINITE_NUMERAL)) {
res = "{0, plural, =0 {auc" + getVariant(noun, INDEFINITE_ARTICLE_SINGULAR) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_NUMERAL)) {
res = "{0, plural, =0 {auc" + getVariant(noun, INDEFINITE_ARTICLE_SINGULAR) + "} one {" + getVariant(noun, DEFINITE_ARTICLE_SINGULAR) + "} other {les # " + getPlural(noun) + "}}";
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {" + noun.getVariant(DEFINITE_ARTICLE_SINGULAR) + "} other {les # " + getPlural(noun) + "}}";
} else if (key.equals(DEMONSTRATIVE_NUMERAL)) {
res = "{0, plural, =0 {auc" + getVariant(noun, INDEFINITE_ARTICLE_SINGULAR) + "} one {" + getVariant(noun, DEMONSTRATIVE_SINGULAR) + "} other {ces # " + getPlural(noun) + "}}";
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {" + noun.getVariant(DEMONSTRATIVE_SINGULAR) + "} other {ces # " + getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_ORDINAL) || key.equals(INDEFINITE_ORDINAL)) {
final boolean estFéminin = noun.getNounClass() == NounClass.FEMININE;
final String article = key.equals(DEFINITE_ORDINAL) ? (estFéminin ? "la " : "le ") : "";
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_en.properties
7,7 → 7,7
 
memory=memory
megabytes={0} MB
processors={0} processor{0,choice,1#|1<s}
processors={0, plural, one { # processor } other { # processors } }
os=Operating system
javaVersion=Version <b>{0}</b> of {1}
javaHome=installation directory
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_fr.properties
7,7 → 7,7
 
memory=mémoire
megabytes={0} Mo
processors={0} processor{0,choice,1#|1<s}
processors={0, plural, one { # processeur } other { # processeurs } }
os=Système d''exploitation
javaVersion=Version <b>{0}</b> de {1}
javaHome=dossier d'installation
26,4 → 26,4
 
cut=Couper
copy=Copier
paste=Coller
paste=Coller
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_pl.properties
Nouveau fichier
0,0 → 1,29
true_key=prawdziwe
false_key=fa\u0142szywy
yes_key=tak
no_key=Nie
 
linkOpenError=Error while opening {0}
 
memory=pami\u0119ci
megabytes={0} MB
processors={0, plural, one { # procesora } other { # procesorów } }
os=Operating system
javaVersion=Version <b>{0}</b> of {1}
javaHome=installation directory
no.laf=No look and feel
 
user=u\u017Cytkownika
home.dir=home directory
cwd=current directory
 
network=Network
hardwareAddress=adres sprz\u0119towy
interfaceFullName=full name
interfaceState=state
interfaceStateUp=up
interfaceStateDown=down
 
cut=Wytnij
copy=Kopi\u0119
paste=Wklej
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/LocalizedInstances.java
14,6 → 14,7
package org.openconcerto.utils.i18n;
 
import org.openconcerto.utils.Log;
import org.openconcerto.utils.ReflectUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Value;
 
88,19 → 89,20
// test emptiness to not mix languages
for (Locale targetLocale = locale; targetLocale != null && l.isEmpty(); targetLocale = this.cntrl.getFallbackLocale(baseName, targetLocale)) {
localeRes = targetLocale;
// e.g. "fr_FR", "fr"
for (final Locale candidate : this.cntrl.getCandidateLocales(baseName, targetLocale)) {
// e.g. org.acme.MyClass_fr
final String bundleName = this.cntrl.toBundleName(baseName, candidate);
 
// code first
final Class<?> loadedClass = loadClass(bundleName, cl);
if (loadedClass != null && this.clazz.isAssignableFrom(loadedClass)) {
final Class<? extends T> subclazz = loadedClass.asSubclass(this.clazz);
final Class<? extends T> subclazz = ReflectUtils.getSubclass(bundleName, this.clazz, cl.getClassLoader());
if (subclazz != null) {
try {
final Value<? extends T> instance = this.getInstance(subclazz);
if (instance.hasValue())
l.add(instance.getValue());
else
Log.get().warning(loadedClass + " exists but the constructor wasn't found");
Log.get().warning(subclazz + " exists but the constructor wasn't found");
} catch (Exception e) {
Log.get().log(Level.WARNING, "Couldn't create an instance using " + subclazz, e);
}
118,14 → 120,6
return Tuple2.create(localeRes, l);
}
 
private final Class<?> loadClass(final String name, final Class<?> cl) {
try {
return Class.forName(name, true, cl.getClassLoader());
} catch (ClassNotFoundException e) {
return null;
}
}
 
/**
* The no-arg static method to use.
*
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/TM.java
21,6 → 21,7
import java.beans.Introspector;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
28,6 → 29,7
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
49,7 → 51,35
public class TM {
 
static public enum MissingMode {
EXCEPTION, NULL, STRING
EXCEPTION {
@Override
protected String returnMissing(TM tm, String key) throws MissingResourceException {
throw new MissingResourceException("Missing translation", tm.getBaseName(), key);
}
},
NULL {
@Override
protected String returnMissing(TM tm, String key) {
return null;
}
},
STRING {
@Override
protected String returnMissing(TM tm, String key) {
return '!' + key + '!';
}
};
 
protected abstract String returnMissing(final TM tm, final String key) throws MissingResourceException;
 
// method to avoid array allocation and Arrays.toString()
protected final String returnResult(final TM tm, final String res, final String key) throws MissingResourceException {
return res == null ? this.returnMissing(tm, key) : res;
}
 
protected final String returnResult(final TM tm, final String res, final String... keys) throws MissingResourceException {
return res == null ? this.returnMissing(tm, Arrays.toString(keys)) : res;
}
}
 
static public final String NOUN_CLASS_PROP = "nounClass";
178,20 → 208,39
}
 
public final String translate(final MissingMode mode, final String key, final Object... args) throws MissingResourceException {
return translate(mode, key, new MessageArgs(args));
return translate(mode, key, args.length == 0 ? MessageArgs.getEmpty() : new MessageArgs(args));
}
 
public final String translateFirst(final MissingMode mode, final String... keys) throws MissingResourceException {
return translateFirst(mode, MessageArgs.getEmpty(), keys);
}
 
/**
* Return the first non-<code>null</code> result.
*
* @param mode what to do if all keys are <code>null</code>.
* @param args the arguments.
* @param keys the keys to search for.
* @return the first non-<code>null</code> result.
* @throws MissingResourceException if {@link MissingMode#EXCEPTION} and all keys are
* <code>null</code>.
*/
public final String translateFirst(final MissingMode mode, final MessageArgs args, final String... keys) throws MissingResourceException {
String res = null;
for (int i = 0; i < keys.length && res == null; i++) {
final String key = keys[i];
if (key != null)
res = this.translate(MissingMode.NULL, key, args);
}
return mode.returnResult(this, res, keys);
}
 
private final String translate(final MissingMode mode, final String key, MessageArgs args) throws MissingResourceException {
Objects.requireNonNull(mode, "Null mode");
Objects.requireNonNull(key, "Null key");
Objects.requireNonNull(args, "Null arguments");
final String res = this.translations.translate(key, args);
if (res == null) {
if (mode == MissingMode.STRING)
return '!' + key + '!';
else if (mode == MissingMode.NULL)
return null;
else
throw new MissingResourceException("Missing translation", this.getBaseName(), key);
}
return res;
return mode.returnResult(this, res, key);
}
 
protected MessageArgs replaceMap(final MessageArgs args, final String msg) {
/trunk/OpenConcerto/src/org/openconcerto/utils/CompareUtils.java
312,4 → 312,12
}
return null;
}
 
static public final <T extends Comparable<? super T>> T min(final T o1, final T o2) {
return o1.compareTo(o2) < 0 ? o1 : o2;
}
 
static public final <T extends Comparable<? super T>> T max(final T o1, final T o2) {
return o1.compareTo(o2) < 0 ? o2 : o1;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/MimeType.java
Nouveau fichier
0,0 → 1,205
/*
* 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.
*/
/*
* Copyright 2007-2009 Medsea Business Solutions S.L.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.openconcerto.utils.mime;
 
import java.io.Serializable;
import java.util.regex.Pattern;
 
/**
* This class represents a simple MimeType object. A mime type is made up of two parts
* <code>&lt;media type&gt;/&lt;sub type&gt;</code>. The media type can be something like
* <code>application</code> or <code>text</code> and the the sub type can be something like
* <code>xml</code> or <code>plain</code>.
*
* Both the media type and sub type can also be the wild card <code>*</code> such as
* <code>*&#47;*</code> and <code>text&#47;*</code>. Note, if the media type is the wild card then
* the sub type must also be a wild card.
*
* @author Steven McArdle
*
*/
public class MimeType implements Serializable {
 
private static final long serialVersionUID = -1324243127744494894L;
 
private static final Pattern mimeSplitter = Pattern.compile("[/;]++");
 
protected String mediaType = "*";
protected String subType = "*";
 
// This is a estimate of how specific this mime type is
private int specificity = 1;
 
/**
* Construct a MimeType from another MimeType instance
*
* @param mimeType
*/
public MimeType(final MimeType mimeType) {
this.mediaType = mimeType.mediaType;
this.subType = mimeType.subType;
this.specificity = mimeType.specificity;
}
 
/**
* Construct a mime type from a String such as <code>text/plain</code>. It tries to ensure that
* the mime type pattern passed in is correctly formatted.
*
* @param mimeType
* @throws IllegalArgumentException
*/
public MimeType(final String mimeType) throws IllegalArgumentException {
if (mimeType == null || mimeType.trim().length() == 0) {
throw new IllegalArgumentException("Invalid MimeType [" + mimeType + "]");
}
String[] parts = mimeSplitter.split(mimeType.trim());
 
if (parts.length > 0) {
// Treat as the mediaType
mediaType = getValidMediaType(parts[0]);
}
if (parts.length > 1) {
subType = getValidSubType(parts[1]);
}
}
 
/**
* Get the media type part of the mime type.
*
* @return media type
*/
public String getMediaType() {
return mediaType;
}
 
/**
* Get the sub type of the mime type
*
* @return sub type
*/
public String getSubType() {
return subType;
}
 
/**
* See if this MimeType is the same as the passed in mime type string
*
* @param mimeType as a String
* @return true if the MimeType passed in has the same media and sub types, else returns false.
*/
private boolean match(final String mimeType) {
return toString().equals(mimeType);
}
 
/**
* Get the hashCode of this MimeType. The hashCode is calculate as (31 * mediaType.hashCode()) +
* subType.hashCode()
*
* @return calculated hashCode
* @see Object#hashCode()
*/
public int hashCode() {
return (31 * mediaType.hashCode()) + subType.hashCode();
}
 
/**
* Overrides the equals method of <code>java.lang.Object</code>. This is able to compare against
* another MimeType instance or a string representation of a mime type.
*
* @return true if the types match else false.
* @see Object#equals(Object o)
*/
public boolean equals(Object o) {
if (o instanceof MimeType) {
if (this.mediaType.equals(((MimeType) o).mediaType) && this.subType.equals(((MimeType) o).subType)) {
return true;
}
} else if (o instanceof String) {
return match((String) o);
}
return false;
}
 
/**
* Overrides the toString method of <code>java.lang.Object</code>.
*
* @return String representation i.e. <code>&lt;media type&gt;/&lt;sub type&gt;.
* @see Object#toString()
*/
public String toString() {
return mediaType + "/" + subType;
}
 
/**
* This indicates how specific the mime types is i.e. how good a match the mime type is when
* returned from the getMimeTypes(...) calls.
* <p>
* This is calculated by the number of times this MimeType would be returned if the Collection
* was not normalised. The higher the count the more MimeDetectors have matched this type. As
* this can be a false positive for types such as application/octect-stream and text/plain where
* they would be returned by multiple MimeDetector(s). These types are referred to as root mime
* types where ALL mime types derive from application/octet-stream and all text/* types derive
* from text/plan so in these cases we set the specificity to 0 no matter how many times they
* match. This ensures they are regarded as the least specific in the returned Collection.
* </p>
*
* @return how specific this MimeType is according to the rest of the MimeTypes in a Collection.
*/
public int getSpecificity() {
return specificity;
}
 
/*
* Set the value of the specificity. The higher the value the more specific a MimeType is.
*/
void setSpecificity(final int specificity) {
this.specificity = specificity;
}
 
/*
* Check the media type at least looks valid. TODO: Enforce more rigorous checking of valid
* media types.
*/
private String getValidMediaType(final String mediaType) {
if (mediaType == null || mediaType.trim().length() == 0) {
return "*";
}
return mediaType;
}
 
/*
* Check the sub type at least looks valid. TODO: Enforce more rigorous checking of valid sub
* types.
*/
private String getValidSubType(final String subType) {
if (subType == null || subType.trim().length() == 0 || "*".equals(mediaType)) {
// If the mediaType is a wild card then the sub type must also be a wild card
return "*";
}
return subType;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/mime.cache
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/mime.cache
Nouveau fichier
Changements de propriété:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: OpenConcerto/src/org/openconcerto/utils/mime/FreeDesktopMimeDetector.java
===================================================================
--- OpenConcerto/src/org/openconcerto/utils/mime/FreeDesktopMimeDetector.java (revision 0)
+++ OpenConcerto/src/org/openconcerto/utils/mime/FreeDesktopMimeDetector.java (revision 156)
@@ -0,0 +1,772 @@
+/*
+ * 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.utils.mime;
+
+/*
+ * Copyright 2007-2009 Medsea Business Solutions S.L.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+import org.openconcerto.utils.CollectionUtils;
+import org.openconcerto.utils.Log;
+import org.openconcerto.utils.OSFamily;
+import org.openconcerto.utils.StreamUtils;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+import java.nio.file.spi.FileTypeDetector;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * The Opendesktop shared mime database contains glob rules and magic number lookup information to
+ * enable applications to detect the mime types of files.
+ * </p>
+ * <p>
+ * This class uses the mime.cache file which is one of the files created by the update-mime-database
+ * application. This file is a memory mapped file that enables the database to be updated and copied
+ * without interrupting applications.
+ * </p>
+ * <p>
+ * This implementation follows the memory mapped spec so it is not required to restart an
+ * application using this mime detector should the underlying mime.cache database change.
+ * </p>
+ * <p>
+ * For a complete description of the information contained in this file please see:
+ * http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
+ * </p>
+ * <p>
+ * This class also follows, where possible, the RECOMENDED order of detection as detailed in this
+ * spec. Thanks go to Mathias Clasen at Red Hat for pointing me to the original xdgmime
+ * implementation http://svn.gnome.org/viewvc/glib/trunk/
+ * gio/xdgmime/xdgmimecache.c?revision=7784&view=markup
+ * </p>
+ * More up to date : https://github.com/GNOME/beagle/blob/master/beagle/glue/xdgmime/xdgmimecache.c
+ *
+ * @author Steven McArdle
+ * @see <a
+ * href="http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html">Shared
+ * MIME-Info</a>
+ */
+@SuppressWarnings({ "unqualified-field-access" })
+public class FreeDesktopMimeDetector extends FileTypeDetector {
+
+ public static enum Mode {
+ /**
+ * <a href=
+ * "http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html#idm140625828606432"
+ * >Recommended checking order</a>
+ */
+ RECOMMENDED, DATA_ONLY, NAME_ONLY
+ }
+
+ public static final String DEFAULT_CACHE = "freeDesktop.mime.cache";
+ public static final String DEFAULT_MODE = "freeDesktop.mime.mode";
+
+ static private Mode getDefaultMode() {
+ final String m = System.getProperty(DEFAULT_MODE);
+ if (m != null) {
+ try {
+ return Mode.valueOf(m.toUpperCase());
+ } catch (Exception e) {
+ Log.get().log(Level.CONFIG, "Ignoring invalid mode : " + m, e);
+ }
+ }
+ return Mode.RECOMMENDED;
+ }
+
+ private static File mimeCacheFile = OSFamily.getInstance() == OSFamily.Windows ? null : new File("/usr/share/mime/mime.cache");
+
+ static private boolean canReadFile(final File f, final String msg) {
+ if (f == null)
+ return false;
+ final boolean res = f.isFile() && f.canRead();
+ if (!res)
+ Log.get().config(msg + f);
+ return res;
+ }
+
+ static private Object getDefaultCache() {
+ final String m = System.getProperty(DEFAULT_CACHE);
+ final File f = m != null ? new File(m) : null;
+ if (canReadFile(f, "Ignoring invalid passed file : ")) {
+ return f;
+ } else if (canReadFile(mimeCacheFile, "Ignoring invalid system file : ")) {
+ return mimeCacheFile;
+ } else {
+ final URL res = FreeDesktopMimeDetector.class.getResource("mime.cache");
+ if (res == null)
+ throw new IllegalStateException("No mime.cache found for " + FreeDesktopMimeDetector.class);
+ return res;
+ }
+ }
+
+ private final ByteBuffer content;
+ private final Mode mode;
+
+ public FreeDesktopMimeDetector() throws IOException {
+ this(getDefaultCache(), getDefaultMode());
+ }
+
+ public FreeDesktopMimeDetector(final File mimeCacheFile, final Mode mode) throws IOException {
+ this((Object) mimeCacheFile, mode);
+ }
+
+ public FreeDesktopMimeDetector(final InputStream is, final Mode mode) throws IOException {
+ this((Object) is, mode);
+ }
+
+ // InputStream will be closed
+ private FreeDesktopMimeDetector(final Object cache, final Mode mode) throws IOException {
+ if (cache instanceof File || cache instanceof FileInputStream) {
+ // Map the mime.cache file as a memory mapped file
+ try (final FileInputStream is = cache instanceof FileInputStream ? (FileInputStream) cache : new FileInputStream((File) cache); final FileChannel rCh = is.getChannel();) {
+ content = rCh.map(FileChannel.MapMode.READ_ONLY, 0, rCh.size());
+ }
+ } else {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream(250 * 1024);
+ try (final InputStream is = cache instanceof URL ? ((URL) cache).openStream() : (InputStream) cache) {
+ StreamUtils.copy(is, out);
+ }
+ content = ByteBuffer.wrap(out.toByteArray());
+ }
+ this.mode = mode;
+ }
+
+ @Override
+ public String probeContentType(Path path) throws IOException {
+ final Collection<String> col;
+ switch (this.mode) {
+ case RECOMMENDED:
+ col = this.getMimeTypesFile(path.toFile());
+ break;
+ case DATA_ONLY:
+ try (final InputStream is = new BufferedInputStream(new FileInputStream(path.toFile()))) {
+ col = this.getMimeTypesInputStream(is);
+ }
+ break;
+ case NAME_ONLY:
+ col = this.getMimeTypesFileName(path.getFileName().toString());
+ break;
+ default:
+ throw new IllegalStateException("Unknown mode : " + this.mode);
+ }
+ return CollectionUtils.getFirst(col);
+ }
+
+ /**
+ * This method resolves mime types closely in accordance with the RECOMENDED order of detection
+ * detailed in the Opendesktop shared mime database specification
+ * http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html See
+ * the Recommended checking order.
+ *
+ * @param fileName the name to inspect.
+ * @return a collection of MIME types.
+ */
+ public Collection<String> getMimeTypesFileName(String fileName) {
+ Collection<WeightedMimeType> mimeTypes = new ArrayList<WeightedMimeType>();
+ // Lookup the globbing methods first
+ lookupMimeTypesForGlobFileName(fileName, mimeTypes);
+
+ return normalizeWeightedMimeList(mimeTypes);
+ }
+
+ /**
+ * This method resolves mime types closely in accordance with the RECOMENDED order of detection
+ * detailed in the Opendesktop shared mime database specification
+ * http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html See
+ * the Recommended checking order.
+ *
+ * @param file the file to inspect.
+ * @return a collection of MIME types.
+ * @throws IOException if the file couldn't be read.
+ */
+ public Collection<String> getMimeTypesFile(File file) throws IOException {
+ Collection<String> mimeTypes = getMimeTypesFileName(file.getName());
+ if (!file.exists()) {
+ return mimeTypes;
+ }
+ try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) {
+ return _getMimeTypes(mimeTypes, is);
+ }
+ }
+
+ /**
+ * This method is unable to perform glob matching as no name is available. This means that it
+ * does not follow the recommended order of detection defined in the shared mime database spec
+ * http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
+ *
+ * @param in the stream to inspect.s
+ * @return a collection of MIME types.
+ * @throws IOException if the stream couldn't be read.
+ */
+ public Collection<String> getMimeTypesInputStream(InputStream in) throws IOException {
+ return lookupMimeTypesForMagicData(in);
+ }
+
+ /**
+ * This method is unable to perform glob matching as no name is available. This means that it
+ * does not follow the recommended order of detection defined in the shared mime database spec
+ * http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
+ *
+ * @param data the data to inspect.
+ * @return a collection of MIME types.
+ */
+ public Collection<String> getMimeTypesByteArray(byte[] data) {
+ return lookupMagicData(data);
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " using the mime.cache file version [" + getMajorVersion() + "." + getMinorVersion() + "].";
+ }
+
+ public String dump() {
+ return "{MAJOR_VERSION=" + getMajorVersion() + " MINOR_VERSION=" + getMinorVersion() + " ALIAS_LIST_OFFSET=" + getAliasListOffset() + " PARENT_LIST_OFFSET=" + getParentListOffset()
+ + " LITERAL_LIST_OFFSET=" + getLiteralListOffset() + " REVERSE_SUFFIX_TREE_OFFSET=" + getReverseSuffixTreeOffset() + " GLOB_LIST_OFFSET=" + getGlobListOffset() + " MAGIC_LIST_OFFSET="
+ + getMagicListOffset() + " NAMESPACE_LIST_OFFSET=" + getNameSpaceListOffset() + " ICONS_LIST_OFFSET=" + getIconListOffset() + " GENERIC_ICONS_LIST_OFFSET="
+ + getGenericIconListOffset() + "}";
+ }
+
+ private Collection<String> lookupMimeTypesForMagicData(InputStream in) throws IOException {
+ int offset = 0;
+ int len = getMaxExtents();
+ byte[] data = new byte[len];
+ // Mark the input stream
+ in.mark(len);
+
+ try {
+ // Since an InputStream might return only some data (not all
+ // requested), we have to read in a loop until
+ // either EOF is reached or the desired number of bytes have been
+ // read.
+ int restBytesToRead = len;
+ while (restBytesToRead > 0) {
+ int bytesRead = in.read(data, offset, restBytesToRead);
+ if (bytesRead < 0)
+ break; // EOF
+
+ offset += bytesRead;
+ restBytesToRead -= bytesRead;
+ }
+ } finally {
+ // Reset the input stream to where it was marked.
+ in.reset();
+ }
+ return lookupMagicData(data);
+ }
+
+ private Collection<String> lookupMagicData(byte[] data) {
+
+ Collection<String> mimeTypes = new ArrayList<String>();
+
+ int listOffset = getMagicListOffset();
+ int numEntries = content.getInt(listOffset);
+ int offset = content.getInt(listOffset + 8);
+
+ for (int i = 0; i < numEntries; i++) {
+ final int matchOffset = offset + (16 * i);
+ final String mimeType = compareToMagicData(matchOffset, data);
+ if (mimeType != null) {
+ mimeTypes.add(mimeType);
+ } else {
+ final String nonMatch = getMimeType(content.getInt(matchOffset + 4));
+ mimeTypes.remove(nonMatch);
+ }
+ }
+
+ return mimeTypes;
+ }
+
+ private String compareToMagicData(int offset, byte[] data) {
+ // TODO
+ // int priority = content.getInt(offset);
+ int mimeOffset = content.getInt(offset + 4);
+ int numMatches = content.getInt(offset + 8);
+ int matchletOffset = content.getInt(offset + 12);
+
+ for (int i = 0; i < numMatches; i++) {
+ if (matchletMagicCompare(matchletOffset + (i * 32), data)) {
+ return getMimeType(mimeOffset);
+ }
+ }
+ return null;
+ }
+
+ private boolean matchletMagicCompare(int offset, byte[] data) {
+ int n_children = content.getInt(offset + 24);
+ int child_offset = content.getInt(offset + 28);
+
+ if (magic_matchlet_compare_to_data(offset, data)) {
+ if (n_children == 0)
+ return true;
+
+ for (int i = 0; i < n_children; i++) {
+ if (matchletMagicCompare(child_offset + 32 * i, data))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean magic_matchlet_compare_to_data(int offset, byte[] data) {
+ int rangeStart = content.getInt(offset);
+ int rangeLength = content.getInt(offset + 4);
+ int dataLength = content.getInt(offset + 12);
+ int dataOffset = content.getInt(offset + 16);
+ int maskOffset = content.getInt(offset + 20);
+
+ for (int i = rangeStart; i <= rangeStart + rangeLength; i++) {
+ boolean validMatch = true;
+ if (i + dataLength > data.length) {
+ return false;
+ }
+ if (maskOffset != 0) {
+ for (int j = 0; j < dataLength; j++) {
+ if ((content.get(dataOffset + j) & content.get(maskOffset + j)) != (data[j + i] & content.get(maskOffset + j))) {
+ validMatch = false;
+ break;
+ }
+ }
+ } else {
+ for (int j = 0; j < dataLength; j++) {
+ if (content.get(dataOffset + j) != data[j + i]) {
+ validMatch = false;
+ break;
+ }
+ }
+ }
+
+ if (validMatch) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void lookupGlobLiteral(String fileName, Collection<WeightedMimeType> mimeTypes) {
+ int listOffset = getLiteralListOffset();
+ int numEntries = content.getInt(listOffset);
+
+ int min = 0;
+ int max = numEntries - 1;
+ while (max >= min) {
+ int mid = (min + max) / 2;
+ String literal = getString(content.getInt((listOffset + 4) + (12 * mid)));
+ int cmp = literal.compareTo(fileName);
+ if (cmp < 0) {
+ min = mid + 1;
+ } else if (cmp > 0) {
+ max = mid - 1;
+ } else {
+ String mimeType = getMimeType(content.getInt((listOffset + 4) + (12 * mid) + 4));
+ int weight = content.getInt((listOffset + 4) + (12 * mid) + 8);
+ mimeTypes.add(new WeightedMimeType(mimeType, literal, weight));
+ return;
+ }
+ }
+ }
+
+ private void lookupGlobFileNameMatch(String fileName, Collection<WeightedMimeType> mimeTypes) {
+ final int listOffset = getGlobListOffset();
+ final int numEntries = content.getInt(listOffset);
+ final int entriesOffset = listOffset + 4;
+
+ for (int i = 0; i < numEntries; i++) {
+ final int entryOffset = entriesOffset + 12 * 1;
+ final int offset = content.getInt(entryOffset);
+ final int mimeTypeOffset = content.getInt(entryOffset + 4);
+ final int weightNFlags = content.getInt(entryOffset + 8);
+ final int weight = weightNFlags & 0xFF;
+ final boolean cs = (weightNFlags & 0x100) != 0;
+
+ final Pattern pattern = Pattern.compile(getString(offset, true), !cs ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
+ if (pattern.matcher(fileName).matches()) {
+ final String mimeType = getMimeType(mimeTypeOffset);
+ final String globPattern = getString(offset, false);
+ mimeTypes.add(new WeightedMimeType(mimeType, globPattern, weight));
+ }
+ }
+ }
+
+ private Collection<String> normalizeWeightedMimeList(Collection<WeightedMimeType> weightedMimeTypes) {
+ if (weightedMimeTypes.isEmpty())
+ return Collections.emptySet();
+ Collection<WeightedMimeType> mimeTypes = new LinkedHashSet<WeightedMimeType>();
+
+ // Sort the weightedMimeTypes
+ Collections.sort((List<WeightedMimeType>) weightedMimeTypes, new Comparator<WeightedMimeType>() {
+ public int compare(WeightedMimeType obj1, WeightedMimeType obj2) {
+ return obj1.weight - obj2.weight;
+ }
+ });
+
+ // Keep only globs with the biggest weight. They are in weight order at
+ // this point
+ int weight = 0;
+ int patternLen = 0;
+ for (final WeightedMimeType mw : weightedMimeTypes) {
+ if (weight < mw.weight) {
+ weight = mw.weight;
+ }
+ if (weight >= mw.weight) {
+ if (mw.pattern.length() > patternLen) {
+ patternLen = mw.pattern.length();
+ }
+ mimeTypes.add(mw);
+ }
+ }
+
+ // Now keep only the longest patterns
+ for (final WeightedMimeType mw : weightedMimeTypes) {
+ if (mw.pattern.length() < patternLen) {
+ mimeTypes.remove(mw);
+ }
+ }
+
+ // Could possibly have multiple mimeTypes here with the same weight and
+ // pattern length. Can even have multiple entries for the same type so
+ // lets remove
+ // any duplicates by copying entries to a HashSet that can only have a
+ // single instance
+ // of each type
+ Collection<String> _mimeTypes = new HashSet<String>();
+ for (final WeightedMimeType mw : mimeTypes) {
+ _mimeTypes.add(mw.toString());
+ }
+ return _mimeTypes;
+ }
+
+ private void lookupMimeTypesForGlobFileName(String fileName, Collection<WeightedMimeType> mimeTypes) {
+ if (fileName == null) {
+ return;
+ }
+
+ lookupGlobLiteral(fileName, mimeTypes);
+ if (!mimeTypes.isEmpty()) {
+ return;
+ }
+
+ int len = fileName.length();
+ lookupGlobSuffix(fileName, false, len, mimeTypes);
+ if (mimeTypes.isEmpty()) {
+ lookupGlobSuffix(fileName, true, len, mimeTypes);
+ }
+
+ if (mimeTypes.isEmpty()) {
+ lookupGlobFileNameMatch(fileName, mimeTypes);
+ }
+ }
+
+ private void lookupGlobSuffix(String fileName, boolean ignoreCase, int len, Collection<WeightedMimeType> mimeTypes) {
+ int listOffset = getReverseSuffixTreeOffset();
+ int numEntries = content.getInt(listOffset);
+ int offset = content.getInt(listOffset + 4);
+
+ lookupGlobNodeSuffix(fileName, numEntries, offset, ignoreCase, len, mimeTypes, new StringBuffer());
+ }
+
+ private void lookupGlobNodeSuffix(final String fileName, final int numEntries, final int offset, final boolean ignoreCase, int len, Collection<WeightedMimeType> mimeTypes, StringBuffer pattern) {
+ final char character = ignoreCase ? fileName.toLowerCase().charAt(len - 1) : fileName.charAt(len - 1);
+
+ if (character == 0) {
+ return;
+ }
+
+ int min = 0;
+ int max = numEntries - 1;
+ while (max >= min && len >= 0) {
+ int mid = (min + max) / 2;
+
+ char matchChar = (char) content.getInt(offset + (12 * mid));
+ if (ignoreCase)
+ matchChar = Character.toLowerCase(matchChar);
+ if (matchChar < character) {
+ min = mid + 1;
+ } else if (matchChar > character) {
+ max = mid - 1;
+ } else {
+ len--;
+ // first leaf nodes (matchChar==0) then tree nodes
+ final int numChildren = content.getInt(offset + (12 * mid) + 4);
+ final int firstChildOffset = content.getInt(offset + (12 * mid) + 8);
+ if (len > 0) {
+ pattern.append(matchChar);
+ lookupGlobNodeSuffix(fileName, numChildren, firstChildOffset, ignoreCase, len, mimeTypes, pattern);
+ }
+ // if the name did not match a longer pattern, try to match this one
+ if (mimeTypes.isEmpty()) {
+ for (int i = 0; i < numChildren; i++) {
+ final int childOffset = firstChildOffset + (12 * i);
+ if (content.getInt(childOffset) != 0) {
+ // not a leaf node anymore
+ break;
+ }
+
+ final int mimeOffset = content.getInt(childOffset + 4);
+ final int weightNFlags = content.getInt(childOffset + 8);
+ final int weight = weightNFlags & 0xFF;
+ final boolean cs = (weightNFlags & 0x100) != 0;
+
+ if (!(cs && ignoreCase))
+ mimeTypes.add(new WeightedMimeType(getMimeType(mimeOffset), pattern.toString(), weight));
+ }
+ }
+ return;
+ }
+ }
+ }
+
+ static class WeightedMimeType extends MimeType {
+
+ private static final long serialVersionUID = 1L;
+ String pattern;
+ int weight;
+
+ WeightedMimeType(String mimeType, String pattern, int weight) {
+ super(mimeType);
+ this.pattern = pattern;
+ this.weight = weight;
+ }
+ }
+
+ private int getMaxExtents() {
+ return content.getInt(getMagicListOffset() + 4);
+ }
+
+ private String aliasLookup(String alias) {
+ int aliasListOffset = getAliasListOffset();
+ int min = 0;
+ int max = content.getInt(aliasListOffset) - 1;
+
+ while (max >= min) {
+ int mid = (min + max) / 2;
+ // content.position((aliasListOffset + 4) + (mid * 8));
+
+ int aliasOffset = content.getInt((aliasListOffset + 4) + (mid * 8));
+ int mimeOffset = content.getInt((aliasListOffset + 4) + (mid * 8) + 4);
+
+ int cmp = getMimeType(aliasOffset).compareTo(alias);
+ if (cmp < 0) {
+ min = mid + 1;
+ } else if (cmp > 0) {
+ max = mid - 1;
+ } else {
+ return getMimeType(mimeOffset);
+ }
+ }
+ return null;
+ }
+
+ private String unaliasMimeType(String mimeType) {
+ String lookup = aliasLookup(mimeType);
+ return lookup == null ? mimeType : lookup;
+ }
+
+ private boolean isMimeTypeSubclass(String mimeType, String subClass) {
+ String umimeType = unaliasMimeType(mimeType);
+ String usubClass = unaliasMimeType(subClass);
+ MimeType _mimeType = new MimeType(umimeType);
+ MimeType _subClass = new MimeType(usubClass);
+
+ if (umimeType.compareTo(usubClass) == 0) {
+ return true;
+ }
+
+ if (isSuperType(usubClass) && (_mimeType.getMediaType().equals(_subClass.getMediaType()))) {
+ return true;
+ }
+
+ // Handle special cases text/plain and application/octet-stream
+ if (usubClass.equals("text/plain") && _mimeType.getMediaType().equals("text")) {
+ return true;
+ }
+
+ if (usubClass.equals("application/octet-stream")) {
+ return true;
+ }
+ int parentListOffset = getParentListOffset();
+ int numParents = content.getInt(parentListOffset);
+ int min = 0;
+ int max = numParents - 1;
+ while (max >= min) {
+ int med = (min + max) / 2;
+ int offset = content.getInt((parentListOffset + 4) + (8 * med));
+ String parentMime = getMimeType(offset);
+ int cmp = parentMime.compareTo(umimeType);
+ if (cmp < 0) {
+ min = med + 1;
+ } else if (cmp > 0) {
+ max = med - 1;
+ } else {
+ offset = content.getInt((parentListOffset + 4) + (8 * med) + 4);
+ int _numParents = content.getInt(offset);
+ for (int i = 0; i < _numParents; i++) {
+ int parentOffset = content.getInt((offset + 4) + (4 * i));
+ if (isMimeTypeSubclass(getMimeType(parentOffset), usubClass)) {
+ return true;
+ }
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+ private boolean isSuperType(String mimeType) {
+ return mimeType.endsWith("/*");
+ }
+
+ private int getGenericIconListOffset() {
+ return content.getInt(36);
+ }
+
+ private int getIconListOffset() {
+ return content.getInt(32);
+ }
+
+ private int getNameSpaceListOffset() {
+ return content.getInt(28);
+ }
+
+ private int getMagicListOffset() {
+ return content.getInt(24);
+ }
+
+ private int getGlobListOffset() {
+ return content.getInt(20);
+ }
+
+ private int getReverseSuffixTreeOffset() {
+ return content.getInt(16);
+ }
+
+ private int getLiteralListOffset() {
+ return content.getInt(12);
+ }
+
+ private int getParentListOffset() {
+ return content.getInt(8);
+ }
+
+ private int getAliasListOffset() {
+ return content.getInt(4);
+ }
+
+ private short getMinorVersion() {
+ return content.getShort(2);
+ }
+
+ private short getMajorVersion() {
+ return content.getShort(0);
+ }
+
+ private String getMimeType(int offset) {
+ return getString(offset);
+ }
+
+ private String getString(int offset) {
+ return getString(offset, false);
+ }
+
+ private String getString(int offset, boolean regularExpression) {
+ int position = content.position();
+ content.position(offset);
+ StringBuffer buf = new StringBuffer();
+ char c = 0;
+ while ((c = (char) content.get()) != 0) {
+ if (regularExpression) {
+ switch (c) {
+ case '.':
+ buf.append("\\");
+ break;
+ case '*':
+ case '+':
+ case '?':
+ buf.append(".");
+ }
+ }
+ buf.append(c);
+ }
+ // Reset position
+ content.position(position);
+
+ if (regularExpression) {
+ buf.insert(0, '^');
+ buf.append('$');
+ }
+ return buf.toString();
+ }
+
+ private Collection<String> _getMimeTypes(Collection<String> mimeTypes, final InputStream in) throws IOException {
+ if (mimeTypes.isEmpty() || mimeTypes.size() > 1) {
+ Collection<String> _mimeTypes = getMimeTypesInputStream(in);
+
+ if (!_mimeTypes.isEmpty()) {
+ if (!mimeTypes.isEmpty()) {
+ // more than one glob matched
+
+ // Check for same mime type
+ for (final String mimeType : mimeTypes) {
+ if (_mimeTypes.contains(mimeType)) {
+ // mimeTypes = new ArrayList();
+ mimeTypes.add(mimeType);
+ // return mimeTypes;
+ }
+ // Check for mime type subtype
+ for (final String _mimeType : _mimeTypes) {
+ if (isMimeTypeSubclass(mimeType, _mimeType)) {
+ // mimeTypes = new ArrayList();
+ mimeTypes.add(mimeType);
+ // return mimeTypes;
+ }
+ }
+ }
+ } else {
+ // No globs matched but we have magic matches
+ return _mimeTypes;
+ }
+ }
+ }
+
+ return mimeTypes;
+
+ }
+}
Index: OpenConcerto/src/org/openconcerto/utils/mime/File.java
===================================================================
--- OpenConcerto/src/org/openconcerto/utils/mime/File.java (revision 0)
+++ OpenConcerto/src/org/openconcerto/utils/mime/File.java (revision 156)
@@ -0,0 +1,35 @@
+/*
+ * 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.utils.mime;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+public class File {
+ public static void main(String[] args) throws IOException {
+ if (args.length == 0) {
+ System.out.println(File.class.getName() + " file...");
+ System.out.println("Allow to find the MIME type of files");
+ System.out.println("The '" + FreeDesktopMimeDetector.DEFAULT_MODE + "' property can be set to " + Arrays.asList(FreeDesktopMimeDetector.Mode.values()));
+ System.out.println("\tthe default is the first one, see http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html#idm140625828606432");
+ System.exit(1);
+ }
+ for (final String f : args) {
+ final Path p = Paths.get(f);
+ System.out.println(f + '\t' + new FreeDesktopMimeDetector().probeContentType(p));
+ }
+ }
+}
Index: OpenConcerto/src/org/openconcerto/utils/mime/FileMagicMimeDetector.java
===================================================================
--- OpenConcerto/src/org/openconcerto/utils/mime/FileMagicMimeDetector.java (revision 0)
+++ OpenConcerto/src/org/openconcerto/utils/mime/FileMagicMimeDetector.java (revision 156)
@@ -0,0 +1,39 @@
+/*
+ * 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.utils.mime;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.spi.FileTypeDetector;
+
+/**
+ * <p>
+ * The <a
+ * href="http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html"
+ * >freedesktop Shared MIME-Info</a> only contains basic magic support. In particular it misses
+ * indirect offset and calculations that <a href="http://www.darwinsys.com/file">file</a> supports.
+ * For example these features are needed for <a
+ * href="https://github.com/file/file/blob/master/magic/Magdir/msooxml">MS OOXML</a>.
+ * </p>
+ *
+ * @see <a href="https://github.com/file/file/blob/master/doc/magic.man">Magic Format</a>
+ */
+public class FileMagicMimeDetector extends FileTypeDetector {
+
+ @Override
+ public String probeContentType(Path path) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+}
Index: OpenConcerto/src/org/openconcerto/utils/StreamUtils.java
===================================================================
--- OpenConcerto/src/org/openconcerto/utils/StreamUtils.java (revision 155)
+++ OpenConcerto/src/org/openconcerto/utils/StreamUtils.java (revision 156)
@@ -13,11 +13,9 @@
package org.openconcerto.utils;
-import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -24,6 +22,9 @@
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.logging.Level;
public class StreamUtils {
@@ -48,6 +49,7 @@
* @throws IOException if an error occurs while reading or writing.
*/
public static void copy(InputStream in, OutputStream out) throws IOException {
+ // TODO use in.transferTo(out) in Java 9
copy(in, out, 512 * 1024);
}
@@ -56,6 +58,8 @@
}
public static long copy(InputStream in, OutputStream out, final int bufferSize, final long length) throws IOException {
+ if (bufferSize < 1)
+ throw new IllegalArgumentException("Buffer size too small : " + bufferSize);
final byte[] buffer = new byte[bufferSize];
long totalCount = 0;
final boolean copyAll = length < 0;
@@ -62,10 +66,14 @@
while (copyAll || totalCount < length) {
final long toRead = copyAll ? buffer.length : Math.min(length - totalCount, buffer.length);
// since buffer.length is an int
- assert 0 <= toRead && toRead <= Integer.MAX_VALUE;
+ assert 0 < toRead && toRead <= Integer.MAX_VALUE;
final int count = in.read(buffer, 0, (int) toRead);
- if (count == -1)
+ if (count <= 0) {
+ // like Files.copy(InputStream, OutputStream), stop if reading 0 bytes
+ if (count == 0)
+ Log.get().log(Level.WARNING, "", new IllegalStateException("read() returned 0 for " + in));
break;
+ }
totalCount += count;
out.write(buffer, 0, count);
}
@@ -75,13 +83,7 @@
}
public static void copy(InputStream ins, File out) throws IOException {
- // buffered since read() in copy(InputStream, OutputStream) may return 1 byte at a time
- final OutputStream ous = new BufferedOutputStream(new FileOutputStream(out));
- try {
- copy(ins, ous);
- } finally {
- ous.close();
- }
+ Files.copy(ins, out.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
/**
/trunk/OpenConcerto/src/org/openconcerto/task/element/TaskSQLElementBase.java
15,8 → 15,6
 
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.task.TM;
import org.openconcerto.utils.i18n.I18nUtils;
 
/**
* @author Sylvain CUAZ
23,10 → 21,6
*/
public abstract class TaskSQLElementBase extends ConfSQLElement {
 
{
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
}
 
public TaskSQLElementBase(final String tableName) {
super(tableName);
}
/trunk/OpenConcerto/src/org/openconcerto/task/element/CompanyAccessSQLElement.java
Nouveau fichier
0,0 → 1,49
/*
* 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.element;
 
import org.openconcerto.sql.element.ConfSQLElement;
 
import java.util.ArrayList;
import java.util.List;
 
public class CompanyAccessSQLElement extends ConfSQLElement {
 
public CompanyAccessSQLElement() {
super("ACCES_SOCIETE");
 
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_USER_COMMON");
l.add("ID_SOCIETE_COMMON");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_USER_COMMON");
l.add("ID_SOCIETE_COMMON");
return l;
}
 
@Override
protected String createCode() {
return "common.company-access";
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_en.xml
1,4 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="User" />
<FIELD name="ID_SOCIETE_COMMON" label="Allowed company access" />
</element>
<element refid="TACHE_COMMON" name="task" />
<element refid="TACHE_RIGHTS" name="right for tasks" namePlural="rights for tasks" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_es.xml
Nouveau fichier
0,0 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="Usario" />
<FIELD name="ID_SOCIETE_COMMON" label="Acceso a la sociedad" />
</element>
<element refid="TACHE_COMMON" name="tarea" />
<element refid="TACHE_RIGHTS" name="derechos para tareas" namePlural="derechos para tareas" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_fr.xml
1,4 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="Utilisateur" />
<FIELD name="ID_SOCIETE_COMMON" label="Accés à la société" />
</element>
<element refid="TACHE_COMMON" nameClass="feminine" name="tâche" />
<element refid="TACHE_RIGHTS" nameClass="masculine" name="droit pour les tâches" namePlural="droits pour les tâches" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_pl.xml
Nouveau fichier
0,0 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="User" />
<FIELD name="ID_SOCIETE_COMMON" label="Ustawienia dostępu" />
</element>
<element refid="TACHE_COMMON" name="task" />
<element refid="TACHE_RIGHTS" name="right for tasks" namePlural="rights for tasks" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/messages_es.properties
Nouveau fichier
0,0 → 1,20
summary=Summary :
todoBefore=Para hacer antes de {date, date, medium} en {date, time, short} por {user}
todoBefore.col=Hacer antes
ok=OK
cancel=Cancelar
taskToDo=Descripción de la tarea
assignedTo=Asignado a
created=Created
completed=Completado
deleteForbidden=Solo puedes eliminar tareas que creaste
assignedBy=Asignado por {user}\nEn {date, date, medium} por {date, time, short}
delete=Borrar
deleteSelectedTasks=Borrar {count, plural, =0 {selected tasks} one {the selected task} other {the # selected tasks}}
addTask=Nueva tarea
hideHistory= Ocultar historial
showDetails=Mostrar detalles
details=Detalles
markDone=Marca hecha
moveOneDay=Mover por un día
showTaskAssignedTo=Mostrar tarea asignada a ...
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListModel.java
152,7 → 152,7
for (TodoListElement elt : rowsDeleted) {
int index = this.elements.indexOf(elt);
if (index >= 0) {
removeRow(index);
elements.remove(index);
}
}
 
298,11 → 298,11
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;
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()));
/trunk/OpenConcerto/src/org/openconcerto/task/config/ComptaBasePropsConfiguration.java
23,10 → 23,12
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLFilter;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.users.CompanyAccessSQLElement;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.users.UserCommonSQLElement;
import org.openconcerto.sql.users.rights.RightSQLElement;
import org.openconcerto.sql.users.rights.UserRightSQLElement;
import org.openconcerto.task.TM;
import org.openconcerto.task.element.CompanyAccessSQLElement;
import org.openconcerto.task.element.TaskRightSQLElement;
import org.openconcerto.task.element.TaskSQLElement;
import org.openconcerto.utils.BaseDirs;
33,6 → 35,8
import org.openconcerto.utils.DesktopEnvironment;
import org.openconcerto.utils.LogUtils;
import org.openconcerto.utils.ProductInfo;
import org.openconcerto.utils.i18n.Grammar_fr;
import org.openconcerto.utils.i18n.NounClass;
 
import java.io.File;
import java.io.FileNotFoundException;
39,8 → 43,10
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
 
public abstract class ComptaBasePropsConfiguration extends PropsConfiguration {
125,13 → 131,21
}
 
@Override
protected List<String> getMappings() {
final List<String> res = new ArrayList<>(super.getMappings());
final String pkg = "/" + TM.class.getPackage().getName().replace('.', '/');
res.add(pkg + "/translation/SQLElementNames");
return res;
}
 
@Override
protected SQLElementDirectory createDirectory() {
final SQLElementDirectory dir = super.createDirectory();
 
// TACHE_COMMON points to SOCIETE but we never display it we don't need the full element
dir.addSQLElement(new ConfSQLElement("SOCIETE_COMMON", "une société", "sociétés"));
dir.addSQLElement(new ConfSQLElement("EXERCICE_COMMON", "un exercice", "exercices"));
dir.addSQLElement(new ConfSQLElement("ADRESSE_COMMON", "une adresse", "adresses"));
dir.addSQLElement(new ConfSQLElement("SOCIETE_COMMON", Grammar_fr.getInstance().createPhrase(NounClass.FEMININE, "société")));
dir.addSQLElement(new ConfSQLElement("EXERCICE_COMMON", Grammar_fr.getInstance().createPhrase(NounClass.MASCULINE, "exercice")));
dir.addSQLElement(new ConfSQLElement("ADRESSE_COMMON", Grammar_fr.getInstance().createPhrase(NounClass.FEMININE, "adresse")));
 
dir.addSQLElement(new TaskRightSQLElement());
dir.addSQLElement(new TaskSQLElement());
138,8 → 152,8
 
dir.addSQLElement(new UserCommonSQLElement(getRoot(), false));
dir.addSQLElement(new CompanyAccessSQLElement());
dir.addSQLElement(UserRightSQLElement.class);
dir.addSQLElement(RightSQLElement.class);
dir.addSQLElement(new UserRightSQLElement(getRoot()));
dir.addSQLElement(new RightSQLElement(getRoot()));
 
return dir;
}
164,7 → 178,14
 
protected final void setRowSociete(int id) {
this.idSociete = id;
this.rowSociete = getSystemRoot().findTable("SOCIETE_COMMON").getValidRow(this.getSocieteID());
final SQLTable tableSociete = getSystemRoot().findTable("SOCIETE_COMMON");
final SQLRow row = tableSociete.getRow(id);
if (row == null) {
throw new IllegalArgumentException("no row for id " + id + " in " + tableSociete);
} else if (!row.isValid()) {
throw new IllegalArgumentException("invalid row : " + row);
}
this.rowSociete = row;
}
 
public final SQLBase getSQLBaseSociete() {
/trunk/OpenConcerto/src/org/openconcerto/task/ui/UserRightPanelDetail.java
179,12 → 179,13
private void swapOnDoubleClick(final JList list, MouseEvent e, String field) {
if (e.getClickCount() == 2) {
int index = list.locationToIndex(e.getPoint());
ListModel dlm = list.getModel();
Object item = dlm.getElementAt(index);
list.ensureIndexIsVisible(index);
User toUser = (User) item;
swapState(selectedUser, toUser, field);
 
if (index >= 0) {
ListModel dlm = list.getModel();
Object item = dlm.getElementAt(index);
list.ensureIndexIsVisible(index);
User toUser = (User) item;
swapState(selectedUser, toUser, field);
}
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetXml.java
15,7 → 15,10
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.ui.PreviewFrame;
import org.openconcerto.erp.core.sales.invoice.report.VenteFactureXmlSheet;
import org.openconcerto.erp.core.sales.quote.report.PaypalStamper;
import org.openconcerto.erp.generationDoc.element.TypeModeleSQLElement;
import org.openconcerto.erp.preferences.PayPalPreferencePanel;
import org.openconcerto.erp.storage.CloudStorageEngine;
import org.openconcerto.erp.storage.StorageEngine;
import org.openconcerto.erp.storage.StorageEngines;
26,19 → 29,31
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.GraphicsEnvironment;
import java.awt.print.PrinterJob;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
213,8 → 228,7
}
 
} catch (Exception e) {
e.printStackTrace();
ExceptionHandler.handle("Impossible de charger le document OpenOffice", e);
ExceptionHandler.handle("Impossible de charger le document OpenOffice " + pdfFile.getAbsolutePath() + "(viewer : " + useODSViewer + ")", e);
}
}
 
239,12 → 253,87
return this.meta;
}
 
public static void createPDF(final File generatedFile, final File pdfFile, final OpenDocument doc, String storagePath) {
public void createPDF(final File generatedFile, final File pdfFile, final OpenDocument doc, String storagePath) {
if (pdfFile == null) {
throw new IllegalArgumentException("null PDF file");
}
try {
SheetUtils.convert2PDF(doc, pdfFile);
if (VenteFactureXmlSheet.TEMPLATE_ID.equals(getDefaultTemplateId())) {
final SQLPreferences prefs = SQLPreferences.getMemCached(getElement().getTable().getDBRoot());
if (prefs.getBoolean(PayPalPreferencePanel.PAYPAL_INVOICE, false)) {
try {
final File inFile = File.createTempFile("oc_", pdfFile.getName());
SheetUtils.convert2PDF(doc, inFile);
PaypalStamper s = new PaypalStamper();
int x = prefs.getInt(PayPalPreferencePanel.PAYPAL_INVOICE_X, 0);
int y = prefs.getInt(PayPalPreferencePanel.PAYPAL_INVOICE_Y, 0);
 
// Reference
String ref = getSQLRow().getString("NUMERO");
// Montant : ex : 10.55
long cents = getSQLRow().getLong("NET_A_PAYER");
String amount = cents / 100 + "." + cents % 100;
// Devise
// TODO : autres devises
String currency = "EUR";
// POST
final URL url = new URL("https://cloud.openconcerto.org/payment");
final URLConnection con = url.openConnection();
final HttpURLConnection http = (HttpURLConnection) con;
http.setRequestMethod("POST");
http.setDoOutput(true);
http.setDefaultUseCaches(false);
 
String hyperlink = null;
// x-www-form-urlencoded
final Map<String, String> arguments = new HashMap<>();
arguments.put("pI", prefs.get(PayPalPreferencePanel.PAYPAL_CLIENTID, ""));
arguments.put("pS", prefs.get(PayPalPreferencePanel.PAYPAL_SECRET, ""));
arguments.put("ref", ref);
arguments.put("amount", amount);
arguments.put("currency", currency);
arguments.put("type", "paypal");
final StringJoiner sj = new StringJoiner("&");
for (Map.Entry<String, String> entry : arguments.entrySet()) {
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
}
final String postData = sj.toString();
System.err.println("SheetXml.createPDF() " + postData);
byte[] out = postData.getBytes(StandardCharsets.UTF_8);
int length = out.length;
http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.connect();
try (OutputStream os = http.getOutputStream()) {
os.write(out);
}
if (http.getResponseCode() != 401) {
 
InputStream is = http.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
 
int numCharsRead;
char[] charArray = new char[1024];
StringBuilder sb = new StringBuilder();
while ((numCharsRead = isr.read(charArray)) > 0) {
sb.append(charArray, 0, numCharsRead);
}
//
hyperlink = sb.toString();
}
s.addLink(inFile, pdfFile, x, y, hyperlink);
} catch (Exception e) {
e.printStackTrace();
SheetUtils.convert2PDF(doc, pdfFile);
}
 
} else {
SheetUtils.convert2PDF(doc, pdfFile);
}
} else {
SheetUtils.convert2PDF(doc, pdfFile);
}
 
} catch (Throwable e) {
ExceptionHandler.handle("Impossible de créer le PDF " + pdfFile.getAbsolutePath(), e);
}
421,8 → 510,23
File f;
try {
f = getOrCreateDocumentFile();
// ComptaPropsConfiguration.getOOConnexion().loadDocument(f, false);
OOUtils.open(f);
if (f != null && f.exists()) {
OOUtils.open(f);
} else {
if (!GraphicsEnvironment.isHeadless()) {
if (f != null) {
JOptionPane.showMessageDialog(null, "Le fichier " + f.getAbsolutePath() + " est manquant");
} else {
JOptionPane.showMessageDialog(null, "Fichier manquant");
}
} else {
if (f != null) {
throw new FileNotFoundException(f.getAbsolutePath() + " missing");
} else {
throw new NullPointerException("null document");
}
}
}
} catch (Exception e) {
ExceptionHandler.handle("Impossible d'ouvrir le document.", e);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLField.java
84,6 → 84,9
// {
String field = this.elt.getAttributeValue("name");
 
if (field != null && field.trim().length() > 0 && !this.row.getTable().contains(field)) {
throw new InvalidTemplateException("Le champ " + field + " n'existe pas dans la table " + this.row.getTable().getName());
}
final SQLField sqlField = (field == null || field.trim().length() == 0) ? null : this.row.getTable().getField(field);
boolean isForeignField = (sqlField == null) ? false : this.row.getTable().getForeignKeys().contains(sqlField);
 
137,10 → 140,16
String typeComp = this.elt.getAttributeValue("type");
if (this.op != null && this.op.trim().length() > 0 && !(typeComp != null && typeComp.trim().length() > 0 && typeComp.toLowerCase().startsWith("deviselettre"))) {
String field2 = this.elt.getAttributeValue("name2");
if (!this.row.getTable().contains(field)) {
throw new InvalidTemplateException("Le champ " + field + " n'existe pas dans la table " + this.row.getTable().getName());
}
Number o = (Number) this.row.getObject(field);
 
Number o2;
if (field2 != null && field2.trim().length() > 0) {
if (!this.row.getTable().contains(field2)) {
throw new InvalidTemplateException("Le champ " + field2 + " n'existe pas dans la table " + this.row.getTable().getName());
}
o2 = (Number) this.row.getObject(field2);
} else {
o2 = Double.parseDouble(this.elt.getAttributeValue("number"));
223,6 → 232,9
}
stringValue = o.toString();
} else {
if (!this.row.getTable().contains(field)) {
throw new InvalidTemplateException("Le champ " + field + " n'existe pas dans la table " + this.row.getTable().getName());
}
Object o2 = this.row.getObject(field);
 
if (o2 != null && scale != null && scale.trim().length() > 0) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetGenerator.java
14,6 → 14,7
package org.openconcerto.erp.generationDoc;
 
import static org.openconcerto.task.config.ComptaBasePropsConfiguration.getStreamStatic;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.ui.PreviewFrame;
import org.openconcerto.erp.preferences.TemplateNXProps;
216,13 → 217,12
fTmp.renameTo(fDest);
 
fDest = new File(this.destDirOO, this.destFileName + ".ods");
final InputStream stream = getStreamStatic(fODSP);
if (stream != null) {
// Copie de l'odsp
File odspOut = new File(this.destDirOO, this.destFileName + ".odsp");
StreamUtils.copy(stream, odspOut);
stream.close();
 
try (final InputStream stream = getStreamStatic(fODSP)) {
if (stream != null) {
// Copie de l'odsp
File odspOut = new File(this.destDirOO, this.destFileName + ".odsp");
StreamUtils.copy(stream, odspOut);
}
}
try {
ssheet.saveAs(fDest);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractJOOReportsSheet.java
231,7 → 231,7
}
}
 
private File getDocumentFile() {
public File getDocumentFile() {
File outputDir = DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(getDefaultTemplateID());
return new File(outputDir, getFileName() + ".odt");
}
302,12 → 302,15
return init;
}
 
public File getPDFDocumentFile() {
final File outputPDFDirectory = DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.templateId);
return new File(outputPDFDirectory, getFileName() + ".pdf");
}
 
public void exportToPdf() {
// Export vers PDF
final String fileName = getFileName();
final File fileOutOO = getDocumentFile();
final File outputPDFDirectory = DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.templateId);
final File fileOutPDF = new File(outputPDFDirectory, fileName + ".pdf");
final File fileOutPDF = getPDFDocumentFile();
 
if (!fileOutOO.exists()) {
generate(false, false, "");
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractLocalTemplateProvider.java
47,7 → 47,7
throw new NullPointerException("null templateId");
}
File templateFile1 = getTemplateFromLocalFile(templateId, language, type);
if (templateFile1 != null && templateFile1.exists()) {
if (templateFile1 != null && templateFile1.exists() && !templateFile1.isDirectory()) {
return templateFile1;
}
File templateFile2 = getTemplateFromLocalFile(templateId + ".ods", language, type);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationListeColumnXML.java
24,12 → 24,16
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.io.BOMSkipper;
 
import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
46,7 → 50,7
public class OOgenerationListeColumnXML {
 
// Cache pour la recherche des styles
private static Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>();
private static Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<>();
 
public static File genere(String modele, File pathDest, String fileDest, Map<Integer, List<Map<String, Object>>> liste, Map<Integer, Map<String, Object>> values) {
return genere(modele, pathDest, fileDest, liste, values, new HashMap<Integer, Map<Integer, String>>(), null, null);
61,7 → 65,11
if (xmlConfiguration == null) {
throw new IllegalStateException("Template configuration " + templateId + " not found (" + TemplateManager.getInstance().getClass().getName() + ")");
}
Document doc = builder.build(xmlConfiguration);
final BufferedReader xmlConfigurationReader = new BufferedReader(new InputStreamReader(xmlConfiguration, Charset.forName("UTF8")));
BOMSkipper.skip(xmlConfigurationReader);
final Document doc = builder.build(xmlConfigurationReader);
xmlConfigurationReader.close();
xmlConfiguration.close();
 
// On initialise un nouvel élément racine avec l'élément racine du
// document.
84,7 → 92,7
for (Integer i : liste.keySet()) {
final Sheet sheet = spreadSheet.getSheet(i);
List children = racine.getChildren("element" + i);
if (children.size() == 0) {
if (children.isEmpty()) {
children = racine.getChildren("element");
}
parseElementsXML(children, sheet, values.get(i));
138,7 → 146,7
}
Object oLastColTmp = tableau.getAttributeValue("lastColumn");
int lastColumn = -1;
int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endPageLine = Integer.parseInt(tableau.getAttributeValue("endPageLine"));
if (oLastColTmp != null) {
lastColumn = sheet.resolveHint(oLastColTmp.toString() + 1).x + 1;
}
202,11 → 210,7
*/
private static int fillTable(Element tableau, List<Map<String, Object>> liste, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test, Map<Integer, String> style) {
 
// int nbPage = 1;
// int currentLineTmp = Integer.valueOf(tableau.getAttributeValue("firstLine"));
// int currentLine = Integer.valueOf(tableau.getAttributeValue("firstLine"));
// int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endLine = Integer.valueOf(tableau.getAttributeValue("endLine"));
int endLine = Integer.parseInt(tableau.getAttributeValue("endLine"));
 
List listElts = tableau.getChildren("element");
 
222,7 → 226,6
int currentCol = firstCol;
for (int i = 0; i < liste.size(); i++) {
Map<String, Object> mValues = liste.get(i);
// System.err.println(mValues);
if (currentCol != firstCol) {
for (int k = 0; k < endLine; k++) {
MutableCell<SpreadSheet> c1 = sheet.getCellAt(firstCol, k);
464,9 → 467,8
}
 
// Copie de l'odsp
try {
File odspOut = new File(pathDest, fileName + ".odsp");
InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);
File odspOut = new File(pathDest, fileName + ".odsp");
try (final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);) {
if (odspIn != null) {
StreamUtils.copy(odspIn, odspOut);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/DepotChequeXmlSheet.java
Nouveau fichier
0,0 → 1,44
/*
* 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.erp.generationDoc.gestcomm;
 
import org.openconcerto.erp.generationDoc.AbstractSheetXMLWithDate;
import org.openconcerto.erp.preferences.PrinterNXProps;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRow;
 
public class DepotChequeXmlSheet extends AbstractSheetXMLWithDate {
 
public static final String TEMPLATE_ID = "DepotCheque";
public static final String TEMPLATE_PROPERTY_NAME = "LocationDepotCheque";
 
@Override
public String getName() {
 
return "DepotCheque" + this.row.getID();
}
 
public DepotChequeXmlSheet(SQLRow row) {
super(row);
this.printer = PrinterNXProps.getInstance().getStringProperty("FacturePrinter");
this.elt = Configuration.getInstance().getDirectory().getElement("DEPOT_CHEQUE");
getDefaultTemplateId();
}
 
@Override
public String getDefaultTemplateId() {
return TEMPLATE_ID;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/ReportingTaxeComplementaireSheetXML.java
83,15 → 83,25
private static SQLTable tableVF = Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE").getTable();
 
class TaxeComplRecap {
private final String code, nom;
private final String code, nom, numeroCptProduit, numeroCpt;
private BigDecimal percentTaxe, totalBase, qte;
 
public TaxeComplRecap(String code, String nom, BigDecimal percentTaxe) {
this.code = code;
this.nom = nom;
public TaxeComplRecap(SQLRowAccessor foreignTaxeCompl) {
this.code = foreignTaxeCompl.getString("CODE");
this.nom = foreignTaxeCompl.getString("NOM");
this.qte = BigDecimal.ZERO;
this.percentTaxe = percentTaxe;
this.percentTaxe = foreignTaxeCompl.getBigDecimal("POURCENT");
this.totalBase = BigDecimal.ZERO;
if (foreignTaxeCompl.getObject("ID_COMPTE_PCE") != null && !foreignTaxeCompl.isForeignEmpty("ID_COMPTE_PCE")) {
this.numeroCpt = foreignTaxeCompl.getForeign("ID_COMPTE_PCE").getString("NUMERO");
} else {
this.numeroCpt = "";
}
if (foreignTaxeCompl.getObject("ID_COMPTE_PCE_PRODUITS") != null && !foreignTaxeCompl.isForeignEmpty("ID_COMPTE_PCE_PRODUITS")) {
this.numeroCptProduit = foreignTaxeCompl.getForeign("ID_COMPTE_PCE_PRODUITS").getString("NUMERO");
} else {
this.numeroCptProduit = "";
}
}
 
public void cumul(BigDecimal qte, BigDecimal total) {
107,6 → 117,14
return nom;
}
 
public String getNumeroCpt() {
return numeroCpt;
}
 
public String getNumeroCptProduit() {
return numeroCptProduit;
}
 
public BigDecimal getQte() {
return qte;
}
142,8 → 160,10
rowvalsVFElt.put("T_PV_HT", null);
rowvalsVFElt.put("QTE", null);
rowvalsVFElt.put("QTE_UNITAIRE", null);
rowvalsVFElt.putRowValues("ID_ARTICLE").putRowValues("ID_TAXE_COMPLEMENTAIRE").putNulls("CODE", "NOM", "POURCENT");
 
final SQLRowValues rowValsTaxeCompl = rowvalsVFElt.putRowValues("ID_ARTICLE").putRowValues("ID_TAXE_COMPLEMENTAIRE");
rowValsTaxeCompl.putNulls("CODE", "NOM", "POURCENT");
rowValsTaxeCompl.putRowValues("ID_COMPTE_PCE_PRODUITS").putNulls("NUMERO", "NOM");
rowValsTaxeCompl.putRowValues("ID_COMPTE_PCE").putNulls("NUMERO", "NOM");
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowvalsVFElt);
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
 
166,7 → 186,7
if (recap.containsKey(foreignTaxeCompl.getID())) {
r = recap.get(foreignTaxeCompl.getID());
} else {
r = new TaxeComplRecap(foreignTaxeCompl.getString("CODE"), foreignTaxeCompl.getString("NOM"), foreignTaxeCompl.getBigDecimal("POURCENT"));
r = new TaxeComplRecap(foreignTaxeCompl);
recap.put(foreignTaxeCompl.getID(), r);
}
r.cumul(sqlRowValues.getBigDecimal("QTE_UNITAIRE").multiply(new BigDecimal(sqlRowValues.getInt("QTE"))), sqlRowValues.getBigDecimal("T_PV_HT"));
186,6 → 206,9
for (TaxeComplRecap item : recap.values()) {
Map<String, Object> vals = new HashMap<String, Object>();
 
vals.put("COMPTE_NUMERO", item.getNumeroCpt());
vals.put("COMPTE_PRODUIT_NUMERO", item.getNumeroCptProduit());
 
vals.put("CODE", item.getCode());
vals.put("NOM", item.getNom());
vals.put("QTE", item.getQte());
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/InvalidTemplateException.java
Nouveau fichier
0,0 → 1,26
/*
* 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.erp.generationDoc;
 
public class InvalidTemplateException extends RuntimeException {
 
public InvalidTemplateException(String cause) {
super(cause);
}
 
public InvalidTemplateException(String cause, Exception e) {
super(cause, e);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/A4.java
28,6 → 28,6
final double width = (210 * DPI) / INCH_TO_MM;
final double height = (297 * DPI) / INCH_TO_MM;
setSize(width, height);
setImageableArea(hMargin, vMargin, width + 2 * hMargin, height - 2 * vMargin);
setImageableArea(hMargin, vMargin, width - 2 * hMargin, height - 2 * vMargin);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/DefaultLocalTemplateProvider.java
109,8 → 109,14
final File from = getFile(templateId + ext, language, type);
final File to = getLocalFile(templateId + ext, language, type);
try {
if (from.exists() && !to.exists()) {
FileUtils.copyFile(from, to);
if (from != null && to != null && from.exists() && !to.exists()) {
final File parentDir = to.getParentFile();
if (parentDir != null) {
if (!parentDir.exists()) {
parentDir.mkdirs();
}
FileUtils.copyFile(from, to);
}
}
} catch (IOException e) {
throw new IllegalStateException("Copie impossible", e);
140,7 → 146,7
for (int i = 0; i < EXTS.length; i++) {
final String ext = EXTS[i];
final File local = getLocalFile(templateId + ext, language, type);
if (local.exists()) {
if (local != null && local.exists()) {
local.delete();
ensureDelete(local);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/element/ModeleSQLElement.java
33,15 → 33,17
super("MODELE", "un modele ", "modeles");
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("NOM");
l.add("ID_TYPE_MODELE");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("NOM");
l.add("ID_TYPE_MODELE");
return l;
52,7 → 54,7
 
@Override
protected Set<String> createRequiredNames() {
final Set<String> s = new HashSet<String>();
final Set<String> s = new HashSet<>();
// s.add("NOM");
// s.add("ID_TYPE_MODELE");
return s;
65,8 → 67,13
};
}
 
@Override
public String getDescription(SQLRow fromRow) {
return fromRow.getString("NOM");
}
 
@Override
protected String createCode() {
return "document.template";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/element/TypeModeleSQLElement.java
16,8 → 16,7
*/
package org.openconcerto.erp.generationDoc.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.DBRoot;
33,16 → 32,12
import java.util.Map;
import java.util.Set;
 
public class TypeModeleSQLElement extends ConfSQLElement {
public class TypeModeleSQLElement extends ComptaSQLConfElement {
 
public TypeModeleSQLElement(DBRoot root) {
super(root.getTable("TYPE_MODELE"), "un type_modele ", "type_modeles");
super(root.getTable("TYPE_MODELE"), "un type de modèle", "types de modèles");
}
 
public TypeModeleSQLElement() {
this(Configuration.getInstance().getRoot());
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("NOM");
91,17 → 86,20
 
if (this.template == null) {
this.template = new HashMap<String, String>();
SQLSelect sel = new SQLSelect(getTable().getBase());
SQLSelect sel = new SQLSelect();
sel.addSelectStar(getTable());
List<SQLRow> rows = (List<SQLRow>) Configuration.getInstance().getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel));
for (SQLRow sqlRow : rows) {
template.put(sqlRow.getString("TABLE"), sqlRow.getString("DEFAULT_MODELE"));
for (SQLRow sqlRow : SQLRowListRSH.execute(sel)) {
this.template.put(sqlRow.getString("TABLE"), sqlRow.getString("DEFAULT_MODELE"));
}
 
}
 
return template;
return this.template;
 
}
 
@Override
protected String createCode() {
return "document.template-type";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java
37,15 → 37,19
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.io.BOMSkipper;
 
import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
77,12 → 81,12
private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
 
// Cache pour la recherche des styles
private Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>();
private Map<SQLRowAccessor, Map<String, Object>> taxe = new HashMap<SQLRowAccessor, Map<String, Object>>();
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>();
private Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<>();
private Map<SQLRowAccessor, Map<String, Object>> taxe = new HashMap<>();
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<>();
 
// Cache pour les SQLRow du tableau
private Map<String, List<? extends SQLRowAccessor>> rowsEltCache = new HashMap<String, List<? extends SQLRowAccessor>>();
private Map<String, List<? extends SQLRowAccessor>> rowsEltCache = new HashMap<>();
private final OOXMLCache rowRefCache = new OOXMLCache();
private final SQLRow row;
 
155,7 → 159,11
+ ((typeTemplate == null) ? "" : typeTemplate));
return null;
}
Document doc = builder.build(xmlConfiguration);
 
final BufferedReader xmlConfigurationReader = new BufferedReader(new InputStreamReader(xmlConfiguration, Charset.forName("UTF8")));
BOMSkipper.skip(xmlConfigurationReader);
final Document doc = builder.build(xmlConfigurationReader);
xmlConfigurationReader.close();
xmlConfiguration.close();
 
// On initialise un nouvel élément racine avec l'élément racine du document.
239,7 → 247,7
// et d'optimiser la recherche
Object oLastColTmp = tableau.getAttributeValue("lastColumn");
int lastColumn = -1;
int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endPageLine = Integer.parseInt(tableau.getAttributeValue("endPageLine"));
if (oLastColTmp != null) {
lastColumn = sheet.resolveHint(oLastColTmp.toString() + 1).x + 1;
}
251,8 → 259,8
return;
}
int nbPage = fillTable(tableau, row, sheet, mapStyle, true, rowLanguage);
int firstLine = Integer.valueOf(tableau.getAttributeValue("firstLine"));
int endLine = Integer.valueOf(tableau.getAttributeValue("endLine"));
int firstLine = Integer.parseInt(tableau.getAttributeValue("firstLine"));
int endLine = Integer.parseInt(tableau.getAttributeValue("endLine"));
Object printRangeObj = sheet.getPrintRanges();
 
System.err.println("Nombre de page == " + nbPage);
286,7 → 294,7
int lineToAdd = endPageLine - endLine;
String repeatedCount = tableau.getAttributeValue("repeatedCount");
if (repeatedCount != null && repeatedCount.trim().length() > 0) {
int count = Integer.valueOf(repeatedCount);
int count = Integer.parseInt(repeatedCount);
sheet.duplicateRows(firstLine, lineToAdd / count, count);
final int rest = lineToAdd % count;
// Si le nombre de ligne ne termine pas à la fin de la page
324,7 → 332,7
cell2.setValue("Page " + (i + start) + "/" + nbPageRef);
}
if (pageAdd != null && pageAdd.trim().length() > 0) {
int pAdd = Integer.valueOf(pageAdd);
int pAdd = Integer.parseInt(pageAdd);
for (int i = 0; i < pAdd; i++) {
Sheet s = sheet.getSpreadSheet().getSheet(idSheet + i + 1);
MutableCell<SpreadSheet> cell2 = s.getCellAt(pageRef);
362,7 → 370,7
SQLRowAccessor foreign = row.getForeign(field.getName());
 
if (c == null) {
Map<Integer, SQLRowAccessor> map = new HashMap<Integer, SQLRowAccessor>();
Map<Integer, SQLRowAccessor> map = new HashMap<>();
map.put(i, foreign);
cacheForeign.put(field.getName(), map);
} else {
371,7 → 379,6
 
return foreign;
}
// return row.getForeignRow(field.getName());
 
}
 
384,7 → 391,7
SQLBackgroundTableCacheItem prefsCpt = SQLBackgroundTableCache.getInstance().getCacheForTable(tableElt.getTable("PREFS_COMPTE"));
if (tableElt.contains("ID_TAXE") && tableElt.contains("T_PA_HT")) {
boolean achat = tableElt.contains("T_PA_TTC");
TotalCalculator calc = new TotalCalculator("T_PA_HT", achat ? "T_PA_HT" : "T_PV_HT", null, achat, null);
TotalCalculator calc = new TotalCalculator("T_PA_HT", achat ? "T_PA_HT" : "T_PV_HT", null, achat, null, null);
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean bServiceActive = Boolean.valueOf(val);
 
487,7 → 494,7
Map<SQLRowAccessor, Tuple2<BigDecimal, BigDecimal>> taxeCalc = calc.getMapHtTVARowTaux();
for (SQLRowAccessor sqlRow : taxeCalc.keySet()) {
Tuple2<BigDecimal, BigDecimal> v = taxeCalc.get(sqlRow);
Map<String, Object> m = new HashMap<String, Object>();
Map<String, Object> m = new HashMap<>();
m.put("MONTANT_HT", v.get0());
m.put("MONTANT_TVA", v.get1());
taxe.put(sqlRow, m);
510,12 → 517,9
 
StyleSQLElement styleElt = Configuration.getInstance().getDirectory().getElement(StyleSQLElement.class);
 
boolean cache = false;
String ref = tableau.getAttributeValue("table") + "_" + row.getTable().getName() + row.getID();
if (rowsEltCache.get(ref) == null) {
rowsEltCache.put(ref, tableElement.getRows());
} else {
cache = true;
}
List<Element> listElts = tableau.getChildren("element");
 
553,10 → 557,10
}
 
// Cache des valeurs
Map<Element, Object> mapValues = new HashMap<Element, Object>();
Map<Element, Object> mapValues = new HashMap<>();
 
// Test si l'ensemble des donnees tient sur la page courante
Map<String, Integer> tmpMapNbCel = new HashMap<String, Integer>();
Map<String, Integer> tmpMapNbCel = new HashMap<>();
int tmpNbCellule = fillTableLine(sheet, mapStyle, true, rowLanguage, tableElement, currentLine, listElts, numeroRef, rowElt, tmpMapNbCel, styleName, mapValues);
for (String s : tmpMapNbCel.keySet()) {
tmpNbCellule = Math.max(tmpNbCellule, tmpMapNbCel.get(s));
569,7 → 573,7
}
 
// Remplissage reel des cellules
Map<String, Integer> mapNbCel = new HashMap<String, Integer>();
Map<String, Integer> mapNbCel = new HashMap<>();
int nbCellule = fillTableLine(sheet, mapStyle, test, rowLanguage, tableElement, currentLine, listElts, numeroRef, rowElt, mapNbCel, styleName, mapValues);
 
for (String s : mapNbCel.keySet()) {
707,7 → 711,7
 
private void fillTaxeDocumentMap(Element tableau, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test) {
 
int line = Integer.valueOf(tableau.getAttributeValue("firstLine"));
int line = Integer.parseInt(tableau.getAttributeValue("firstLine"));
List<Element> listElts = tableau.getChildren("element");
 
for (SQLRowAccessor rowTaxe : taxe.keySet()) {
953,12 → 957,10
}
 
// Copie de l'odsp
try {
File odspOut = new File(pathDest, fileName + ".odsp");
final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, langage, null);
File odspOut = new File(pathDest, fileName + ".odsp");
try (final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, langage, null);) {
if (odspIn != null) {
StreamUtils.copy(odspIn, odspOut);
odspIn.close();
}
} catch (FileNotFoundException e) {
System.err.println("OOgenerationXML.saveSpreadSheet() : Le fichier odsp n'existe pas.");
985,7 → 987,7
System.err.println("End row search : " + rowCount);
for (int i = 0; i < rowCount; i++) {
int x = 0;
Map<Integer, String> mapCellStyle = new HashMap<Integer, String>();
Map<Integer, String> mapCellStyle = new HashMap<>();
String style = "";
 
for (int j = 0; j < columnCount; j++) {
1045,7 → 1047,7
List<Element> listTable = racine.getChildren("table");
 
Element tableau;
if (listTable.size() == 0) {
if (listTable.isEmpty()) {
return false;
} else {
if (listTable.get(0).getAttributeValue("table").equalsIgnoreCase("TVA")) {
1058,7 → 1060,7
 
Object oLastColTmp = tableau.getAttributeValue("lastColumn");
int lastColumn = -1;
int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endPageLine = Integer.parseInt(tableau.getAttributeValue("endPageLine"));
if (oLastColTmp != null) {
lastColumn = sheet.resolveHint(oLastColTmp.toString() + 1).x + 1;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationListeXML.java
24,12 → 24,16
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.io.BOMSkipper;
 
import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
62,7 → 66,11
if (xmlConfiguration == null) {
throw new IllegalStateException("Template configuration " + templateId + " not found (" + TemplateManager.getInstance().getClass().getName() + ")");
}
Document doc = builder.build(xmlConfiguration);
final BufferedReader xmlConfigurationReader = new BufferedReader(new InputStreamReader(xmlConfiguration, Charset.forName("UTF8")));
BOMSkipper.skip(xmlConfigurationReader);
final Document doc = builder.build(xmlConfigurationReader);
xmlConfigurationReader.close();
xmlConfiguration.close();
 
// On initialise un nouvel élément racine avec l'élément racine du
// document.
74,6 → 82,7
throw new IllegalStateException("Template " + templateId + " not found (" + TemplateManager.getInstance().getClass().getName() + ")");
}
final SpreadSheet spreadSheet = new ODPackage(template).getSpreadSheet();
 
Sheet sheet0 = spreadSheet.getSheet(0);
if (sheetName != null && sheetName.size() > 0) {
for (int i = 1; i < sheetName.size(); i++) {
83,7 → 92,12
}
 
for (Integer i : liste.keySet()) {
final Sheet sheet = spreadSheet.getSheet(i);
final Sheet sheet;
try {
sheet = spreadSheet.getSheet(i);
} catch (Exception e) {
throw new InvalidTemplateException("La feuille numéro " + i + " n'est pas dans le modèle", e);
}
List children = racine.getChildren("element" + i);
if (children.size() == 0) {
children = racine.getChildren("element");
96,6 → 110,7
parseListeXML(child, liste.get(i), sheet, mapStyle.get(i));
}
cacheStyle.clear();
 
// Sauvegarde du fichier
return saveSpreadSheet(spreadSheet, pathDest, fileDest, templateId, rowLanguage);
 
555,9 → 570,8
}
 
// Copie de l'odsp
try {
File odspOut = new File(pathDest, fileName + ".odsp");
InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);
File odspOut = new File(pathDest, fileName + ".odsp");
try (final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);) {
if (odspIn != null) {
StreamUtils.copy(odspIn, odspOut);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLCache.java
24,6 → 24,7
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelectJoin;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.CompareUtils;
301,8 → 302,11
if (orderBy != null && orderBy.contains(".")) {
String fieldRefTable = orderBy.substring(0, orderBy.indexOf('.'));
String field = orderBy.substring(orderBy.indexOf('.') + 1, orderBy.length());
sel.addJoin("LEFT", sel.getAlias(tableForeign).getField(fieldRefTable));
sel.addFieldOrder(sel.getAlias(tableForeign.getForeignTable(fieldRefTable)).getField(field));
if (sel.getJoin(tableForeign.getField(fieldRefTable)) == null) {
sel.addJoin("LEFT", sel.getAlias(tableForeign).getField(fieldRefTable));
}
SQLSelectJoin join = sel.getJoin(tableForeign.getField(fieldRefTable));
sel.addFieldOrder(join.getJoinedTable().getField(field));
} else {
sel.addFieldOrder(tableForeign.getOrderField());
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtReglementFactureFournisseur.java
70,7 → 70,7
// long l = ((Number) avoirRow.getObject("MONTANT_TTC")).longValue();
// prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue() - l);
// } else {
prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue());
prixTTC = new PrixTTC(((Long) saisieRow.getObject("NET_A_PAYER")).longValue());
// }
 
this.date = (Date) saisieRow.getObject("DATE");
192,7 → 192,7
// long l = ((Number) avoirRow.getObject("MONTANT_TTC")).longValue();
// prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue() - l);
// } else {
prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue());
prixTTC = new PrixTTC(((Long) saisieRow.getObject("NET_A_PAYER")).longValue());
// }
 
// Ajout dans cheque fournisseur
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtDepotChequeClient.java
Nouveau fichier
0,0 → 1,174
/*
* 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.
*/
/*
* 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.erp.generationEcritures;
 
import org.openconcerto.erp.core.common.element.BanqueSQLElement;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.StringUtils;
 
import java.util.ArrayList;
import java.util.List;
 
public class GenerationMvtDepotChequeClient extends GenerationEcritures {
 
private long montant;
 
private static final SQLTable tablePrefCompte = base.getTable("PREFS_COMPTE");
private static final SQLRow rowPrefsCompte = tablePrefCompte.getRow(2);
private final SQLRow depot;
private SQLRowAccessor banque;
 
public GenerationMvtDepotChequeClient(SQLRow depot) {
this.montant = depot.getLong("MONTANT");
this.date = depot.getDate("DATE").getTime();
this.banque = depot.getForeign("ID_" + BanqueSQLElement.TABLENAME);
this.depot = depot;
// SQLRow chequeRow = base.getTable("CHEQUE_A_ENCAISSER").getRow(this.idCheque);
// String num = "";
// if (chequeRow != null && !chequeRow.isUndefined() &&
// chequeRow.getString("NUMERO").trim().length() > 0) {
// num = " N° " + chequeRow.getString("NUMERO");
// }
//
// if (s != null && s.trim().length() > 0) {
// this.nom = s + (num.trim().length() > 0 ? " - Cheque" + num : "");
// } else {
// this.nom = "Reglement cheque client" + num;
// }
}
 
public void genere() throws Exception {
System.err.println("génération des ecritures de règlement d'un cheque client du mouvement " + this.idMvt);
this.nom = this.depot.getString("NOM");
if (this.depot.getObject("ID_MOUVEMENT") == null || this.depot.isForeignEmpty("ID_MOUVEMENT")) {
this.idMvt = getNewMouvement(depot.getTable().getName(), depot.getID(), 1, this.nom);
} else {
this.idMvt = this.depot.getForeignID("ID_MOUVEMENT");
SQLRowValues rowValspiece = this.depot.getForeign("ID_MOUVEMENT").getForeign("ID_PIECE").createEmptyUpdateRow();
rowValspiece.put("NOM", this.nom);
rowValspiece.update();
}
 
// initialisation des valeurs de la map
this.putValue("ID_MOUVEMENT", new Integer(this.idMvt));
this.putValue("DATE", new java.sql.Date(this.date.getTime()));
this.putValue("NOM", this.nom);
if (this.banque == null || this.banque.isUndefined() || this.banque.isForeignEmpty("ID_JOURNAL")) {
fillJournalBanqueFromRow(depot);
} else {
int idJrnl = this.banque.getForeignID("ID_JOURNAL");
this.putValue("ID_JOURNAL", idJrnl);
}
 
List<Integer> pieceIDs = new ArrayList<Integer>();
SQLRowValues rowValsDepotElt = new SQLRowValues(depot.getTable().getTable("DEPOT_CHEQUE_ELEMENT"));
rowValsDepotElt.putNulls("MONTANT", "TIERS");
rowValsDepotElt.putRowValues("ID_CLIENT").putNulls("NOM", "ID_COMPTE_PCE");
final SQLRowValues rowValuesChq = rowValsDepotElt.putRowValues("ID_CHEQUE_A_ENCAISSER");
rowValuesChq.putNulls("SANS_VALEUR_ENCAISSEMENT").putRowValues("ID_MOUVEMENT").putNulls("ID_PIECE");
rowValuesChq.putNulls("ID_COMPTE_PCE_TIERS").putNulls("NUMERO");
List<SQLRowValues> cheques = SQLRowValuesListFetcher.create(rowValsDepotElt).fetch(new Where(rowValsDepotElt.getTable().getField("ID_DEPOT_CHEQUE"), "=", depot.getID()));
for (SQLRowValues sqlRowAccessor : cheques) {
final SQLRowAccessor clientRow = sqlRowAccessor.getForeign("ID_CLIENT");
// this.nom = this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20);
this.putValue("NOM", this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20));
SQLRowAccessor chequeRow = sqlRowAccessor.getForeign("ID_CHEQUE_A_ENCAISSER");
pieceIDs.add(chequeRow.getForeign("ID_MOUVEMENT").getForeignID("ID_PIECE"));
// compte Clients
SQLRowAccessor rowCptTiers = chequeRow.getForeign("ID_COMPTE_PCE_TIERS");
int idCompteClient = rowCptTiers != null && !rowCptTiers.isUndefined() ? rowCptTiers.getID() : -1;
 
if (chequeRow.getBoolean("SANS_VALEUR_ENCAISSEMENT")) {
if (idCompteClient == -1) {
if (clientRow != null) {
idCompteClient = clientRow.getInt("ID_COMPTE_PCE");
}
if (idCompteClient <= 1) {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_CLIENT");
if (idCompteClient <= 1) {
idCompteClient = ComptePCESQLElement.getIdComptePceDefault("Clients");
}
}
}
} else {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_VALEUR_ENCAISSEMENT");
if (idCompteClient <= 1) {
idCompteClient = ComptePCESQLElement.getIdComptePceDefault("ValeurEncaissement");
}
}
 
this.putValue("ID_COMPTE_PCE", new Integer(idCompteClient));
this.putValue("DEBIT", new Long(0));
this.putValue("CREDIT", new Long(sqlRowAccessor.getLong("MONTANT")));
SQLRow insertedRow = ajoutEcriture();
 
sqlRowAccessor.createEmptyUpdateRow().put("ID_ECRITURE", insertedRow.getID()).getGraph().store(StoreMode.COMMIT, false);
sqlRowAccessor.getForeign("ID_CHEQUE_A_ENCAISSER").createEmptyUpdateRow().put("ENCAISSE", Boolean.TRUE).getGraph().store(StoreMode.COMMIT, false);
}
// compte de reglement cheque, ...
fillCompteBanqueFromRow(depot, "VenteCheque", false);
this.putValue("NOM", this.nom);
this.putValue("DEBIT", new Long(this.montant));
this.putValue("CREDIT", new Long(0));
SQLRow insertedRow = ajoutEcriture();
 
depot.createEmptyUpdateRow().put("ID_MOUVEMENT", idMvt).put("ID_ECRITURE", insertedRow.getID()).getGraph().store(StoreMode.COMMIT, false);
 
pieceIDs.add(mouvementTable.getRow(idMvt).getForeignID("ID_PIECE"));
lettrageAuto(pieceIDs, this.date);
 
System.err.println("Ecritures générées pour le mouvement " + this.idMvt);
 
}
 
// private void setDateReglement(int idCheque, Date d) throws SQLException {
// if (idCheque > 1) {
// SQLRow chequeRow =
// Configuration.getInstance().getBase().getTable("CHEQUE_A_ENCAISSER").getRow(idCheque);
// final int sourceId = MouvementSQLElement.getSourceId(chequeRow.getInt("ID_MOUVEMENT"));
// SQLRow rowMvt = Configuration.getInstance().getBase().getTable("MOUVEMENT").getRow(sourceId);
//
// if (rowMvt.getString("SOURCE").equalsIgnoreCase("SAISIE_VENTE_FACTURE")) {
// SQLElement eltFacture =
// Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE");
// SQLRow saisieRow = eltFacture.getTable().getRow(rowMvt.getInt("IDSOURCE"));
// // On fixe la date du paiement
// SQLRowValues rowValsUpdateVF = saisieRow.createEmptyUpdateRow();
// rowValsUpdateVF.put("DATE_REGLEMENT", new Timestamp(d.getTime()));
// rowValsUpdateVF.update();
// }
// }
// }
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtTicketCaisse.java
79,7 → 79,7
GenerationMvtTicketCaisse.this.putValue("ID_MOUVEMENT", Integer.valueOf(GenerationMvtTicketCaisse.this.idMvt));
}
 
TotalCalculator calc = getValuesFromElement(rowTicket, rowTicket.getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT"), BigDecimal.ZERO, null, null);
TotalCalculator calc = getValuesFromElement(rowTicket, rowTicket.getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT"), BigDecimal.ZERO, null, BigDecimal.ZERO, null, null);
long ttcLongValue = calc.getTotalTTC().movePointRight(2).longValue();
 
// compte Vente Produits
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationEcritures.java
19,6 → 19,7
import org.openconcerto.erp.core.common.ui.TotalCalculator;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.generationDoc.OOXMLCache;
import org.openconcerto.erp.generationEcritures.provider.AnalytiqueProvider;
import org.openconcerto.erp.generationEcritures.provider.AnalytiqueProviderManager;
import org.openconcerto.erp.preferences.DefaultNXProps;
26,11 → 27,13
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLBackgroundTableCacheItem;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
40,6 → 43,7
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
92,6 → 96,9
return this.rowAnalytiqueSource;
}
 
private Date dDebEx = null;
private Date dCloture = null;
 
/**
* Ajout d'une écriture et maj des totaux du compte associé
*
106,7 → 113,8
// Report des valeurs pour accelerer les IListes
Number n = (Number) this.mEcritures.get("ID_JOURNAL");
if (n != null) {
SQLRow rowJrnl = journalTable.getRow(n.intValue());
final SQLBackgroundTableCacheItem cacheForTableJrnl = SQLBackgroundTableCache.getInstance().getCacheForTable(journalTable);
SQLRow rowJrnl = cacheForTableJrnl.getRowFromId(n.intValue());
if (rowJrnl == null) {
throw new IllegalArgumentException("Le journal qui a pour ID " + n + " a été archivé.");
}
116,7 → 124,11
 
Number n2 = (Number) this.mEcritures.get("ID_COMPTE_PCE");
if (n2 != null) {
SQLRow rowCpt = compteTable.getRow(n2.intValue());
final SQLBackgroundTableCacheItem cacheForTableCpt = SQLBackgroundTableCache.getInstance().getCacheForTable(compteTable);
SQLRow rowCpt = cacheForTableCpt.getRowFromId(n2.intValue());
if (rowCpt == null) {
rowCpt = compteTable.getRow(n2.intValue());
}
this.mEcritures.put("COMPTE_NUMERO", rowCpt.getString("NUMERO"));
this.mEcritures.put("COMPTE_NOM", rowCpt.getString("NOM"));
}
143,17 → 155,18
// TODO checker que les ecritures sont entrees à une date correcte
Date d = (Date) this.mEcritures.get("DATE");
 
SQLTable tableExercice = Configuration.getInstance().getBase().getTable("EXERCICE_COMMON");
SQLRow rowSociete = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
SQLRow rowExercice = tableExercice.getRow(rowSociete.getInt("ID_EXERCICE_COMMON"));
Date dDebEx = (Date) rowExercice.getObject("DATE_DEB");
if (this.dDebEx == null) {
SQLTable tableExercice = Configuration.getInstance().getBase().getTable("EXERCICE_COMMON");
SQLRow rowSociete = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
SQLRow rowExercice = tableExercice.getRow(rowSociete.getInt("ID_EXERCICE_COMMON"));
this.dDebEx = (Date) rowExercice.getObject("DATE_DEB");
this.dCloture = (Date) rowExercice.getObject("DATE_CLOTURE");
}
 
Date dCloture = (Date) rowExercice.getObject("DATE_CLOTURE");
 
if (dCloture != null) {
if (dCloture.after(d)) {
final String error = "Impossible de générer l'écriture pour la date " + SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL).format(d)
+ ". Cette date est postérieure à la date de clôture (" + SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL).format(dCloture) + ")";
+ ". Cette date est antérieure à la date de clôture (" + SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL).format(dCloture) + ")";
throw new IllegalArgumentException(error);
}
} else {
168,17 → 181,14
valEcriture.put("IDUSER_CREATE", UserManager.getInstance().getCurrentUser().getId());
 
try {
if (valEcriture.getInvalid() == null) {
// ajout de l'ecriture
SQLRow ecritureRow = valEcriture.insert();
// ajout de l'ecriture
// SQLRow ecritureRow = valEcriture.insert();
SQLRow ecritureRow = valEcriture.getGraph().store(StoreMode.INSERT, false).getStoredRow(valEcriture);
 
// TODO Analytique
addAssocAnalytiqueFromProvider(ecritureRow, this.rowAnalytiqueSource);
return ecritureRow;
} else {
System.err.println("GenerationEcritures.java :: Error in values for insert in table " + GenerationEcritures.ecritureTable.getName() + " : " + valEcriture.toString());
throw new IllegalArgumentException("Erreur lors de la génération des écritures données incorrectes. " + valEcriture);
}
// TODO Analytique
addAssocAnalytiqueFromProvider(ecritureRow, this.rowAnalytiqueSource);
return ecritureRow;
 
} catch (SQLException e) {
System.err.println("Error insert row in " + GenerationEcritures.ecritureTable.getName() + " : " + e);
final SQLException eFinal = e;
368,27 → 378,41
return getNewMouvement(source, idSource, idPere, rowValsPiece);
}
 
protected TotalCalculator getValuesFromElement(SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, SQLTable tableEchantillon) {
return getValuesFromElement(false, false, "T_PV_HT", row, foreign, portHT, rowTVAPort, tableEchantillon, null);
protected TotalCalculator getValuesFromElement(SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, BigDecimal fraisDocHT, SQLRow rowTVAFraisDoc, SQLTable tableEchantillon) {
return getValuesFromElement(false, false, "T_PV_HT", row, foreign, portHT, rowTVAPort, fraisDocHT, rowTVAFraisDoc, tableEchantillon, null);
}
 
protected TotalCalculator getValuesFromElement(boolean intra, boolean achat, String fieldTotalHT, SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, SQLTable tableEchantillon,
SQLRow defaultCompte) {
protected TotalCalculator getValuesFromElement(boolean intra, boolean achat, String fieldTotalHT, SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, BigDecimal fraisDocHT,
SQLRow rowTVAFraisDoc, SQLTable tableEchantillon, SQLRow defaultCompte) {
 
TotalCalculator calc = new TotalCalculator("T_PA_HT", fieldTotalHT, null, achat, defaultCompte);
final SQLRow tiers;
if (achat) {
tiers = row.getForeign("ID_FOURNISSEUR");
} else {
tiers = row.getForeign("ID_CLIENT");
}
 
SQLRowAccessor rowCatCompta = null;
if (tiers.getObject("ID_CATEGORIE_COMPTABLE") != null && !tiers.isForeignEmpty("ID_CATEGORIE_COMPTABLE")) {
rowCatCompta = tiers.getForeign("ID_CATEGORIE_COMPTABLE");
}
TotalCalculator calc = new TotalCalculator("T_PA_HT", fieldTotalHT, null, achat, defaultCompte, rowCatCompta);
calc.setIntraComm(intra);
 
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean bServiceActive = Boolean.valueOf(val);
 
calc.setServiceActive(bServiceActive != null && bServiceActive);
 
SQLBackgroundTableCacheItem cacheCompte = SQLBackgroundTableCache.getInstance().getCacheForTable(compteTable);
if (row.getTable().contains("ID_COMPTE_PCE_SERVICE") && !row.isForeignEmpty("ID_COMPTE_PCE_SERVICE")) {
SQLRowAccessor serviceCompte = row.getForeign("ID_COMPTE_PCE_SERVICE");
if (!serviceCompte.isUndefined()) {
SQLRowAccessor serviceCompte = cacheCompte.getRowFromId(row.getForeignID("ID_COMPTE_PCE_SERVICE"));
if (serviceCompte != null && !serviceCompte.isUndefined()) {
calc.setRowDefaultCptService(serviceCompte);
}
}
if (row.getTable().contains("ID_COMPTE_PCE_VENTE") && !row.isForeignEmpty("ID_COMPTE_PCE_VENTE")) {
SQLRowAccessor produitCompte = row.getForeign("ID_COMPTE_PCE_VENTE");
SQLRowAccessor produitCompte = cacheCompte.getRowFromId(row.getForeignID("ID_COMPTE_PCE_VENTE"));
if (!produitCompte.isUndefined()) {
calc.setRowDefaultCptProduit(produitCompte);
}
395,11 → 419,14
}
long remise = 0;
BigDecimal totalAvtRemise = BigDecimal.ZERO;
OOXMLCache cacheRefRows = new OOXMLCache();
final List<? extends SQLRowAccessor> referentRows = cacheRefRows.getReferentRows(Arrays.asList(row), foreign);
if (row.getTable().contains("REMISE_HT")) {
remise = row.getLong("REMISE_HT");
if (remise != 0) {
List<SQLRow> rows = row.getReferentRows(foreign);
for (SQLRow sqlRow : rows) {
 
// List<SQLRow> rows = row.getReferentRows(foreign);
for (SQLRowAccessor sqlRow : referentRows) {
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), 1, false);
}
 
429,10 → 456,10
}
calc.setRemise(valRemiseHTReel, totalAvtRemise);
 
List<SQLRow> rows = row.getReferentRows(foreign);
for (int i = 0; i < rows.size(); i++) {
SQLRow sqlRow = rows.get(i);
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), i, i == rows.size() - 1);
// List<SQLRow> rows = row.getReferentRows(foreign);
for (int i = 0; i < referentRows.size(); i++) {
SQLRowAccessor sqlRow = referentRows.get(i);
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), i, i == referentRows.size() - 1);
}
 
if (tableEchantillon != null) {
448,10 → 475,10
rowValsPort.put("ID_TAXE", rowTVAPort.getIDNumber());
 
final SQLTable tablePrefCompte = Configuration.getInstance().getRoot().findTable("PREFS_COMPTE");
final SQLRow rowPrefsCompte = tablePrefCompte.getRow(2);
final SQLRow rowPrefsCompte = SQLBackgroundTableCache.getInstance().getCacheForTable(tablePrefCompte).getRowFromId(2);
SQLRow rowDefaultCptPort;
if (rowTVAPort.getFloat("TAUX") > 0) {
rowDefaultCptPort = rowPrefsCompte.getForeign("ID_COMPTE_PCE_PORT_SOUMIS");
rowDefaultCptPort = cacheCompte.getRowFromId(rowPrefsCompte.getForeignID("ID_COMPTE_PCE_PORT_SOUMIS"));
if (rowDefaultCptPort == null || rowDefaultCptPort.isUndefined()) {
try {
rowDefaultCptPort = ComptePCESQLElement.getRowComptePceDefault("PortVenteSoumisTVA");
460,7 → 487,7
}
}
} else {
rowDefaultCptPort = rowPrefsCompte.getForeign("ID_COMPTE_PCE_PORT_NON_SOUMIS");
rowDefaultCptPort = cacheCompte.getRowFromId(rowPrefsCompte.getForeignID("ID_COMPTE_PCE_PORT_NON_SOUMIS"));
if (rowDefaultCptPort == null || rowDefaultCptPort.isUndefined()) {
try {
rowDefaultCptPort = ComptePCESQLElement.getRowComptePceDefault("PortVenteNonSoumisTVA");
472,8 → 499,21
final SQLRowValues rowValsArt = rowValsPort.putRowValues("ID_ARTICLE");
rowValsArt.put(achat ? "ID_COMPTE_PCE_ACHAT" : "ID_COMPTE_PCE", rowDefaultCptPort.getID());
rowValsArt.put("ID_TAXE_COMPLEMENTAIRE", null);
rowValsArt.put("ID_FAMILLE_ARTICLE", null);
calc.addLine(rowValsPort, rowValsPort.getForeign("ID_ARTICLE"), 1, false);
}
 
if (rowTVAFraisDoc != null && !rowTVAFraisDoc.isUndefined()) {
// Frais documents
SQLRowValues rowValsFraisDoc = new SQLRowValues(foreign);
rowValsFraisDoc.put(achat ? "T_PA_HT" : "T_PV_HT", fraisDocHT);
rowValsFraisDoc.put("QTE", 1);
rowValsFraisDoc.put("ID_TAXE", rowTVAFraisDoc.getIDNumber());
rowValsFraisDoc.put("SERVICE", Boolean.TRUE);
rowValsFraisDoc.put("ID_FAMILLE_ARTICLE", null);
calc.addLine(rowValsFraisDoc, null, 1, false);
}
 
calc.checkResult();
return calc;
}
646,4 → 686,5
}
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtAvoirClient.java
100,9 → 100,10
 
TotalCalculator calc;
if (rowClient.getTable().contains("ID_COMPTE_PCE_PRODUIT") && !rowClient.isForeignEmpty("ID_COMPTE_PCE_PRODUIT")) {
calc = getValuesFromElement(false, false, "T_PV_HT", avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, null, rowClient.getForeign("ID_COMPTE_PCE_PRODUIT"));
calc = getValuesFromElement(false, false, "T_PV_HT", avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, BigDecimal.ZERO, null, null,
rowClient.getForeign("ID_COMPTE_PCE_PRODUIT"));
} else {
calc = getValuesFromElement(avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, null);
calc = getValuesFromElement(avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, BigDecimal.ZERO, null, null);
}
Map<SQLRowAccessor, Map<SQLRowAccessor, BigDecimal>> taxeCompl = calc.getMapHtTaxeCompl();
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementVenteNG.java
63,7 → 63,12
 
public GenerationReglementVenteNG(String label, SQLRow rowClient, PrixTTC ttc, Date d, SQLRow modeReglement, SQLRow source, SQLRow mvtSource, boolean createEncaisse, boolean avance)
throws Exception {
this(label, rowClient, ttc, d, modeReglement, source, mvtSource, createEncaisse, avance, rowClient.getString("NOM"), null);
}
 
public GenerationReglementVenteNG(String label, SQLRow rowClient, PrixTTC ttc, Date d, SQLRow modeReglement, SQLRow source, SQLRow mvtSource, boolean createEncaisse, boolean avance, String tiers,
SQLRowAccessor cptTiers) throws Exception {
 
SQLRow typeRegRow = modeReglement.getForeignRow("ID_TYPE_REGLEMENT");
setRowAnalytiqueSource(source);
// iniatilisation des valeurs de la map
107,7 → 112,8
if (createEncaisse) {
SQLRowValues rowVals = new SQLRowValues(tableEncaisse);
rowVals.put("MONTANT", ttc.getLongValue());
rowVals.put("ID_CLIENT", rowClient.getID());
rowVals.put("ID_CLIENT", rowClient != null ? rowClient.getID() : null);
rowVals.put("TIERS", tiers);
rowVals.put("DATE", this.date);
if (typeRegRow.getID() >= TypeReglementSQLElement.TRAITE) {
Calendar c2 = modeReglement.getDate("DATE_VIREMENT");
154,9 → 160,9
 
Calendar c = modeReglement.getDate("DATE_DEPOT");
if (c != null) {
paiementCheque(c.getTime(), source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance);
paiementCheque(c.getTime(), source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance, tiers, cptTiers);
} else {
paiementCheque(this.date, source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance);
paiementCheque(this.date, source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance, tiers, cptTiers);
}
 
} else {
176,7 → 182,7
this.putValue("ID_JOURNAL", JournalSQLElement.CAISSES);
}
 
int idCompteClient = rowClient.getInt("ID_COMPTE_PCE");
int idCompteClient = cptTiers != null && !cptTiers.isUndefined() ? cptTiers.getID() : rowClient.getInt("ID_COMPTE_PCE");
if (avance) {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_AVANCE_CLIENT");
if (idCompteClient <= 1) {
239,7 → 245,9
valEcheance.put("ID_MOUVEMENT", Integer.valueOf(this.idMvt));
valEcheance.put("DATE", dateEch);
valEcheance.put("MONTANT", Long.valueOf(ttc.getLongValue()));
valEcheance.put("ID_CLIENT", rowClient.getID());
valEcheance.put("ID_CLIENT", rowClient == null ? null : rowClient.getID());
valEcheance.put("TIERS", tiers);
valEcheance.put("ID_COMPTE_PCE_TIERS", cptTiers == null || !cptTiers.isUndefined() ? null : cptTiers.getID());
if (source.getTable().equals(tableSaisieVenteFacture)) {
valEcheance.put("ID_SAISIE_VENTE_FACTURE", source.getID());
}
334,13 → 342,15
}
}
 
private void paiementCheque(Date dateEch, SQLRow source, PrixTTC ttc, SQLRow rowClient, SQLRow modeRegl, SQLRow mvtSource, boolean avance) throws Exception {
private void paiementCheque(Date dateEch, SQLRow source, PrixTTC ttc, SQLRow rowClient, SQLRow modeRegl, SQLRow mvtSource, boolean avance, String tiers, SQLRowAccessor cptTiers) throws Exception {
 
SQLRowValues valCheque = new SQLRowValues(base.getTable("CHEQUE_A_ENCAISSER"));
SQLPreferences prefs = SQLPreferences.getMemCached(valCheque.getTable().getDBRoot());
boolean createEcr = prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CREATE_ECR_CHQ, true);
 
valCheque.put("ID_CLIENT", rowClient.getID());
valCheque.put("ID_CLIENT", rowClient == null ? null : rowClient.getID());
valCheque.put("ID_COMPTE_PCE_TIERS", cptTiers == null ? null : cptTiers.getID());
valCheque.put("TIERS", tiers);
valCheque.put("SANS_VALEUR_ENCAISSEMENT", !createEcr);
final String foreignBanqueFieldName = "ID_" + BanqueSQLElement.TABLENAME;
if (valCheque.getTable().contains(foreignBanqueFieldName))
364,7 → 374,7
}
 
if (createEcr) {
int idCompteClient = rowClient.getInt("ID_COMPTE_PCE");
int idCompteClient = cptTiers == null || cptTiers.isUndefined() ? rowClient.getInt("ID_COMPTE_PCE") : cptTiers.getID();
if (avance) {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_AVANCE_CLIENT");
if (idCompteClient <= 1) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtAvoirFournisseur.java
15,9 → 15,11
 
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.model.PrixHT;
import org.openconcerto.erp.model.PrixTTC;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
 
91,6 → 93,7
SQLRow rowEcr = ajoutEcriture();
// addAssocAnalytiqueFromProvider(rowEcr, avoirRow);
 
SQLRowAccessor taxe = TaxeCache.getCache().getRowFromId(avoirRow.getForeignID("ID_TAXE"));
if (prixTVA.getLongValue() > 0) {
// compte TVA
int idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
100,9 → 103,19
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVAImmo");
}
} else {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVADeductible");
if (rowFourn.getBoolean("UE")) {
idCompteTVA = taxe.getForeignID("ID_COMPTE_PCE_DED_INTRA");
if (idCompteTVA <= 1) {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVAIntraComm");
}
}
} else {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVADeductible");
}
}
}
 
112,9 → 125,12
ajoutEcriture();
 
if (rowFourn.getBoolean("UE")) {
int idCompteTVAIntra = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
int idCompteTVAIntra = taxe.getForeignID("ID_COMPTE_PCE_COLLECTE_INTRA");
if (idCompteTVAIntra <= 1) {
idCompteTVAIntra = ComptePCESQLElement.getIdComptePceDefault("TVAIntraComm");
idCompteTVAIntra = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
if (idCompteTVAIntra <= 1) {
idCompteTVAIntra = ComptePCESQLElement.getIdComptePceDefault("TVAIntraComm");
}
}
this.putValue("ID_COMPTE_PCE", Integer.valueOf(idCompteTVAIntra));
this.putValue("DEBIT", Long.valueOf(prixTVA.getLongValue()));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtSaisieVenteFacture.java
139,12 → 139,14
 
SQLTable tableEchantillon = null;
BigDecimal portHT = BigDecimal.valueOf(saisieRow.getLong("PORT_HT")).movePointLeft(2);
BigDecimal fraisDocHT = BigDecimal.valueOf(saisieRow.getLong("FRAIS_DOCUMENT_HT")).movePointLeft(2);
TotalCalculator calc;
if (clientRow.getTable().contains("ID_COMPTE_PCE_PRODUIT") && !clientRow.isForeignEmpty("ID_COMPTE_PCE_PRODUIT")) {
calc = getValuesFromElement(false, false, "T_PV_HT", saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), tableEchantillon,
clientRow.getForeign("ID_COMPTE_PCE_PRODUIT"));
calc = getValuesFromElement(false, false, "T_PV_HT", saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), fraisDocHT,
saisieRow.getForeign("ID_TAXE_FRAIS_DOCUMENT"), tableEchantillon, clientRow.getForeign("ID_COMPTE_PCE_PRODUIT"));
} else {
calc = getValuesFromElement(saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), tableEchantillon);
calc = getValuesFromElement(saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), fraisDocHT,
saisieRow.getForeign("ID_TAXE_FRAIS_DOCUMENT"), tableEchantillon);
}
 
// On génére les ecritures si la facture n'est pas un acompte
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementAchat.java
72,6 → 72,9
}
 
SQLRow rowMvtSource = tableMouvement.getRow(mvtSource);
if (rowMvtSource == null) {
throw new IllegalStateException("Aucun mouvement source associé aux échéances.\n(Mouvement source : " + mvtSource + ", REGLER_MONTANT " + regMontantRow.getID() + ")");
}
 
// si paiement comptant
if ((modeRegRow.getInt("AJOURS") == 0) && (modeRegRow.getInt("LENJOUR") == 0)) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtFactureFournisseur.java
96,7 → 96,7
}
BigDecimal portHT = BigDecimal.valueOf(saisieRow.getLong("PORT_HT")).movePointLeft(2);
TotalCalculator calc = getValuesFromElement(rowFournisseur.getBoolean("UE"), true, "T_PA_HT", saisieRow, saisieRow.getTable().getTable("FACTURE_FOURNISSEUR_ELEMENT"), portHT,
saisieRow.getForeign("ID_TAXE_PORT"), null, rowCompteAchat);
saisieRow.getForeign("ID_TAXE_PORT"), BigDecimal.ZERO, null, null, rowCompteAchat);
 
long ttcLongValue = calc.getTotalTTC().movePointRight(2).longValue();
long htLongValue = calc.getTotalHT().movePointRight(2).longValue();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/action/ListeDesArticlesAction.java
22,13 → 22,14
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.view.ListeAddPanel;
52,6 → 53,7
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
82,8 → 84,10
final FamilleArticlePanel panelFam = new FamilleArticlePanel(elt.getForeignElement("ID_FAMILLE_ARTICLE"));
 
final SQLTableModelSourceOnline createTableSource = elt.createTableSource();
SQLPreferences prefs = SQLPreferences.getMemCached(elt.getTable().getDBRoot());
 
SQLTableModelColumn colStock;
SQLTableModelColumn colStock = null;
// if (!prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_MULTI_DEPOT, false)) {
if (elt.getTable().getDBRoot().contains("ARTICLE_PRIX_REVIENT")) {
colStock = createTableSource.getColumn(createTableSource.getColumns().size() - 2);
} else {
120,7 → 124,7
colStock.setRenderer(ComptaSQLConfElement.CURRENCY_RENDERER);
createTableSource.getColumns().add(colStock);
}
// createTableSource.getColumns().add(colStock);
// }
final IListe liste = new IListe(createTableSource);
 
final ListeAddPanel panel = new ListeAddPanel(elt, liste) {
131,7 → 135,7
GridBagConstraints c = new DefaultGridBagConstraints();
c.gridwidth = 2;
panel.add(new JLabel("Voulez vous supprimer ou rendre obsoléte?"), c);
JButton buttonObs = new JButton("Obsoléte");
JButton buttonObs = new JButton("Obsolète");
JButton buttonSuppr = new JButton("Supprimer");
c.gridy++;
panel.add(buttonObs, c);
205,17 → 209,20
// });
// }
// }
List<Tuple2<? extends SQLTableModelColumn, IListTotalPanel.Type>> fields = new ArrayList<Tuple2<? extends SQLTableModelColumn, IListTotalPanel.Type>>(1);
fields.add(Tuple2.create(colStock, IListTotalPanel.Type.SOMME));
 
IListTotalPanel total = new IListTotalPanel(liste, fields, null, "Total");
GridBagConstraints c2 = new DefaultGridBagConstraints();
c2.gridy = 4;
c2.anchor = GridBagConstraints.EAST;
c2.weightx = 0;
c2.fill = GridBagConstraints.NONE;
panel.add(total, c2);
if (colStock != null) {
// && !prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_MULTI_DEPOT, false)) {
List<Tuple2<? extends SQLTableModelColumn, IListTotalPanel.Type>> fields = new ArrayList<Tuple2<? extends SQLTableModelColumn, IListTotalPanel.Type>>(1);
fields.add(Tuple2.create(colStock, IListTotalPanel.Type.SOMME));
 
IListTotalPanel total = new IListTotalPanel(liste, fields, null, "Total");
GridBagConstraints c2 = new DefaultGridBagConstraints();
c2.gridy = 4;
c2.anchor = GridBagConstraints.EAST;
c2.weightx = 0;
c2.fill = GridBagConstraints.NONE;
panel.add(total, c2);
}
JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(panelFam), panel);
JPanel panelAll = new JPanel(new GridBagLayout());
GridBagConstraints c = new DefaultGridBagConstraints();
300,18 → 307,20
if (panel.getCheckObsolete().isSelected()) {
w = new Where(this.sqlTableArticle.getField("OBSOLETE"), "=", Boolean.FALSE);
 
w = w.or(new Where(request.getAlias(this.sqlTableArticle.getForeignTable("ID_STOCK").getField("QTE_REEL")), ">", 0));
// FIXME Fonctionnement avec multidepot
// w = w.or(new
// Where(request.getAlias(this.sqlTableArticle.getForeignTable("ID_STOCK").getField("QTE_REEL")),
// ">", 0));
}
 
if (id > 1) {
SQLRow row = this.sqlTableFamilleArticle.getRow(id);
Set<Integer> idsMatch = new HashSet<>();
idsMatch.add(id);
 
fillChildren(idsMatch, CollectionUtils.createSet(id));
 
Where w2 = new Where(this.sqlTableArticle.getField("ID_FAMILLE_ARTICLE"), "=", this.sqlTableFamilleArticle.getKey());
 
String code = row.getString("CODE") + ".%";
final Where w3 = new Where(this.sqlTableFamilleArticle.getField("CODE"), "LIKE", code);
w2 = w2.and(w3.or(new Where(this.sqlTableFamilleArticle.getKey(), "=", id)));
 
w2 = w2.and(new Where(this.sqlTableFamilleArticle.getKey(), idsMatch));
if (w != null) {
w = w.and(w2);
} else {
321,4 → 330,23
}
return w;
}
 
private void fillChildren(Set<Integer> idsMatch, Set<Integer> father) {
SQLRowValues rowVals = new SQLRowValues(this.sqlTableFamilleArticle);
final String keyFieldName = rowVals.getTable().getKey().getName();
rowVals.put(keyFieldName, null);
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowVals);
List<SQLRowValues> children = fetcher.fetch(new Where(this.sqlTableFamilleArticle.getField("ID_FAMILLE_ARTICLE_PERE"), father));
Set<Integer> childToCheck = new HashSet<>();
for (SQLRowValues child : children) {
if (!idsMatch.contains(child.getID())) {
childToCheck.add(child.getID());
idsMatch.add(child.getID());
}
}
if (!childToCheck.isEmpty()) {
fillChildren(idsMatch, childToCheck);
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/action/InventairePanel.java
14,6 → 14,7
package org.openconcerto.erp.core.sales.product.action;
 
import org.openconcerto.erp.core.common.ui.NumericTextField;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.ComposedItemStockUpdater;
import org.openconcerto.erp.core.supplychain.stock.element.StockItem;
import org.openconcerto.erp.core.supplychain.stock.element.StockItem.TypeStockMouvement;
21,7 → 22,6
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.view.list.IListe;
60,7 → 60,7
private final String mvtStockTableQuoted;
private static String defaultLabel = "Mise à jour des stocks";
 
public InventairePanel(final IListe liste, final List<? extends SQLRowAccessor> articles) {
public InventairePanel(final IListe liste, final List<? extends SQLRowAccessor> stocks) {
super(new GridBagLayout());
final SQLTable mvtStockTable = Configuration.getInstance().getRoot().findTable("MOUVEMENT_STOCK");
this.mvtStockTableQuoted = mvtStockTable.getSQLName().quote();
158,15 → 158,13
fieldReel.getDocument().addDocumentListener(l);
fieldRecpAtt.getDocument().addDocumentListener(l);
 
if (articles.size() == 1) {
SQLRowAccessor r = articles.get(0);
if (!r.isForeignEmpty("ID_STOCK")) {
SQLRowAccessor stock = r.getForeign("ID_STOCK");
fieldReel.setText(String.valueOf(stock.getFloat("QTE_REEL")));
fieldLivAtt.setText(String.valueOf(stock.getFloat("QTE_LIV_ATTENTE")));
fieldRecpAtt.setText(String.valueOf(stock.getFloat("QTE_RECEPT_ATTENTE")));
fieldTh.setText(String.valueOf(stock.getFloat("QTE_TH")));
}
if (stocks.size() == 1) {
SQLRowAccessor r = stocks.get(0);
SQLRowAccessor stock = r;
fieldReel.setText(String.valueOf(stock.getFloat("QTE_REEL")));
fieldLivAtt.setText(String.valueOf(stock.getFloat("QTE_LIV_ATTENTE")));
fieldRecpAtt.setText(String.valueOf(stock.getFloat("QTE_RECEPT_ATTENTE")));
fieldTh.setText(String.valueOf(stock.getFloat("QTE_TH")));
}
 
c.gridy++;
202,14 → 200,21
List<List<String>> multipleRequests = new ArrayList<List<String>>();
List<String> multipleRequestsHundred = new ArrayList<String>(100);
boolean usePrice = mvtStockTable.contains("PRICE");
 
List<StockItem> stockItems = new ArrayList<StockItem>();
final Date dateValue = date.getValue();
for (SQLRowAccessor sqlRowAccessor : articles) {
for (SQLRowAccessor sqlRowAccessor : stocks) {
if (multipleRequestsHundred.size() > 100) {
multipleRequests.add(multipleRequestsHundred);
multipleRequestsHundred = new ArrayList<String>(100);
}
StockItem item = new StockItem(sqlRowAccessor);
StockItem item = new StockItem(sqlRowAccessor.getForeign("ID_ARTICLE"), sqlRowAccessor);
if (!item.isStockInit()) {
((ReferenceArticleSQLElement) liste.getSource().getElem().getDirectory().getElement("ARTICLE")).initStock(sqlRowAccessor.getForeignID("ID_ARTICLE"));
SQLRow rowArticle = sqlRowAccessor.getForeign("ID_ARTICLE").asRow();
rowArticle.fetchValues();
item = new StockItem(rowArticle, rowArticle.getForeign("ID_STOCK"));
}
stockItems.add(item);
boolean modified = false;
if (qteReel != null && !NumberUtils.areNumericallyEqual(qteReel, item.getRealQty())) {
double diff = qteReel.doubleValue() - item.getRealQty();
235,18 → 240,7
if (item.isStockInit()) {
multipleRequestsHundred.add(item.getUpdateRequest());
} else {
SQLRowValues rowVals = new SQLRowValues(sqlRowAccessor.getTable().getForeignTable("ID_STOCK"));
rowVals.put("QTE_REEL", item.getRealQty());
rowVals.put("QTE_TH", item.getVirtualQty());
rowVals.put("QTE_LIV_ATTENTE", item.getDeliverQty());
rowVals.put("QTE_RECEPT_ATTENTE", item.getReceiptQty());
SQLRowValues rowValsArt = item.getArticle().createEmptyUpdateRow();
rowValsArt.put("ID_STOCK", rowVals);
try {
rowValsArt.commit();
} catch (SQLException e1) {
e1.printStackTrace();
}
throw new IllegalStateException();
}
}
 
269,12 → 263,12
 
final DBRoot root = mvtStockTable.getDBRoot();
if (root.contains("ARTICLE_ELEMENT")) {
List<StockItem> stockItems = new ArrayList<StockItem>();
for (SQLRowAccessor sqlRowAccessor2 : articles) {
final SQLRow asRow = sqlRowAccessor2.asRow();
asRow.fetchValues();
stockItems.add(new StockItem(asRow));
}
// List<StockItem> stockItems = new ArrayList<StockItem>();
// for (SQLRowAccessor sqlRowAccessor2 : stocks) {
// final SQLRow asRow = sqlRowAccessor2.asRow();
// asRow.fetchValues();
// stockItems.add(new StockItem(asRow));
// }
// Mise à jour des stocks des nomenclatures
ComposedItemStockUpdater comp = new ComposedItemStockUpdater(root, stockItems);
try {
292,14 → 286,14
 
private String getMvtRequest(Date time, BigDecimal prc, double qteFinal, StockItem item, String label, boolean reel, boolean usePrice) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String mvtStockQuery = "INSERT INTO " + mvtStockTableQuoted + " (\"QTE\",\"DATE\",\"ID_ARTICLE\",\"NOM\",\"REEL\",\"ORDRE\"";
String mvtStockQuery = "INSERT INTO " + mvtStockTableQuoted + " (\"QTE\",\"DATE\",\"ID_ARTICLE\",\"ID_STOCK\",\"NOM\",\"REEL\",\"ORDRE\"";
 
if (usePrice && prc != null) {
mvtStockQuery += ",\"PRICE\"";
}
 
mvtStockQuery += ") VALUES(" + qteFinal + ",'" + dateFormat.format(time) + "'," + item.getArticle().getID() + ",'" + label + "'," + reel + ", (SELECT (MAX(\"ORDRE\")+1) FROM "
+ mvtStockTableQuoted + ")";
mvtStockQuery += ") VALUES(" + qteFinal + ",'" + dateFormat.format(time) + "'," + item.getArticle().getID() + "," + item.stock.getID() + ",'" + label + "'," + reel
+ ", (SELECT (MAX(\"ORDRE\")+1) FROM " + mvtStockTableQuoted + ")";
if (usePrice && prc != null) {
mvtStockQuery += "," + prc.setScale(6, RoundingMode.HALF_UP).toString();
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/ArticleCategorieComptableTable.java
Nouveau fichier
0,0 → 1,80
/*
* 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.erp.core.sales.product.ui;
 
import org.openconcerto.erp.core.common.ui.DeviseNumericHTConvertorCellEditor;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.sales.product.component.ReferenceArticleSQLComponent;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.view.list.CellDynamicModifier;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTablePanel;
import org.openconcerto.sql.view.list.SQLTableElement;
import org.openconcerto.utils.DecimalUtils;
 
import java.math.BigDecimal;
import java.util.List;
import java.util.Vector;
 
public class ArticleCategorieComptableTable extends RowValuesTablePanel {
 
private SQLTableElement cat;
private SQLTable article = Configuration.getInstance().getBase().getTable("ARTICLE");
 
public ArticleCategorieComptableTable() {
 
init();
uiInit();
 
}
 
/**
*
*/
protected void init() {
 
final SQLElement e = getSQLElement();
 
final List<SQLTableElement> list = new Vector<SQLTableElement>();
 
this.cat = new SQLTableElement(e.getTable().getField("ID_CATEGORIE_COMPTABLE"));
this.cat.setEditable(false);
list.add(this.cat);
 
list.add(new SQLTableElement(e.getTable().getField("ID_COMPTE_PCE_VENTE")));
 
list.add(new SQLTableElement(e.getTable().getField("ID_TAXE_VENTE")));
list.add(new SQLTableElement(e.getTable().getField("ID_COMPTE_PCE_ACHAT")));
 
list.add(new SQLTableElement(e.getTable().getField("ID_TAXE_ACHAT")));
 
this.defaultRowVals = new SQLRowValues(getSQLElement().getTable());
this.model = new RowValuesTableModel(e, list, e.getTable().getField("ID_CATEGORIE_COMPTABLE"), false, this.defaultRowVals);
 
this.table = new RowValuesTable(this.model, null);
}
 
public SQLElement getSQLElement() {
return Configuration.getInstance().getDirectory().getElement("ARTICLE_CATEGORIE_COMPTABLE");
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/ArticleTarifTable.java
29,6 → 29,7
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTablePanel;
import org.openconcerto.sql.view.list.SQLTableElement;
import org.openconcerto.ui.table.NumberCellRenderer;
import org.openconcerto.utils.DecimalUtils;
 
import java.math.BigDecimal;
121,6 → 122,16
this.defaultRowVals.put("PRIX_METRIQUE_VT_1", BigDecimal.ZERO);
this.defaultRowVals.put("PV_HT", BigDecimal.ZERO);
this.defaultRowVals.put("PV_TTC", BigDecimal.ZERO);
if (e.getTable().contains("POURCENT_REMISE")) {
final SQLTableElement tableElementDiscount = new SQLTableElement(e.getTable().getField("POURCENT_REMISE"), BigDecimal.class) {
@Override
protected Object getDefaultNullValue() {
return BigDecimal.ZERO;
}
};
tableElementDiscount.setRenderer(new NumberCellRenderer());
list.add(tableElementDiscount);
}
this.model = new RowValuesTableModel(e, list, e.getTable().getField("ID_TARIF"), false, this.defaultRowVals);
 
this.table = new RowValuesTable(this.model, null);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/GestionArticlePreferencePanel.java
36,7 → 36,7
 
private final JCheckBox checkModeVente, checkLongueur, checkLargeur, checkPoids;
private final JCheckBox checkService, checkVenteComptoir, checkShowPoids, checkShowStyle, checkSFE;
private final JCheckBox checkDevise, checkMarge;
private final JCheckBox checkMarge;
private JCheckBox checkSite;
 
public GestionArticlePreferencePanel() {
55,12 → 55,9
this.checkModeVente = new JCheckBox("Activer le mode de vente spécifique");
this.checkVenteComptoir = new JCheckBox("Activer le mode vente comptoir");
this.checkShowPoids = new JCheckBox("Voir le Poids");
this.checkDevise = new JCheckBox("Gérer les devises");
this.checkMarge = new JCheckBox("Afficher le taux de marque au lieu du taux de marge");
 
 
this.add(this.checkDevise, c);
c.gridy++;
this.add(this.checkMarge, c);
c.gridy++;
this.add(this.checkService, c);
109,7 → 106,6
props.setProperty("ShowSiteFacture", String.valueOf(this.checkSite.isSelected()));
}
props.setProperty("ArticleVenteComptoir", String.valueOf(this.checkVenteComptoir.isSelected()));
props.setProperty(AbstractVenteArticleItemTable.ARTICLE_SHOW_DEVISE, String.valueOf(this.checkDevise.isSelected()));
props.setProperty(TotalPanel.MARGE_MARQUE, String.valueOf(this.checkMarge.isSelected()));
props.store();
}
123,7 → 119,6
this.checkService.setSelected(true);
this.checkSFE.setSelected(false);
this.checkVenteComptoir.setSelected(true);
this.checkDevise.setSelected(false);
this.checkMarge.setSelected(false);
if (this.checkSite != null) {
this.checkSite.setSelected(false);
172,10 → 167,8
// Show Style
this.checkShowStyle.setSelected(props.getBooleanValue("ArticleShowStyle", false));
 
// Devise
this.checkDevise.setSelected(props.getBooleanValue(AbstractVenteArticleItemTable.ARTICLE_SHOW_DEVISE, false));
 
// Devise
this.checkMarge.setSelected(props.getBooleanValue(TotalPanel.MARGE_MARQUE, false));
 
// Mode vente
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/ArticleFournisseurSecondaireTable.java
Nouveau fichier
0,0 → 1,62
/*
* 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.erp.core.sales.product.ui;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTablePanel;
import org.openconcerto.sql.view.list.SQLTableElement;
 
import java.util.List;
import java.util.Vector;
 
public class ArticleFournisseurSecondaireTable extends RowValuesTablePanel {
 
private SQLTable article = Configuration.getInstance().getBase().getTable("ARTICLE");
 
public ArticleFournisseurSecondaireTable() {
 
init();
uiInit();
 
}
 
/**
*
*/
protected void init() {
 
final SQLElement e = getSQLElement();
 
final List<SQLTableElement> list = new Vector<SQLTableElement>();
 
SQLTableElement f = new SQLTableElement(e.getTable().getField("ID_FOURNISSEUR"));
f.setEditable(false);
list.add(f);
 
this.defaultRowVals = new SQLRowValues(getSQLElement().getTable());
this.model = new RowValuesTableModel(e, list, e.getTable().getField("ID_FOURNISSEUR"), false, this.defaultRowVals);
 
this.table = new RowValuesTable(this.model, null);
}
 
public SQLElement getSQLElement() {
return Configuration.getInstance().getDirectory().getElement("ARTICLE_FOURNISSEUR_SECONDAIRE");
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/PriceByQty.java
56,6 → 56,9
});
for (PriceByQty priceByQty : list) {
if (priceByQty.qty > qty) {
if (result == null) {
result = priceByQty.price;
}
break;
}
if (result == null || priceByQty.startDate.before(d)) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/ProductHelper.java
24,6 → 24,7
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.cc.ITransformer;
 
import java.math.BigDecimal;
211,11 → 212,12
return getChildWithQtyFrom(items, new HashSet<Integer>());
}
 
private List<ProductComponent> getChildWithQtyFrom(List<ProductComponent> items, Set<Integer> ancestors) {
private List<ProductComponent> getChildWithQtyFrom(List<ProductComponent> items, Set<Integer> ancestorsOrigin) {
 
if (root.contains("ARTICLE_ELEMENT")) {
 
int originalAncestorsSize = ancestors.size();
int originalAncestorsSize = ancestorsOrigin.size();
Set<Integer> ancestors = new HashSet<Integer>(ancestorsOrigin);
 
List<ProductComponent> result = new ArrayList<ProductComponent>();
 
222,16 → 224,21
// liste des ids parents
final List<Integer> parentsArticleIDs = new ArrayList<Integer>();
 
// ID Article -- component
ListMap<Integer, ProductComponent> productCompByID = new ListMap<Integer, ProductComponent>();
 
// Quantité par parents
Map<Integer, ProductComponent> productCompByID = new HashMap<Integer, ProductComponent>();
final Map<Integer, BigDecimal> qtyParent = new HashMap<Integer, BigDecimal>();
// final ListMap<Integer, BigDecimal> qtyParentIDSource = new HashMap<Integer,
// BigDecimal>();
for (ProductComponent p : items) {
parentsArticleIDs.add(p.getProduct().getID());
BigDecimal qty = BigDecimal.ZERO;
if (qtyParent.get(p.getProduct().getID()) != null) {
qty = qtyParent.get(p.getProduct().getID());
}
qtyParent.put(p.getProduct().getID(), qty.add(p.getQty()));
productCompByID.add(p.getProduct().getID(), p);
int idSource = p.getProduct().getID();
parentsArticleIDs.add(idSource);
// BigDecimal qty = BigDecimal.ZERO;
// if (qtyParent.get(idSource) != null) {
// qty = qtyParent.get(idSource);
// }
// qtyParent.put(idSource, qty.add(p.getQty()));
}
 
// get all childs
239,8 → 246,10
 
SQLRowValues rowVals = new SQLRowValues(costTable);
 
final SQLRowValues stockRowValues = rowVals.putRowValues("ID_ARTICLE").put("ID", null).put("GESTION_STOCK", null).put("CODE", null).put("NOM", null).putRowValues("ID_STOCK");
stockRowValues.putNulls("QTE_TH", "QTE_RECEPT_ATTENTE", "QTE_REEL", "QTE_LIV_ATTENTE");
final SQLRowValues artRowValues = rowVals.putRowValues("ID_ARTICLE").putNulls("ID", "GESTION_STOCK", "CODE", "NOM", "ID_DEPOT_STOCK", "ID_UNITE_VENTE");
SQLRowValues stockRowVals = new SQLRowValues(root.getTable("STOCK"));
stockRowVals.putNulls("QTE_TH", "QTE_RECEPT_ATTENTE", "QTE_REEL", "QTE_LIV_ATTENTE", "ID_DEPOT_STOCK");
stockRowVals.put("ID_ARTICLE", artRowValues);
rowVals.putRowValues("ID_ARTICLE_PARENT").put("ID", null);
rowVals.put("QTE", null);
rowVals.put("QTE_UNITAIRE", null);
263,22 → 272,33
for (SQLRowValues childRowValues : childs) {
final SQLRowAccessor foreignArticleParent = childRowValues.getForeign("ID_ARTICLE_PARENT");
 
if (!childRowValues.isForeignEmpty("ID_ARTICLE") && childRowValues.getForeign("ID_ARTICLE") != null) {
ProductComponent childComponent = ProductComponent.createFrom(childRowValues);
if (childRowValues.getObject("ID_ARTICLE") != null && !childRowValues.isForeignEmpty("ID_ARTICLE")) {
 
List<ProductComponent> source = productCompByID.get(foreignArticleParent.getID());
// Test pour éviter les boucles dans les boms
if (!ancestors.contains(childComponent.getProduct().getID())) {
if (!ancestorsOrigin.contains(foreignArticleParent.getID())) {
ancestors.add(foreignArticleParent.getID());
// parentsArticleIDs.remove(foreignArticleParent.getID());
// Calcul de la quantité qte_unit * qte * qteMergedParent
childComponent.setQty(childComponent.getQty().multiply(qtyParent.get(foreignArticleParent.getID()), DecimalUtils.HIGH_PRECISION));
for (ProductComponent productParent : source) {
 
// Cumul des valeurs si l'article est présent plusieurs fois dans le bom
ProductComponent existProduct = productCompByID.get(childComponent.getProduct().getID());
if (existProduct == null) {
final SQLRowAccessor foreignArticle = childRowValues.getForeign("ID_ARTICLE");
ProductComponent childComponent = ProductComponent.createFromRowArticle(foreignArticle, productParent.getSource());
 
// parentsArticleIDs.remove(foreignArticleParent.getID());
// Calcul de la quantité qte_unit * qte * qteMergedParent
childComponent.setQty(childComponent.getQty().multiply(productParent.getQty(), DecimalUtils.HIGH_PRECISION));
 
// Cumul des valeurs si l'article est présent plusieurs fois dans le
// bom
// ProductComponent existProduct =
// productCompByID.get(childComponent.getProduct().getID());
// if (existProduct == null) {
// Maintenant on garde une ligne disctincte pour chaque kit
result.add(childComponent);
productCompByID.put(childComponent.getProduct().getID(), childComponent);
} else {
existProduct.addQty(childComponent.getQty());
// productCompByID.put(childComponent.getProduct().getID(),
// childComponent);
// } else {
// existProduct.addQty(childComponent.getQty());
// }
}
}
}
289,13 → 309,13
// Merge des valeurs
for (ProductComponent s : bomFromChilds) {
 
ProductComponent existProduct = productCompByID.get(s.getProduct().getID());
if (existProduct == null) {
result.add(s);
productCompByID.put(s.getProduct().getID(), s);
} else {
existProduct.addQty(s.getQty());
}
// ProductComponent existProduct = productCompByID.get(s.getProduct().getID());
// if (existProduct == null) {
result.add(s);
// productCompByID.put(s.getProduct().getID(), s);
// } else {
// existProduct.addQty(s.getQty());
// }
}
}
 
302,21 → 322,21
// Ajout des articles présents dans l'ensemble de départ
if (originalAncestorsSize == 0) {
for (ProductComponent p : items) {
ProductComponent existProduct = productCompByID.get(p.getProduct().getID());
if (existProduct == null) {
result.add(p);
productCompByID.put(p.getProduct().getID(), p);
} else {
existProduct.addQty(p.getQty());
}
// ProductComponent existProduct = productCompByID.get(p.getProduct().getID());
// if (existProduct == null) {
result.add(p);
// productCompByID.put(p.getProduct().getID(), p);
// } else {
// existProduct.addQty(p.getQty());
// }
}
}
 
// On supprime les ancestors (kits) du result
for (Integer anc : ancestors) {
ProductComponent comp = productCompByID.get(anc);
if (comp != null) {
result.remove(comp);
// ProductComponent comp = productCompByID.get(anc);
if (productCompByID.containsKey(anc)) {
result.removeAll(productCompByID.get(anc));
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/ProductComponent.java
14,13 → 14,19
package org.openconcerto.erp.core.sales.product.model;
 
import org.openconcerto.erp.core.sales.product.model.ProductHelper.SupplierPriceField;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
29,13 → 35,17
 
public class ProductComponent {
private final SQLRowAccessor product;
private final SQLRowAccessor source;
private final SQLRowAccessor stock;
private BigDecimal qty;
private final ProductHelper helper;
 
public ProductComponent(SQLRowAccessor product, BigDecimal qty) {
public ProductComponent(SQLRowAccessor product, BigDecimal qty, SQLRowAccessor source, SQLRowAccessor stock) {
this.product = product;
this.qty = qty;
this.helper = new ProductHelper(product.getTable().getDBRoot());
this.source = source;
this.stock = stock;
}
 
public SQLRowAccessor getProduct() {
42,6 → 52,14
return product;
}
 
public SQLRowAccessor getSource() {
return source;
}
 
public SQLRowAccessor getStock() {
return stock;
}
 
public BigDecimal getQty() {
return qty;
}
80,6 → 98,8
result = PriceByQty.getPriceForQty(qty.setScale(0, RoundingMode.HALF_UP).intValue(), prices, d);
if (result == null) {
result = PriceByQty.getPriceForQty(qty.setScale(0, RoundingMode.HALF_UP).intValue(), prices, lastDate);
} else if (prices.size() > 0) {
result = prices.get(0).getPrice();
}
}
if (result == null) {
112,16 → 132,87
return null;
}
 
public static ProductComponent createFromRowArticle(SQLRowAccessor rowArticle, SQLRowAccessor rowValsSource) {
SQLRowAccessor rowStock = getStock(rowArticle, rowArticle, rowValsSource);
 
return new ProductComponent(rowArticle, BigDecimal.ONE, rowValsSource, rowStock);
}
 
public static ProductComponent createFrom(SQLRowAccessor rowVals) {
return createFrom(rowVals, 1);
return createFrom(rowVals, 1, rowVals);
}
 
public static ProductComponent createFrom(SQLRowAccessor rowVals, int qteMultiple) {
public static ProductComponent createFrom(SQLRowAccessor rowVals, SQLRowAccessor rowValsSource) {
return createFrom(rowVals, 1, rowValsSource);
}
 
public static ProductComponent createFrom(SQLRowAccessor rowVals, int qteMultiple, SQLRowAccessor rowValsSource) {
 
if (rowVals.getForeign("ID_ARTICLE") == null || rowVals.isForeignEmpty("ID_ARTICLE")) {
throw new IllegalArgumentException("Aucun article associé à la row " + rowVals.getTable().getName() + " " + rowVals.getID());
}
final int qteMult = (rowVals.getTable().getName().equalsIgnoreCase("BON_DE_LIVRAISON_ELEMENT") ? rowVals.getInt("QTE_LIVREE") : rowVals.getInt("QTE"));
final int qte = qteMult * qteMultiple;
final BigDecimal qteUV = rowVals.getBigDecimal("QTE_UNITAIRE");
BigDecimal qteFinal = qteUV.multiply(new BigDecimal(qte), DecimalUtils.HIGH_PRECISION);
return new ProductComponent(rowVals.getForeign("ID_ARTICLE"), qteFinal);
SQLRowAccessor rowStock = getStock(rowVals.getForeign("ID_ARTICLE"), rowVals, rowValsSource);
 
// }
// else {
// rowStock = rowVals.getForeign("ID_ARTICLE").getForeign("ID_STOCK");
// }
return new ProductComponent(rowVals.getForeign("ID_ARTICLE"), qteFinal, rowValsSource, rowStock);
// return new ProductComponent(rowVals.getForeign("ID_ARTICLE"), qteFinal);
}
 
private static SQLRowAccessor getStock(SQLRowAccessor rowValsProduct, SQLRowAccessor rowValsElt, SQLRowAccessor rowValsSource) {
SQLRowAccessor rowStock = null;
final int idDepot;
if (rowValsSource.getFields().contains("ID_DEPOT_STOCK") && !rowValsSource.isForeignEmpty("ID_DEPOT_STOCK")) {
idDepot = rowValsSource.getForeignID("ID_DEPOT_STOCK");
} else {
if (rowValsElt.getForeign("ID_DEPOT_STOCK") != null && !rowValsElt.isForeignEmpty("ID_DEPOT_STOCK")) {
idDepot = rowValsElt.getForeignID("ID_DEPOT_STOCK");
} else {
idDepot = DepotStockSQLElement.DEFAULT_ID;
try {
rowValsElt.createEmptyUpdateRow().put("ID_DEPOT_STOCK", idDepot).commit();
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'initialisation du stock!", e);
}
 
}
}
 
SQLTable stockTable = rowValsElt.getTable().getTable("STOCK");
SQLRowValues putRowValuesStock = new SQLRowValues(stockTable);
putRowValuesStock.putNulls(stockTable.getTable().getFieldsName());
 
SQLRowValuesListFetcher fetch = SQLRowValuesListFetcher.create(putRowValuesStock);
Where w = new Where(putRowValuesStock.getTable().getField("ID_DEPOT_STOCK"), "=", idDepot);
Where w2 = new Where(putRowValuesStock.getTable().getField("ID_ARTICLE"), "=", rowValsProduct.getID());
Collection<SQLRowValues> rowValsResult = fetch.fetch(w.and(w2));
if (rowValsResult.size() == 0) {
SQLRowValues rowValsStock = new SQLRowValues(stockTable);
rowValsStock.put("ID_ARTICLE", rowValsProduct.getID());
rowValsStock.put("ID_DEPOT_STOCK", idDepot);
rowValsStock.put("QTE_TH", 0F);
rowValsStock.put("QTE_REEL", 0F);
rowValsStock.put("QTE_RECEPT_ATTENTE", 0F);
rowValsStock.put("QTE_LIV_ATTENTE", 0F);
try {
rowStock = rowValsStock.insert();
if (idDepot == DepotStockSQLElement.DEFAULT_ID) {
rowValsProduct.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();
}
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors la création du stock!", e);
}
} else if (rowValsResult.size() == 1) {
rowStock = rowValsResult.iterator().next();
} else if (rowValsResult.size() > 1) {
throw new IllegalStateException("2 lignes de stocks pour le même dépôt! Article " + rowValsProduct.getID() + " Depot " + rowValsElt.getForeignID("ID_DEPOT_STOCK"));
}
return rowStock;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/component/ReferenceArticleSQLComponent.java
21,12 → 21,17
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.sales.product.element.ArticleCodeClientTable;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.erp.core.sales.product.element.SupplierPriceListTable;
import org.openconcerto.erp.core.sales.product.element.UniteVenteArticleSQLElement;
import org.openconcerto.erp.core.sales.product.ui.ArticleCategorieComptableTable;
import org.openconcerto.erp.core.sales.product.ui.ArticleDesignationTable;
import org.openconcerto.erp.core.sales.product.ui.ArticleTarifTable;
import org.openconcerto.erp.core.sales.product.ui.ProductItemListTable;
import org.openconcerto.erp.core.sales.product.ui.ProductQtyPriceListTable;
import org.openconcerto.erp.core.sales.product.ui.RowValuesTableEditionPanel;
import org.openconcerto.erp.core.supplychain.stock.element.ComposedItemStockUpdater;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.StockItem;
import org.openconcerto.erp.model.ISQLCompteSelector;
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.erp.preferences.GestionArticleGlobalPreferencePanel;
38,9 → 43,11
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.preferences.SQLPreferences;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.FormLayouter;
import org.openconcerto.ui.TitledSeparator;
47,6 → 54,7
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.ui.preferences.DefaultProps;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
61,6 → 69,7
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
97,9 → 106,15
private ArticleDesignationTable tableDes = new ArticleDesignationTable();
private ArticleCodeClientTable tableCodeClient = new ArticleCodeClientTable();
private ArticleTarifTable tableTarifVente = new ArticleTarifTable(this);
private ArticleCategorieComptableTable tableCatComptable = new ArticleCategorieComptableTable();
private SupplierPriceListTable tableFourSec = new SupplierPriceListTable();
 
private ProductQtyPriceListTable tableTarifQteVente = new ProductQtyPriceListTable(this);
private ProductItemListTable tableBom;
private final JTextField textMarge = new JTextField(15);
private final JTextField textMarge = new JTextField(10);
private final JLabel labelMarge = new JLabel("% ");
private ElementComboBox boxCR;
private JCheckBox boxMargeWithCR;
 
private DocumentListener pieceHAArticle = new SimpleDocumentListener() {
 
139,10 → 154,19
ReferenceArticleSQLComponent.this.textMarge.getDocument().removeDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextMarge);
if (ReferenceArticleSQLComponent.this.textPVHT.getText().trim().length() > 0 && ReferenceArticleSQLComponent.this.textPAHT.getText().trim().length() > 0) {
final BigDecimal vt = StringUtils.getBigDecimalFromUserText(ReferenceArticleSQLComponent.this.textPVHT.getText());
final BigDecimal ha = StringUtils.getBigDecimalFromUserText(ReferenceArticleSQLComponent.this.textPAHT.getText());
BigDecimal ha = StringUtils.getBigDecimalFromUserText(ReferenceArticleSQLComponent.this.textPAHT.getText());
 
if (vt != null && ha != null) {
if (vt.signum() != 0 && ha.signum() != 0) {
 
if (boxMargeWithCR.isSelected() && boxCR != null) {
SQLRow rowCR = boxCR.getSelectedRow();
if (rowCR != null && !rowCR.isUndefined()) {
BigDecimal cr = rowCR.getBigDecimal("POURCENT");
ha = ha.multiply(cr.movePointLeft(2).add(BigDecimal.ONE), DecimalUtils.HIGH_PRECISION);
}
}
 
BigDecimal margeHT = vt.subtract(ha);
 
BigDecimal value;
162,6 → 186,7
} else {
ReferenceArticleSQLComponent.this.textMarge.setText("0");
}
labelMarge.setText("% (" + StringUtils.leftAlign(margeHT.setScale(2, RoundingMode.HALF_UP).toString(), 9) + ")");
}
}
}
184,18 → 209,34
BigDecimal ha = StringUtils.getBigDecimalFromUserText(this.textPAHT.getText());
if (ha != null && this.textMarge.getText().trim().length() > 0) {
 
if (boxMargeWithCR.isSelected() && boxCR != null) {
SQLRow rowCR = this.boxCR.getSelectedRow();
if (rowCR != null && !rowCR.isUndefined()) {
BigDecimal cr = rowCR.getBigDecimal("POURCENT");
ha = ha.multiply(cr.movePointLeft(2).add(BigDecimal.ONE), DecimalUtils.HIGH_PRECISION);
}
}
 
BigDecimal d = StringUtils.getBigDecimalFromUserText(this.textMarge.getText());
if (d == null) {
d = BigDecimal.ZERO;
}
final BigDecimal vt;
if (DefaultNXProps.getInstance().getBooleanValue(TotalPanel.MARGE_MARQUE, false)) {
final BigDecimal e = BigDecimal.ONE.subtract(d.divide(BigDecimal.valueOf(100), DecimalUtils.HIGH_PRECISION));
if (e.signum() == 0) {
this.textPVHT.setText("0");
vt = BigDecimal.ZERO;
} else {
this.textPVHT.setText(ha.divide(e, DecimalUtils.HIGH_PRECISION).setScale(getTable().getField("PV_HT").getType().getDecimalDigits(), RoundingMode.HALF_UP).toString());
vt = ha.divide(e, DecimalUtils.HIGH_PRECISION).setScale(getTable().getField("PV_HT").getType().getDecimalDigits(), RoundingMode.HALF_UP);
}
} else {
BigDecimal result = ha.multiply(d.divide(BigDecimal.valueOf(100), DecimalUtils.HIGH_PRECISION).add(BigDecimal.ONE));
this.textPVHT.setText(result.setScale(getTable().getField("PV_HT").getType().getDecimalDigits(), RoundingMode.HALF_UP).toString());
vt = result.setScale(getTable().getField("PV_HT").getType().getDecimalDigits(), RoundingMode.HALF_UP);
this.textPVHT.setText(vt.toString());
}
this.textPVHT.setText(vt.toString());
BigDecimal margeHT = vt.subtract(ha);
labelMarge.setText("% (" + StringUtils.leftAlign(margeHT.setScale(2, RoundingMode.HALF_UP).toString(), 9) + ")");
}
}
}
214,6 → 255,8
this.checkObs.setVisible(true);
this.tableTarifVente.setArticleValues(r);
this.tableTarifVente.insertFrom("ID_ARTICLE", r.getID());
this.tableCatComptable.insertFrom("ID_ARTICLE", r.getID());
this.tableFourSec.insertFrom("ID_ARTICLE", r.getID());
this.tableTarifQteVente.insertFrom("ID_ARTICLE", r.getID());
if (this.tableBom != null) {
this.tableBom.insertFrom("ID_ARTICLE_PARENT", r.getID());
306,6 → 349,7
// Gestion des unités de vente
final boolean gestionUV = prefs.getBoolean(GestionArticleGlobalPreferencePanel.UNITE_VENTE, true);
c.gridy++;
final ElementComboBox boxUnite = new ElementComboBox();
if (gestionUV) {
c.gridx = 0;
c.weightx = 0;
313,7 → 357,6
c.gridx++;
c.weightx = 1;
c.fill = GridBagConstraints.NONE;
ElementComboBox boxUnite = new ElementComboBox();
DefaultGridBagConstraints.lockMinimumSize(boxUnite);
this.add(boxUnite, c);
this.addView(boxUnite, "ID_UNITE_VENTE");
330,6 → 373,35
this.addView(fieldSKU, "SKU");
c.fill = GridBagConstraints.HORIZONTAL;
 
c.gridy++;
if (gestionUV) {
c.gridx = 0;
c.weightx = 0;
this.add(new JLabel(getLabelFor("QTE_UNITAIRE"), SwingConstants.RIGHT), c);
c.gridx++;
c.weightx = 1;
c.fill = GridBagConstraints.NONE;
final JTextField qte = new JTextField(10);
qte.setEditable(false);
 
this.add(qte, c);
this.addView(qte, "QTE_UNITAIRE", REQ);
boxUnite.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!boxUnite.isEmpty() && boxUnite.getSelectedId() == UniteVenteArticleSQLElement.A_LA_PIECE) {
qte.setText("1");
qte.setEditable(false);
} else {
qte.setEditable(true);
}
 
}
});
c.fill = GridBagConstraints.HORIZONTAL;
}
 
DefaultProps props = DefaultNXProps.getInstance();
 
// Article détaillé
460,8 → 532,19
ElementComboBox boxTaxeCompl = new ElementComboBox();
panel.add(boxTaxeCompl, c);
 
c.weightx = 0;
c.gridy++;
c.gridx = 0;
JLabel labelMatiere = new JLabel(getLabelFor("MATIERE"));
c.fill = GridBagConstraints.BOTH;
panel.add(labelMatiere, c);
c.weightx = 1;
c.gridx++;
SQLTextCombo comboMatiere = new SQLTextCombo();
panel.add(comboMatiere, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
TitledSeparator sep = new TitledSeparator(getLabelFor("INFOS"));
panel.add(sep, c);
472,6 → 555,7
panel.add(infos, c);
 
this.addSQLObject(infos, "INFOS");
this.addSQLObject(comboMatiere, "MATIERE");
this.addSQLObject(box, "ID_ECO_CONTRIBUTION");
this.addSQLObject(boxTaxeCompl, "ID_TAXE_COMPLEMENTAIRE");
return panel;
640,16 → 724,30
}
});
 
boolean visibleDepot = (prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_MULTI_DEPOT, false));
c.gridx = 0;
c.gridy++;
c.weightx = 0;
final JLabel labelDepot = new JLabel(getLabelFor("ID_DEPOT_STOCK"));
panel.add(labelDepot, c);
labelDepot.setVisible(visibleDepot);
c.gridx++;
c.weightx = 1;
ElementComboBox boxDepot = new ElementComboBox();
panel.add(boxDepot, c);
boxDepot.setVisible(visibleDepot);
this.addView(boxDepot, "ID_DEPOT_STOCK", REQ);
 
c.gridwidth = 1;
if (gestionStockMin) {
c.gridx = 0;
c.gridy++;
c.weightx = 0;
panel.add(new JLabel(getLabelFor("QTE_MIN")), c);
c.gridx++;
c.weightx = 1;
panel.add(fieldQteMin, c);
this.addView(fieldQteMin, "QTE_MIN");
// c.gridx = 0;
// c.gridy++;
// c.weightx = 0;
// panel.add(new JLabel(getLabelFor("QTE_MIN")), c);
// c.gridx++;
// c.weightx = 1;
// panel.add(fieldQteMin, c);
// this.addView(fieldQteMin, "QTE_MIN");
 
c.gridx = 0;
c.gridy++;
700,12 → 798,16
this.addView(selAchat, "ID_COMPTE_PCE_ACHAT");
 
c.gridy++;
c.gridx = 0;
c.weighty = 1;
c.weightx = 1;
c.fill = GridBagConstraints.BOTH;
final JPanel spacer = new JPanel();
spacer.setOpaque(false);
panel.add(spacer, c);
c.gridwidth = GridBagConstraints.REMAINDER;
 
panel.add(createCategorieComptablePanel(), c);
// final JPanel spacer = new JPanel();
// spacer.setOpaque(false);
// panel.add(spacer, c);
return panel;
}
 
752,13 → 854,85
}
});
} else {
 
// Tarif fournisseur
c.gridy++;
c.gridx = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
TitledSeparator sep = new TitledSeparator("Tarifs fournisseurs");
panel.add(sep, c);
 
// Ajout fournisseur
c.gridwidth = 1;
c.weightx = 0;
c.gridy++;
c.gridx = 0;
panel.add(new JLabel("Ajouter le fournisseur "), c);
 
final ElementComboBox boxF = new ElementComboBox();
boxF.init(Configuration.getInstance().getDirectory().getElement("FOURNISSEUR"));
 
c.gridx++;
panel.add(boxF, c);
 
c.fill = GridBagConstraints.NONE;
c.gridx++;
JButton buttonAjouter = new JButton("Ajouter");
buttonAjouter.setOpaque(false);
panel.add(buttonAjouter, c);
c.gridx++;
JButton buttonSupprimer = new JButton("Supprimer");
buttonSupprimer.setOpaque(false);
panel.add(buttonSupprimer, c);
 
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
c.weightx = 1;
c.gridy++;
c.gridx = 0;
c.fill = GridBagConstraints.BOTH;
final JPanel spacer = new JPanel();
spacer.setOpaque(false);
panel.add(spacer, c);
this.tableFourSec.setOpaque(false);
panel.add(this.tableFourSec, c);
 
// Listeners
buttonAjouter.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
 
SQLRow rowCat = boxF.getSelectedRow();
if (rowCat == null || rowCat.isUndefined()) {
return;
}
int nbRows = tableFourSec.getModel().getRowCount();
 
// for (int i = 0; i < nbRows; i++) {
// SQLRowValues rowVals = tableFourSec.getModel().getRowValuesAt(i);
// int idTarif =
// Integer.parseInt(rowVals.getObject("ID_FOURNISSEUR").toString());
// if (idTarif == rowCat.getID()) {
// JOptionPane.showMessageDialog(null, "Impossible d'ajouter.\nLe fournisseur
// est déjà présent dans la liste!");
// return;
// }
// }
 
SQLRowValues rowVals = new SQLRowValues(Configuration.getInstance().getBase().getTable("ARTICLE_TARIF_FOURNISSEUR"));
if (getSelectedID() > 1) {
rowVals.put("ID_ARTICLE", getSelectedID());
}
rowVals.put("ID_FOURNISSEUR", rowCat.getID());
tableFourSec.getModel().addRow(rowVals);
}
});
buttonSupprimer.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
tableFourSec.removeSelectedRow();
}
});
}
return panel;
}
887,6 → 1061,83
return panel;
}
 
private JPanel createCategorieComptablePanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
 
// Ajout catégorie
c.gridwidth = 1;
c.weightx = 0;
c.gridy++;
c.gridx = 0;
panel.add(new JLabel("Ajouter la catégorie "), c);
 
final ElementComboBox boxCat = new ElementComboBox();
boxCat.init(Configuration.getInstance().getDirectory().getElement("CATEGORIE_COMPTABLE"));
 
c.gridx++;
panel.add(boxCat, c);
 
c.fill = GridBagConstraints.NONE;
c.gridx++;
JButton buttonAjouter = new JButton("Ajouter");
buttonAjouter.setOpaque(false);
panel.add(buttonAjouter, c);
c.gridx++;
JButton buttonSupprimer = new JButton("Supprimer");
buttonSupprimer.setOpaque(false);
panel.add(buttonSupprimer, c);
 
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.weighty = 1;
c.gridy++;
c.gridx = 0;
c.fill = GridBagConstraints.BOTH;
this.tableCatComptable.setOpaque(false);
panel.add(this.tableCatComptable, c);
 
// Listeners
buttonAjouter.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
 
SQLRow rowCat = boxCat.getSelectedRow();
if (rowCat == null || rowCat.isUndefined()) {
return;
}
int nbRows = tableCatComptable.getModel().getRowCount();
 
for (int i = 0; i < nbRows; i++) {
SQLRowValues rowVals = tableCatComptable.getModel().getRowValuesAt(i);
int idTarif = Integer.parseInt(rowVals.getObject("ID_CATEGORIE_COMPTABLE").toString());
if (idTarif == rowCat.getID()) {
JOptionPane.showMessageDialog(null, "Impossible d'ajouter.\nLa catégorie est déjà présente dans la liste!");
return;
}
}
 
SQLRowValues rowVals = new SQLRowValues(Configuration.getInstance().getBase().getTable("ARTICLE_CATEGORIE_COMPTABLE"));
if (getSelectedID() > 1) {
rowVals.put("ID_ARTICLE", getSelectedID());
}
rowVals.put("ID_CATEGORIE_COMPTABLE", rowCat.getID());
tableCatComptable.getModel().addRow(rowVals);
}
});
buttonSupprimer.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
tableCatComptable.removeSelectedRow();
}
});
return panel;
}
 
private JPanel createBOMpanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
997,7 → 1248,7
this.textMarge.getDocument().addDocumentListener(this.listenerMargeTextMarge);
cAchat.gridx++;
cAchat.weightx = 0;
p.add(new JLabel("% "), cAchat);
p.add(this.labelMarge, cAchat);
 
// Poids
JLabel labelPds = new JLabel(getLabelFor("POIDS"));
1026,7 → 1277,58
c.fill = GridBagConstraints.NONE;
 
this.add(p, c);
c.gridx = 0;
c.gridy++;
c.gridwidth = 1;
 
if (getTable().contains("ID_COUT_REVIENT")) {
// Cout de revient
c.weightx = 0;
c.fill = GridBagConstraints.HORIZONTAL;
this.add(new JLabel(getLabelFor("ID_COUT_REVIENT"), SwingConstants.RIGHT), c);
 
JPanel pCR = new JPanel(new GridBagLayout());
GridBagConstraints cCR = new DefaultGridBagConstraints();
cCR.insets = new Insets(0, 0, 0, 4);
this.boxCR = new ElementComboBox(true, 15);
 
pCR.add(boxCR, cCR);
this.addView(boxCR, "ID_COUT_REVIENT");
DefaultGridBagConstraints.lockMinimumSize(boxCR);
boxCR.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!isFilling()) {
ReferenceArticleSQLComponent.this.textPVHT.getDocument().removeDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextVT);
updateVtFromMarge();
ReferenceArticleSQLComponent.this.textPVHT.getDocument().addDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextVT);
}
}
});
cCR.gridx++;
this.boxMargeWithCR = new JCheckBox(getLabelFor("MARGE_WITH_COUT_REVIENT"));
pCR.add(boxMargeWithCR, cCR);
addView(boxMargeWithCR, "MARGE_WITH_COUT_REVIENT");
boxMargeWithCR.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
if (!isFilling()) {
ReferenceArticleSQLComponent.this.textPVHT.getDocument().removeDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextVT);
updateVtFromMarge();
ReferenceArticleSQLComponent.this.textPVHT.getDocument().addDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextVT);
}
}
});
c.gridx++;
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.WEST;
c.weightx = 1;
c.fill = GridBagConstraints.NONE;
this.add(pCR, c);
}
 
// PV HT
c.gridx = 0;
c.gridy++;
1121,10 → 1423,12
this.taxeListener = new PropertyChangeListener() {
 
public void propertyChange(PropertyChangeEvent evt) {
if (ReferenceArticleSQLComponent.this.textPVHT.getText().trim().length() > 0) {
setTextTTC();
} else {
setTextHT();
if (!isFilling()) {
if (ReferenceArticleSQLComponent.this.textPVHT.getText().trim().length() > 0) {
setTextTTC();
} else {
setTextHT();
}
}
tableTarifVente.fireModification();
}
1258,8 → 1562,11
 
@Override
public void update() {
SQLRow row = this.getTable().getRow(this.getSelectedID());
super.update();
this.tableTarifVente.updateField("ID_ARTICLE", getSelectedID());
this.tableCatComptable.updateField("ID_ARTICLE", getSelectedID());
this.tableFourSec.updateField("ID_ARTICLE", getSelectedID());
this.tableTarifQteVente.updateField("ID_ARTICLE", getSelectedID());
if (this.tableBom != null) {
this.tableBom.updateField("ID_ARTICLE_PARENT", getSelectedID());
1270,6 → 1577,24
if (this.codeFournisseurTable != null) {
this.codeFournisseurTable.updateField("ID_ARTICLE", getSelectedID());
}
 
((ReferenceArticleSQLElement) getElement()).initStock(getSelectedID());
 
SQLSelect sel = new SQLSelect();
SQLTable tableStock = getTable().getTable("STOCK");
sel.addSelect(tableStock.getKey());
Where w = new Where(tableStock.getField("ID_ARTICLE"), "=", getSelectedID()).and(new Where(tableStock.getField("ID_DEPOT_STOCK"), "=", row.getForeignID("ID_DEPOT_STOCK")));
sel.setWhere(w);
 
List<SQLRow> stock = SQLRowListRSH.execute(sel);
if (stock != null && stock.size() == 1) {
try {
row.createEmptyUpdateRow().put("ID_STOCK", stock.get(0).getID()).update();
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de la mise à jour du stock principal", e);
}
}
 
}
 
/**
1324,6 → 1649,8
public int insert(SQLRow order) {
int id = super.insert(order);
this.tableTarifVente.updateField("ID_ARTICLE", id);
this.tableCatComptable.updateField("ID_ARTICLE", id);
this.tableFourSec.updateField("ID_ARTICLE", id);
this.tableTarifQteVente.updateField("ID_ARTICLE", id);
if (this.tableBom != null) {
this.tableBom.updateField("ID_ARTICLE_PARENT", id);
1333,6 → 1660,7
if (this.codeFournisseurTable != null) {
this.codeFournisseurTable.updateField("ID_ARTICLE", id);
}
((ReferenceArticleSQLElement) getElement()).initStock(id);
return id;
}
 
1341,12 → 1669,16
SQLRowValues rowVals = new SQLRowValues(getTable());
 
rowVals.put("ID_TAXE", TaxeCache.getCache().getFirstTaxe().getID());
rowVals.put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID);
rowVals.put("ID_UNITE_VENTE", UniteVenteArticleSQLElement.A_LA_PIECE);
rowVals.put("QTE_UNITAIRE", BigDecimal.ONE);
rowVals.put("ID_MODE_VENTE_ARTICLE", ReferenceArticleSQLElement.A_LA_PIECE);
selectModeVente(ReferenceArticleSQLElement.A_LA_PIECE);
rowVals.put("VALEUR_METRIQUE_1", Float.valueOf("1.0"));
rowVals.put("PA_HT", BigDecimal.ZERO);
rowVals.put("QTE_UNITAIRE", BigDecimal.ONE);
rowVals.put("POIDS", Float.valueOf(0));
rowVals.put("GESTION_STOCK", Boolean.TRUE);
 
return rowVals;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/SupplierPriceListSQLElement.java
Nouveau fichier
0,0 → 1,62
/*
* 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.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
 
import java.util.ArrayList;
import java.util.List;
 
public class SupplierPriceListSQLElement extends ComptaSQLConfElement {
public static final String ELEMENT_CODE = "supplier.pricelist";
 
public SupplierPriceListSQLElement() {
super("ARTICLE_TARIF_FOURNISSEUR");
}
 
@Override
protected String createCode() {
return ELEMENT_CODE;
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_ARTICLE");
l.add("ID_FOURNISSEUR");
l.add("QTE");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_ARTICLE");
l.add("ID_FOURNISSEUR");
return l;
}
 
@Override
protected String getParentFFName() {
return "ID_ARTICLE";
}
 
@Override
protected SQLComponent createComponent() {
// TODO Auto-generated method stub
return null;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ArticleSQLElement.java
18,11 → 18,13
import org.openconcerto.erp.model.PrixHT;
import org.openconcerto.erp.model.PrixTTC;
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.erp.preferences.GestionArticleGlobalPreferencePanel;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.ElementSQLObject;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.GestionDevise;
50,8 → 52,9
super("ARTICLE", "un article", "articles");
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>();
 
l.add("CODE");
l.add("NOM");
65,8 → 68,12
l.add("VALEUR_METRIQUE_3");
l.add("PRIX_METRIQUE_HA_1");
l.add("PRIX_METRIQUE_VT_1");
l.add("ID_STOCK");
SQLPreferences prefs = SQLPreferences.getMemCached(getTable().getDBRoot());
 
if (!prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_MULTI_DEPOT, false)) {
l.add("ID_STOCK");
}
 
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean b = Boolean.valueOf(val);
if (b != null && b.booleanValue()) {
75,8 → 82,9
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("CODE");
l.add("NOM");
return l;
95,8 → 103,7
private JTextField textNom, textCode;
private JTextField textPoids;
private DocumentListener htDocListener, ttcDocListener;
private PropertyChangeListener taxeListener;
final ElementComboBox comboSelTaxe = new ElementComboBox(false);
private final ElementComboBox comboSelTaxe = new ElementComboBox(false);
 
public void addViews() {
 
136,7 → 143,7
 
};
 
this.taxeListener = new PropertyChangeListener() {
PropertyChangeListener taxeListener = new PropertyChangeListener() {
 
public void propertyChange(PropertyChangeEvent evt) {
 
229,7 → 236,7
 
this.textPVHT.getDocument().addDocumentListener(this.htDocListener);
this.textPVTTC.getDocument().addDocumentListener(this.ttcDocListener);
this.comboSelTaxe.addValueListener(this.taxeListener);
this.comboSelTaxe.addValueListener(taxeListener);
}
 
private void setTextHT() {
268,4 → 275,9
}
};
}
 
@Override
protected String createCode() {
return "sales.product";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ArticleFournisseurSecondaireSQLElement.java
Nouveau fichier
0,0 → 1,89
/*
* 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.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JLabel;
import javax.swing.SwingConstants;
 
public class ArticleFournisseurSecondaireSQLElement extends ComptaSQLConfElement {
 
public ArticleFournisseurSecondaireSQLElement() {
super("ARTICLE_FOURNISSEUR_SECONDAIRE", "une liaison article fournisseur", "liaisons article fournisseur");
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_ARTICLE");
l.add("ID_FOURNISSEUR");
return l;
}
 
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_ARTICLE");
l.add("ID_FOURNISSEUR");
return l;
}
 
@Override
protected String getParentFFName() {
return "ID_ARTICLE";
}
 
/*
* (non-Javadoc)
*
* @see org.openconcerto.devis.SQLElement#getComponent()
*/
public SQLComponent createComponent() {
return new BaseSQLComponent(this) {
public void addViews() {
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
 
// Famille père
final JLabel labelLangue = new JLabel(getLabelFor("ID_ARTICLE"), SwingConstants.RIGHT);
c.gridx = 0;
c.gridy++;
c.weightx = 0;
this.add(labelLangue, c);
 
final ElementComboBox artBox = new ElementComboBox(true, 25);
DefaultGridBagConstraints.lockMinimumSize(artBox);
c.gridx++;
c.weightx = 1;
this.add(artBox, c);
 
this.addSQLObject(artBox, "ID_ARTICLE");
}
 
};
}
 
@Override
protected String createCode() {
return createCodeOfPackage() + ".supplier";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ReliquatSQLElement.java
48,7 → 48,7
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".reliquatbr";
return createCodeOfPackage() + ".reliquatbr";
}
}
 
187,6 → 187,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".reliquatbl";
return createCodeOfPackage() + ".reliquatbl";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ModeVenteArticleSQLElement.java
72,6 → 72,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".sale";
return createCodeOfPackage() + ".sale";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/UniteVenteArticleSQLElement.java
94,6 → 94,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".unit";
return createCodeOfPackage() + ".unit";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/MetriqueSQLElement.java
80,6 → 80,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".quantity";
return createCodeOfPackage() + ".quantity";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ProductItemSQLElement.java
17,7 → 17,6
import org.openconcerto.erp.core.sales.product.component.ProductItemGroup;
import org.openconcerto.sql.element.GroupSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.utils.ListMap;
 
import java.util.ArrayList;
28,7 → 27,7
public static final String TABLE_PRODUCT_ITEM = "ARTICLE_ELEMENT";
 
public ProductItemSQLElement() {
super(TABLE_PRODUCT_ITEM, "un élément de nomenclature", " éléments de nomenclature");
super(TABLE_PRODUCT_ITEM, "un élément de nomenclature", "éléments de nomenclature");
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/SupplierPriceListTable.java
Nouveau fichier
0,0 → 1,134
/*
* 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.
*/
/*
* 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.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.finance.accounting.model.CurrencyConverter;
import org.openconcerto.erp.core.sales.product.ui.CurrencyWithSymbolRenderer;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.view.list.CellDynamicModifier;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTablePanel;
import org.openconcerto.sql.view.list.SQLTableElement;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Vector;
 
public class SupplierPriceListTable extends RowValuesTablePanel {
 
public SupplierPriceListTable() {
init();
uiInit();
}
 
/**
*
*/
protected void init() {
final SQLElement eProductCost = getSQLElement();
final SQLTable productPropertyTable = eProductCost.getTable();
final List<SQLTableElement> list = new Vector<SQLTableElement>();
 
final SQLTableElement eSupplier = new SQLTableElement(productPropertyTable.getField("ID_FOURNISSEUR"));
list.add(eSupplier);
// list.add(new SQLTableElement(productPropertyTable.getField("REF_FOURNISSEUR")));
// list.add(new SQLTableElement(productPropertyTable.getField("TYPE_REAPPRO")));
// list.add(new SQLTableElement(productPropertyTable.getField("ACHETEUR")));
list.add(new SQLTableElement(productPropertyTable.getField("CODE_PAYS_ORIGINE")));
final SQLTableElement ePrixAchatDevise = new SQLTableElement(productPropertyTable.getField("PRIX_ACHAT_DEVISE_F"));
 
Path p = new Path(getSQLElement().getTable()).addForeignTable("FOURNISSEUR").addForeignField("ID_DEVISE");
ePrixAchatDevise.setRenderer(new CurrencyWithSymbolRenderer(new FieldPath(p, "CODE")));
list.add(ePrixAchatDevise);
final SQLTableElement ePrixAchat = new SQLTableElement(productPropertyTable.getField("PRIX_ACHAT"));
ePrixAchat.setRenderer(new CurrencyWithSymbolRenderer());
final CurrencyConverter c = new CurrencyConverter();
ePrixAchat.setModifier(new CellDynamicModifier() {
 
@Override
public Object computeValueFrom(SQLRowValues row, SQLTableElement source) {
if (row.getObject("ID_FOURNISSEUR") == null) {
return row.getBigDecimal("PRIX_ACHAT_DEVISE_F");
}
 
final String supplierCurrency = row.getForeign("ID_FOURNISSEUR").getForeign("ID_DEVISE").getString("CODE");
final BigDecimal prixAchatDevice = row.getBigDecimal("PRIX_ACHAT_DEVISE_F");
if (prixAchatDevice == null) {
return BigDecimal.ZERO;
}
try {
BigDecimal p = c.convert(prixAchatDevice, supplierCurrency, c.getCompanyCurrencyCode(), new Date(), true);
return p.setScale(2, RoundingMode.HALF_UP);
} catch (Exception e) {
e.printStackTrace();
}
 
return BigDecimal.ZERO;
}
});
ePrixAchat.setEditable(false);
list.add(ePrixAchat);
ePrixAchatDevise.addModificationListener(ePrixAchat);
ePrixAchatDevise.addModificationListener(eSupplier);
// final SQLTableElement eConditions = new
// SQLTableElement(productPropertyTable.getField("CONDITIONS"));
// eConditions.setEditor(new JComboBoxCellEditor(new
// JComboBox(ReferenceArticleSQLElement.CONDITIONS)));
// list.add(eConditions);
list.add(new SQLTableElement(productPropertyTable.getField("QTE")));
list.add(new SQLTableElement(productPropertyTable.getField("DATE_PRIX")));
 
list.add(new SQLTableElement(productPropertyTable.getField("DELAI_REAPPRO")));
list.add(new SQLTableElement(productPropertyTable.getField("DELAI_TRANSPORT")));
// list.add(new SQLTableElement(productPropertyTable.getField("PRIORITE")));
 
this.defaultRowVals = new SQLRowValues(getSQLElement().getTable());
this.defaultRowVals.put("QTE", 1);
this.defaultRowVals.put("PRIORITE", 1);
 
this.model = new RowValuesTableModel(eProductCost, list, productPropertyTable.getField("ID_FOURNISSEUR"), false, this.defaultRowVals);
 
this.table = new RowValuesTable(this.model, null);
}
 
protected String multiply(List<String> asList) {
return null;
}
 
public SQLElement getSQLElement() {
return Configuration.getInstance().getDirectory().getElement("ARTICLE_TARIF_FOURNISSEUR");
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/FamilleEcoContributionSQLElement.java
13,9 → 13,10
package org.openconcerto.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.ListMap;
 
27,12 → 28,17
import javax.swing.JLabel;
import javax.swing.JTextField;
 
public class FamilleEcoContributionSQLElement extends ConfSQLElement {
public class FamilleEcoContributionSQLElement extends ComptaSQLConfElement {
 
public FamilleEcoContributionSQLElement() {
super("FAMILLE_ECO_CONTRIBUTION");
public FamilleEcoContributionSQLElement(final DBRoot root) {
super(root.getTable("FAMILLE_ECO_CONTRIBUTION"));
}
 
@Override
protected String createCode() {
return this.createCodeOfPackage() + ".ewaste-family";
}
 
protected List<String> getListFields() {
final List<String> list = new ArrayList<String>(2);
list.add("NOM");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ReferenceArticleSQLElement.java
15,11 → 15,14
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.common.ui.PanelFrame;
import org.openconcerto.erp.core.edm.AttachmentAction;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.reports.history.ui.HistoriqueArticleFrame;
import org.openconcerto.erp.core.sales.product.action.InventairePanel;
import org.openconcerto.erp.core.sales.product.component.ReferenceArticleSQLComponent;
import org.openconcerto.erp.core.supplychain.stock.element.ComposedItemStockUpdater;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.StockItem;
import org.openconcerto.erp.generationDoc.gestcomm.FicheArticleXmlSheet;
import org.openconcerto.erp.model.MouseSheetXmlListeListener;
import org.openconcerto.erp.preferences.DefaultNXProps;
37,6 → 40,7
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel.EditMode;
import org.openconcerto.sql.view.list.BaseSQLTableModelColumn;
46,8 → 50,10
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSource;
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.ui.PanelFrame;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ListMap;
 
import java.awt.event.ActionEvent;
55,7 → 61,9
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import javax.swing.AbstractAction;
70,7 → 78,7
public static final int AU_METRE_LARGEUR = 6;
private static final int PRIX_HA = 1;
private static final int PRIX_VT = 2;
protected final PredicateRowAction stock;
protected PredicateRowAction stock;
 
public static final String[] CONDITIONS = new String[] { "CFR", "CIF", "CPT", "DAT", "DDP", "DDU", "EXW", "FCA", "FOB" };
 
83,7 → 91,13
@Override
public void actionPerformed(ActionEvent e) {
 
PanelFrame p = new PanelFrame(new InventairePanel(IListe.get(e), IListe.get(e).getSelectedRows()), "Mise à jour des stocks");
final List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
List<SQLRowAccessor> l = new ArrayList<SQLRowAccessor>();
for (SQLRowValues sqlRowValues : selectedRows) {
l.add(sqlRowValues.asRow().getForeign("ID_STOCK"));
}
 
PanelFrame p = new PanelFrame(new InventairePanel(IListe.get(e), l), "Mise à jour des stocks");
FrameUtil.show(p);
 
}
91,6 → 105,18
stock.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
getRowActions().add(stock);
 
PredicateRowAction history = new PredicateRowAction(new AbstractAction("Historique") {
 
@Override
public void actionPerformed(ActionEvent e) {
HistoriqueArticleFrame frame = new HistoriqueArticleFrame(ReferenceArticleSQLElement.this);
frame.selectId(IListe.get(e).getSelectedId());
frame.setVisible(true);
}
}, false, true);
history.setPredicate(IListeEvent.getSingleSelectionPredicate());
getRowActions().add(history);
 
PredicateRowAction clone = new PredicateRowAction(new AbstractAction("Dupliquer") {
 
@Override
112,6 → 138,7
 
PredicateRowAction actionAttachment = new PredicateRowAction(new AttachmentAction().getAction(), true);
actionAttachment.setPredicate(IListeEvent.getSingleSelectionPredicate());
 
getRowActions().add(actionAttachment);
}
 
192,7 → 219,10
l.add("ID_FAMILLE_ARTICLE");
l.add("ID_FOURNISSEUR");
l.add("SKU");
 
// if (!prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_MULTI_DEPOT, false)) {
l.add("ID_STOCK");
// }
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean b = Boolean.valueOf(val);
if (b != null && b.booleanValue()) {
208,7 → 238,7
if (prefs.getBoolean(GestionArticleGlobalPreferencePanel.SHOW_PRODUCT_BAR_CODE, false)) {
res.add(null, "CODE_BARRE");
}
res.addAll(null, "NOM", "ID_FAMILLE_ARTICLE");
res.addAll(null, "CODE", "NOM", "ID_FAMILLE_ARTICLE");
return res;
}
 
384,6 → 414,7
SQLRowValues vals = new SQLRowValues(row);
BigDecimal taux = BigDecimal.ONE.add(new BigDecimal(TaxeCache.getCache().getTauxFromId(row.getForeignID("ID_TAXE")) / 100f));
vals.put("PV_TTC", vals.getBigDecimal("PV_HT").multiply(taux));
vals.put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID);
int idArticle;
try {
 
494,8 → 525,70
&& rowVals1.getString("VALEUR_METRIQUE_2").equals(rowVals2.getString("VALEUR_METRIQUE_2")) && rowVals1.getString("VALEUR_METRIQUE_3").equals(rowVals2.getString("VALEUR_METRIQUE_3")));
}
 
public void initStock(int id) {
SQLRow row = getTable().getRow(id);
SQLSelect sel = new SQLSelect();
sel.addSelectStar(getTable().getTable("DEPOT_STOCK"));
List<SQLRow> rowsDepot = SQLRowListRSH.execute(sel);
 
SQLSelect selStock = new SQLSelect();
selStock.addSelectStar(getTable().getTable("STOCK"));
selStock.setWhere(new Where(getTable().getTable("STOCK").getField("ID_ARTICLE"), "=", id));
List<SQLRow> rowsStock = SQLRowListRSH.execute(selStock);
Map<Integer, SQLRow> initedDepot = new HashMap<>();
for (SQLRow sqlRow : rowsStock) {
initedDepot.put(sqlRow.getForeignID("ID_DEPOT_STOCK"), sqlRow);
}
 
List<StockItem> stockItems = new ArrayList<StockItem>();
for (SQLRow sqlRow : rowsDepot) {
try {
if (!initedDepot.keySet().contains(sqlRow.getID())) {
SQLRowValues rowVals = new SQLRowValues(getTable().getTable("STOCK"));
rowVals.put("ID_ARTICLE", row.getID());
rowVals.put("ID_DEPOT_STOCK", sqlRow.getID());
 
SQLRow rowStock = rowVals.commit();
if ((row.getObject("ID_DEPOT_STOCK") == null || row.isForeignEmpty("ID_DEPOT_STOCK")) && sqlRow.getID() == DepotStockSQLElement.DEFAULT_ID) {
row.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID).commit();
} else if (sqlRow.getID() == row.getForeignID("ID_DEPOT_STOCK")) {
row.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();
}
stockItems.add(new StockItem(row, rowStock));
 
} else {
SQLRow rowExisting = initedDepot.get(sqlRow.getID());
if ((row.getObject("ID_DEPOT_STOCK") == null || row.isForeignEmpty("ID_DEPOT_STOCK")) && sqlRow.getID() == DepotStockSQLElement.DEFAULT_ID) {
row.createEmptyUpdateRow().put("ID_STOCK", rowExisting.getID()).put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID).commit();
} else if (sqlRow.getID() == row.getForeignID("ID_DEPOT_STOCK")) {
row.createEmptyUpdateRow().put("ID_STOCK", rowExisting.getID()).commit();
}
stockItems.add(new StockItem(row, rowExisting));
}
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'initialisation du stock de l'article", e);
}
}
if (row.getReferentRows(getTable().getTable("ARTICLE_ELEMENT").getField("ID_ARTICLE_PARENT")).size() > 0) {
ComposedItemStockUpdater up = new ComposedItemStockUpdater(getTable().getDBRoot(), stockItems);
try {
up.updateNomenclature(stockItems);
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'actualisation du stock!", e);
}
}
}
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".ref";
return createCodeOfPackage() + ".ref";
}
 
@Override
protected void _initComboRequest(ComboSQLRequest req) {
super._initComboRequest(req);
req.addToGraphToFetch("ID_DEPOT_STOCK");
// req.addForeignToGraphToFetch("ID_DEPOT_STOCK", Arrays.asList("ID"));
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ArticleCatComptableSQLElement.java
Nouveau fichier
0,0 → 1,92
/*
* 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.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JLabel;
import javax.swing.SwingConstants;
 
public class ArticleCatComptableSQLElement extends ComptaSQLConfElement {
 
public ArticleCatComptableSQLElement() {
super("ARTICLE_CATEGORIE_COMPTABLE", "une liaison article catégorie comptable", "liaisons article catégorie comptable");
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_ARTICLE");
l.add("ID_CATEGORIE_COMPTABLE");
l.add("ID_COMPTE_PCE_VENTE");
l.add("ID_COMPTE_PCE_ACHAT");
l.add("ID_TAXE");
return l;
}
 
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_ARTICLE");
l.add("ID_CATEGORIE_COMPTABLE");
return l;
}
 
@Override
protected String getParentFFName() {
return "ID_ARTICLE";
}
 
/*
* (non-Javadoc)
*
* @see org.openconcerto.devis.SQLElement#getComponent()
*/
public SQLComponent createComponent() {
return new BaseSQLComponent(this) {
public void addViews() {
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
 
// Famille père
final JLabel labelLangue = new JLabel(getLabelFor("ID_ARTICLE"), SwingConstants.RIGHT);
c.gridx = 0;
c.gridy++;
c.weightx = 0;
this.add(labelLangue, c);
 
final ElementComboBox artBox = new ElementComboBox(true, 25);
DefaultGridBagConstraints.lockMinimumSize(artBox);
c.gridx++;
c.weightx = 1;
this.add(artBox, c);
 
this.addSQLObject(artBox, "ID_ARTICLE");
}
 
};
}
 
@Override
protected String createCode() {
return createCodeOfPackage() + ".compta";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/EcoContributionSQLElement.java
13,11 → 13,11
package org.openconcerto.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.ListMap;
 
29,12 → 29,17
import javax.swing.JLabel;
import javax.swing.JTextField;
 
public class EcoContributionSQLElement extends ConfSQLElement {
public class EcoContributionSQLElement extends ComptaSQLConfElement {
 
public EcoContributionSQLElement() {
super("ECO_CONTRIBUTION");
public EcoContributionSQLElement(final DBRoot root) {
super(root.getTable("ECO_CONTRIBUTION"));
}
 
@Override
protected String createCode() {
return this.createCodeOfPackage() + ".ewaste-tax";
}
 
protected List<String> getListFields() {
final List<String> list = new ArrayList<String>(2);
list.add("ID_FAMILLE_ECO_CONTRIBUTION");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/CoutRevientSQLElement.java
Nouveau fichier
0,0 → 1,104
/*
* 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.erp.core.sales.product.element;
 
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.ListMap;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JLabel;
import javax.swing.JTextField;
 
public class CoutRevientSQLElement extends ComptaSQLConfElement {
 
public CoutRevientSQLElement() {
super("COUT_REVIENT");
}
 
protected List<String> getListFields() {
final List<String> list = new ArrayList<String>(2);
list.add("CODE");
list.add("NOM");
list.add("POURCENT");
return list;
}
 
protected List<String> getComboFields() {
final List<String> list = new ArrayList<String>(2);
list.add("CODE");
list.add("NOM");
list.add("POURCENT");
return list;
}
 
@Override
public ListMap<String, String> getShowAs() {
return ListMap.singleton(null, "CODE");
 
}
 
public SQLComponent createComponent() {
return new BaseSQLComponent(this) {
 
public void addViews() {
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new DefaultGridBagConstraints();
 
// Code
final JLabel labelCode = new JLabel(getLabelFor("CODE"));
c.weightx = 0;
this.add(labelCode, c);
c.gridx++;
c.weightx = 1;
final JTextField textCode = new JTextField();
this.add(textCode, c);
 
// Nom
c.gridx++;
c.weightx = 0;
final JLabel labelNom = new JLabel(getLabelFor("NOM"));
this.add(labelNom, c);
c.gridx++;
c.weightx = 1;
final JTextField textNom = new JTextField();
this.add(textNom, c);
 
// Famille
c.gridy++;
c.gridx = 0;
c.weightx = 0;
 
final JLabel labelTaux = new JLabel(getLabelFor("POURCENT"));
this.add(labelTaux, c);
c.gridx++;
c.weightx = 1;
final JTextField textTaux = new JTextField();
this.add(textTaux, c);
 
this.addRequiredSQLObject(textTaux, "POURCENT");
this.addRequiredSQLObject(textNom, "NOM");
this.addRequiredSQLObject(textCode, "CODE");
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ArticleDesignationSQLElement.java
99,6 → 99,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".name";
return createCodeOfPackage() + ".name";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ArticleTarifSQLElement.java
72,6 → 72,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".price";
return createCodeOfPackage() + ".price";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ArticleCodeClientSQLElement.java
77,7 → 77,7
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".customcode";
return createCodeOfPackage() + ".customcode";
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/FamilleArticleSQLElement.java
201,6 → 201,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".family";
return createCodeOfPackage() + ".family";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/io/BarcodeReader.java
24,7 → 24,10
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
 
51,11 → 54,23
// non final car un TimerTask n'est pas reutilisable
private TimerTask task;
private boolean enable = true;
private boolean debug = false;
Map<Integer, String> mapCharacterFR = new HashMap<>();
 
public BarcodeReader(int maxInterKeyDelay) {
this.timer = null;
this.task = null;
this.maxInterKeyDelay = maxInterKeyDelay;
mapCharacterFR.put((int) '&', "1");
mapCharacterFR.put((int) 'é', "2");
mapCharacterFR.put((int) '"', "3");
mapCharacterFR.put((int) '\'', "4");
mapCharacterFR.put((int) '(', "5");
mapCharacterFR.put((int) '-', "6");
mapCharacterFR.put((int) 'è', "7");
mapCharacterFR.put((int) '_', "8");
mapCharacterFR.put((int) 'ç', "9");
mapCharacterFR.put((int) 'à', "0");
}
 
public synchronized void removeBarcodeListener(BarcodeListener l) {
115,35 → 130,61
if (this.firstTime < 0) {
this.firstTime = t;
}
int key = e.getKeyCode();
int keyCode = e.getKeyCode();
 
final long delay = t - this.firstTime;
if (key == KeyEvent.VK_BACK_SPACE || key == KeyEvent.VK_DELETE || (delay > maxInterKeyDelay && key != KeyEvent.VK_SHIFT)) {
if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE || (delay > maxInterKeyDelay && keyCode != KeyEvent.VK_SHIFT)) {
// touche normale
if (this.debug) {
System.err.println("TOuche normale " + keyCode);
}
this.eve.add(e);
redispatch();
return true;
}
 
final char key2 = e.getKeyChar();
final char keyChar = e.getKeyChar();
this.eve.add(e);
if (e.getID() == KeyEvent.KEY_RELEASED) {
if (key == KeyEvent.VK_SHIFT) {
if (keyCode == KeyEvent.VK_SHIFT) {
// rien
} else if (key2 == '*' || key2 == '$' || key2 == '+' || key2 == '/' || key2 == '%' || key2 == '-' | key2 == ' ') {
this.value += key2;
} else if (Character.isLetter(key2) || Character.isDigit(key2)) {
this.value += key2;
} else if (key >= KeyEvent.VK_0 && key <= KeyEvent.VK_9 || key >= KeyEvent.VK_A && key <= KeyEvent.VK_Z) {
if (this.debug) {
System.err.println("SHIFT " + keyCode);
}
} else if (keyChar == '*' || keyChar == '$' || keyChar == '+' || keyChar == '/' || keyChar == '%' || keyChar == ' ') {
this.value += keyChar;
if (this.debug) {
System.err.println("KEY " + keyCode + " - " + keyChar);
}
} else if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9 || keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z) {
// from KeyEvent : same as ASCII
this.value += (char) key;
} else if (key == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
if (this.debug) {
System.err.println("[0-9] [A-Z] " + keyCode);
}
this.value += (char) keyCode;
} else if (keyCode == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
// fin de code barre
if (this.debug) {
System.err.println("BARCODE OK ENTER OR LENGHT " + keyCode + " length = " + this.value.length() + " min length =" + MIN_BARCODE_LENGTH);
}
this.value = this.value.trim();
fire(this.value);
reset();
} else if (mapCharacterFR.containsKey((int) keyChar)) {
if (this.debug) {
System.err.println("MAP DEFAULT FR CHAR " + keyChar + " WITH " + mapCharacterFR.get((int) keyChar));
}
this.value += mapCharacterFR.get((int) keyChar);
} else if (Character.isLetter(keyChar) || Character.isDigit(keyChar)) {
this.value += keyChar;
if (this.debug) {
System.err.println("LETTER OR DIGIT " + keyChar);
}
} else {
// Caractere non code barre
if (this.debug) {
System.err.println("CHAR NON CODE BARRE " + e);
}
redispatch();
}
// lance un timer s'il reste des evenements non dispatchés
189,6 → 230,14
this.firstTime = -1;
}
 
public Map<Integer, String> getMapCharacterFR() {
return mapCharacterFR;
}
 
public void setDebug(boolean debug) {
this.debug = debug;
}
 
public static void main(String[] args) {
String delay = "80";
if (args.length > 0) {
223,6 → 272,13
panel.add(new JScrollPane(t1), c);
 
BarcodeReader reader = new BarcodeReader(d);
reader.setDebug(true);
 
System.err.println("FR MAP");
for (Entry<Integer, String> string : reader.getMapCharacterFR().entrySet()) {
System.err.println(string.getKey() + " --> " + string.getValue());
}
 
reader.addBarcodeListener(new BarcodeListener() {
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/POSConfiguration.java
79,6 → 79,7
 
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
117,14 → 118,27
private String LCDLine1 = "Bienvenue";
private String LCDLine2 = "ILM Informatique";
 
public static synchronized POSConfiguration getInstance() {
public static POSConfiguration createInstance() throws JDOMException, IOException {
POSConfiguration res = new POSConfiguration(getConfigFile(new File(".")));
res.loadConfiguration();
return res;
}
 
@Deprecated
public static synchronized POSConfiguration setInstance() throws JDOMException, IOException {
if (instance == null) {
instance = new POSConfiguration(getConfigFile(new File(".")));
instance.loadConfiguration();
instance = createInstance();
} else {
throw new IllegalStateException("already set");
}
return instance;
}
 
@Deprecated
public static synchronized POSConfiguration getInstance() {
return instance;
}
 
private POSConfiguration(final File confFile) {
this.confFile = confFile;
ticketPrinterConf1 = new TicketPrinterConfiguration();
341,8 → 355,10
if (idClient <= 0) {
idClient = defaultIDClient;
}
TotalCalculator calc = new TotalCalculator("T_PA_HT", "T_PV_HT", null);
 
// TODO fusionner TotalCalculator avec Ticket.GetTotalCalcutor
TotalCalculator calc = new TotalCalculator("T_PA_HT", "T_PV_HT", null, null);
 
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean bServiceActive = Boolean.valueOf(val);
calc.setServiceActive(bServiceActive != null && bServiceActive);
395,6 → 411,9
rowValsElt.put("ID_CLIENT", idClient);
 
long montant = Long.valueOf(paiement.getMontantInCents());
// Check si montant especes > especes données alors montant especes =
// montant donné - montant rendu
// TODO gérer ce cas si paiement multiple
if (ticket.getPaiements().size() == 1 && paiement.getType() == Paiement.ESPECES) {
montant = longValueTotal;
}
497,7 → 516,7
public String getLabel(SQLRowAccessor rowOrigin, SQLRowAccessor rowElt) {
return "Ticket N°" + rowOrigin.getString("NUMERO");
}
}, row, row.getReferentRows(getClientCaisse().getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT")), TypeStockUpdate.REAL_DELIVER);
}, row, row.getReferentRows(getClientCaisse().getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT")), TypeStockUpdate.REAL_VIRTUAL_DELIVER);
stockUpdater.update();
}
 
529,7 → 548,7
this.footerLines = footerLines;
}
 
private void loadConfiguration() {
private void loadConfiguration() throws JDOMException, IOException {
if (!isConfigurationFileCreated()) {
System.err.println("POSConfiguration.loadConfigurationFromXML() configuration not loaded. " + getConfigFile().getAbsolutePath() + " missing.");
return;
538,67 → 557,62
final SAXBuilder builder = new SAXBuilder();
File file = getConfigFile();
 
try {
System.out.println("POSConfiguration.loadConfigurationFromXML() loading " + file.getAbsolutePath());
Document document = builder.build(file);
// config
final Element rootElement = document.getRootElement();
setUserID(Integer.valueOf(rootElement.getAttributeValue("userID", "2")));
setCompanyID(Integer.valueOf(rootElement.getAttributeValue("societeID", "42")));
setPosID(Integer.valueOf(rootElement.getAttributeValue("caisseID", "2")));
setScanDelay(Integer.valueOf(rootElement.getAttributeValue("scanDelay", "80")));
// screen
final List<Element> children = rootElement.getChildren("screen");
if (children != null) {
for (Element e : children) {
this.screenWidth = Integer.valueOf(e.getAttributeValue("width", "0"));
this.screenHeight = Integer.valueOf(e.getAttributeValue("height", "0"));
}
System.out.println("POSConfiguration.loadConfigurationFromXML() loading " + file.getAbsolutePath());
Document document = builder.build(file);
// config
final Element rootElement = document.getRootElement();
setUserID(Integer.valueOf(rootElement.getAttributeValue("userID", "2")));
setCompanyID(Integer.valueOf(rootElement.getAttributeValue("societeID", "42")));
setPosID(Integer.valueOf(rootElement.getAttributeValue("caisseID", "2")));
setScanDelay(Integer.valueOf(rootElement.getAttributeValue("scanDelay", "80")));
// screen
final List<Element> children = rootElement.getChildren("screen");
if (children != null) {
for (Element e : children) {
this.screenWidth = Integer.valueOf(e.getAttributeValue("width", "0"));
this.screenHeight = Integer.valueOf(e.getAttributeValue("height", "0"));
}
// credit card
final List<Element> childrenCreditCard = rootElement.getChildren("creditcard");
if (childrenCreditCard != null) {
for (Element e : childrenCreditCard) {
this.creditCardPort = e.getAttributeValue("port", "");
}
}
// credit card
final List<Element> childrenCreditCard = rootElement.getChildren("creditcard");
if (childrenCreditCard != null) {
for (Element e : childrenCreditCard) {
this.creditCardPort = e.getAttributeValue("port", "");
}
// lcd
final List<Element> childrenLCD = rootElement.getChildren("lcd");
if (childrenLCD != null) {
for (Element e : childrenLCD) {
this.LCDType = e.getAttributeValue("type", "serial");
this.LCDPort = e.getAttributeValue("port", "");
this.LCDLine1 = e.getAttributeValue("line1", "");
this.LCDLine2 = e.getAttributeValue("line2", "");
}
}
// lcd
final List<Element> childrenLCD = rootElement.getChildren("lcd");
if (childrenLCD != null) {
for (Element e : childrenLCD) {
this.LCDType = e.getAttributeValue("type", "serial");
this.LCDPort = e.getAttributeValue("port", "");
this.LCDLine1 = e.getAttributeValue("line1", "");
this.LCDLine2 = e.getAttributeValue("line2", "");
}
}
 
// header
final List<Element> headers = rootElement.getChildren("header");
if (headers != null) {
for (Element header : headers) {
this.headerLines.add(new TicketLine(header.getValue(), header.getAttributeValue("style")));
}
// header
final List<Element> headers = rootElement.getChildren("header");
if (headers != null) {
for (Element header : headers) {
this.headerLines.add(new TicketLine(header.getValue(), header.getAttributeValue("style")));
}
// footer
final List<Element> footers = rootElement.getChildren("footer");
if (footers != null) {
for (Element header : footers) {
this.footerLines.add(new TicketLine(header.getValue(), header.getAttributeValue("style")));
}
}
// footer
final List<Element> footers = rootElement.getChildren("footer");
if (footers != null) {
for (Element header : footers) {
this.footerLines.add(new TicketLine(header.getValue(), header.getAttributeValue("style")));
}
// ticket printers
final List<Element> printers = rootElement.getChildren("ticketPrinter");
if (printers.size() > 0) {
configureTicketPrinter(this.ticketPrinterConf1, printers.get(0));
}
if (printers.size() > 1) {
configureTicketPrinter(this.ticketPrinterConf2, printers.get(1));
}
} catch (Exception e) {
e.printStackTrace();
}
 
// ticket printers
final List<Element> printers = rootElement.getChildren("ticketPrinter");
if (printers.size() > 0) {
configureTicketPrinter(this.ticketPrinterConf1, printers.get(0));
}
if (printers.size() > 1) {
configureTicketPrinter(this.ticketPrinterConf2, printers.get(1));
}
}
 
private void configureTicketPrinter(TicketPrinterConfiguration conf, Element element) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/element/CaisseJournalSQLElement.java
48,6 → 48,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".log";
return createCodeOfPackage() + ".log";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/element/CaisseTicketSQLElement.java
30,7 → 30,7
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("NUMERO");
l.add("NOM");
return l;
37,7 → 37,7
}
 
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("NUMERO");
l.add("NOM");
return l;
45,7 → 45,7
 
@Override
public ListMap<String, String> getShowAs() {
final ListMap<String, String> res = new ListMap<String, String>();
final ListMap<String, String> res = new ListMap<>();
res.putCollection(null, "NUMERO", "NOM");
return res;
 
64,4 → 64,10
}
};
}
 
@Override
protected String createCodeSuffix() {
return ".receipt";
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/element/TicketCaisseSQLElement.java
77,6 → 77,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".ticket";
return createCodeOfPackage() + ".ticket";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/element/SaisieVenteComptoirSQLElement.java
806,6 → 806,7
rowVals.put("IDSOURCE", id);
rowVals.put("SOURCE", getTable().getName());
rowVals.put("ID_ARTICLE", rowVC.getInt("ID_ARTICLE"));
rowVals.put("ID_STOCK", rowVC.getForeign("ID_ARTICLE").getForeignID("ID_STOCK"));
rowVals.put("DATE", rowVC.getObject("DATE"));
 
try {
957,6 → 958,7
rowVals.put("IDSOURCE", getSelectedID());
rowVals.put("SOURCE", getTable().getName());
rowVals.put("ID_ARTICLE", row.getInt("ID_ARTICLE"));
rowVals.put("ID_STOCK", row.getForeign("ID_ARTICLE").getForeignID("ID_STOCK"));
rowVals.put("DATE", row.getObject("DATE"));
try {
SQLRow rowNew = rowVals.insert();
1030,6 → 1032,6
 
@Override
protected String createCode() {
return createCodeFromPackage() + ".sale";
return createCodeOfPackage() + ".sale";
}
}