OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 173 → Rev 174

/trunk/OpenConcerto/.classpath
16,7 → 16,6
<classpathentry exported="true" kind="lib" path="lib/ognl-2.6.5.jar"/>
<classpathentry exported="true" kind="lib" path="lib/resolver.jar"/>
<classpathentry exported="true" kind="lib" path="lib/RXTXcomm.jar"/>
<classpathentry exported="true" kind="lib" path="lib/poi-3.8-beta3-20110606.jar"/>
<classpathentry kind="lib" path="lib/jcip-annotations.jar"/>
<classpathentry kind="lib" path="lib/fb-annotations-2.0.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-dbcp-1.4.jar"/>
44,5 → 43,6
<classpathentry kind="lib" path="lib/mysql-connector-java-5.1.40-bin.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="lib/postgresql-42.2.2.jre7.jar"/>
<classpathentry kind="lib" path="lib/poi-3.17.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
/trunk/OpenConcerto/lib/jOpenCalendar.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/jOpenDocument-1.4rc2.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/jopendocument/link/OOConnexion.java
84,8 → 84,14
perms.add(new RuntimePermission("modifyThread"));
// needed by PrinterJob.getPrinterJob()
perms.add(new RuntimePermission("queuePrintJob"));
 
// ProcessBuilder.start() calls SecurityManager.checkExec() which requires
// absolute path (or execute on "<<ALL FILES>>")
 
// needed by OOConnexion.init() to find the port
perms.add(new FilePermission("/usr/bin/lsof", "execute"));
// macOS path
perms.add(new FilePermission("/usr/sbin/lsof", "execute"));
perms.add(new FilePermission("/bin/ps", "execute"));
perms.add(new FilePermission("C:/Windows/System32/tasklist.exe", "execute"));
perms.add(new RuntimePermission("getenv.*"));
/trunk/OpenConcerto/src/org/jopendocument/link/OOInstallation.java
102,10 → 102,14
rootPaths.addAll(Arrays.asList(loRootPaths));
rootPaths.addAll(Arrays.asList(ooRootPaths));
}
 
for (final String p : rootPaths) {
if (DesktopEnvironment.test("reg", "query", p))
// On force à chercher dans le registre 64 bits sinon il va chercher dans le registre 32
// bits si os 64b et VM 32b
if (DesktopEnvironment.test("reg", "query", p, "/reg:64"))
return p;
}
 
return null;
}
 
123,7 → 127,8
// all string values for the passed registry path
private static Map<String, String> getStringValues(final String path, final String option) throws IOException {
final Map<String, String> values = new HashMap<String, String>();
final String out = DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(new String[] { "reg", "query", path, option }));
// On force /reg:64 (utile si on utilise une VM 32 avec un systeme 64 bits)
final String out = DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(new String[] { "reg", "query", path, option, "/reg:64" }));
final Matcher matcher = stringValuePattern.matcher(out);
while (matcher.find()) {
values.put(matcher.group(1), matcher.group(2));
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_fr.xml
2,21 → 2,23
<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" />
<FIELD name="NOM" label="Nom" />
<FIELD name="PRENOM" label="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" />
<FIELD name="PASSWORD_CONFIRM" label="Confirmation" />
<FIELD name="LOGIN" label="Identifiant" titlelabel="Identifiant" />
<FIELD name="SURNOM" label="Surnom" titlelabel="Surnom" />
<FIELD name="LOGIN" label="Identifiant" />
<FIELD name="SURNOM" label="Surnom" />
<FIELD name="ADMIN" label="Administrateur" titlelabel="Admin." />
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" titlelabel="Droits utilisateur" />
<FIELD name="ID_USER_RIGHT_COMMON" label="Droits utilisateur" />
<FIELD name="MAIL" label="E-Mail" titlelabel="E-Mail" />
<FIELD name="COMPTE_NUMERO" label="N° compte comptable" />
<FIELD name="DISABLED" label="Compte désactivé" />
<FIELD name="TEL" label="Téléphone" titlelabel="Téléphone" />
<FIELD name="TEL" label="Téléphone" />
<FIELD name="COLOR" label="Couleur" />
</element>
<element refid="sql.right">
<name base="droit" nounClass="masculine" />
<FIELD name="CODE" label="Code" titlelabel="Code" />
<FIELD name="CODE" label="Code" />
<FIELD name="NOM" label="Nom" titlelabel="Nom du droit" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</element>
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
202,10 → 202,55
* @return the corresponding SQLElement, or <code>null</code> if none can be found.
* @throws IllegalArgumentException if there's more than one match.
*/
public synchronized final <S extends SQLElement> S getElement(Class<S> clazz) {
return clazz.cast(this.getElement(getSoleTable(this.byClass, clazz)));
public final <S extends SQLElement> S getElement(Class<S> clazz) {
return this.getElementOfClass(clazz, false);
}
 
public final <S extends SQLElement> S getElementOfClass(Class<S> clazz, final boolean allowSubclass) {
final List<S> res = getElementsOfClass(clazz, allowSubclass);
if (res.size() > 1)
throw new IllegalArgumentException(clazz + " is not unique: " + res);
return res.isEmpty() ? null : res.get(0);
}
 
/**
* Search for SQLElement whose class is <code>clazz</code>.
*
* @param clazz the class.
* @param allowSubclass <code>true</code> to include {@link Class#isInstance(Object)
* subclasses}, <code>false</code> to only return exact match.
* @return the corresponding elements.
*/
public final <S extends SQLElement> List<S> getElementsOfClass(final Class<S> clazz, final boolean allowSubclass) {
final List<S> res;
synchronized (this) {
if (allowSubclass) {
res = new ArrayList<>();
for (final SQLElement elem : this.elements.values()) {
if (clazz.isInstance(elem))
res.add(clazz.cast(elem));
}
} else {
final Set<SQLTable> tables = this.byClass.get(clazz);
if (tables != null) {
res = new ArrayList<>(tables.size());
for (final SQLTable t : tables) {
res.add(clazz.cast(this.getElement(t)));
}
} else {
res = Collections.emptyList();
}
}
}
if (res.isEmpty()) {
return Collections.emptyList();
} else if (res.size() == 1) {
return Collections.singletonList(res.get(0));
} else {
return Collections.unmodifiableList(res);
}
}
 
public synchronized final SQLElement getElementForCode(String code) {
return this.getElement(getSoleTable(this.byCode, code));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java
64,8 → 64,8
 
private final Group group;
private final int columns = 2;
private final Map<String, JComponent> labels = new HashMap<String, JComponent>();
private final Map<String, JComponent> editors = new HashMap<String, JComponent>();
private final Map<String, JComponent> labels = new HashMap<>();
private final Map<String, JComponent> editors = new HashMap<>();
private String startTabAfter = null;
private boolean tabGroup;
private int tabDepth;
80,6 → 80,12
 
public GroupSQLComponent(final SQLElement element, final Group group) {
super(element);
if (element == null) {
throw new IllegalArgumentException("null SQLElement");
}
if (group == null) {
throw new IllegalArgumentException("null group (SQLElement : " + element + ")");
}
this.group = group;
this.hasAdditionnalFields = this.getElement().getAdditionalFields().size() > 0;
this.additionnalFieldsGroup = getAdditionalFieldsGroup(group.getDescendantGroups());
99,7 → 105,7
}
 
public void startTabGroupAfter(String id) {
startTabAfter = id;
this.startTabAfter = id;
}
 
@Override
155,7 → 161,8
c.gridx = 0;
c.weightx = 1;
c.gridwidth = 4;
panel.add(getLabel(id), c);
JComponent comp = getLabel(id);
panel.add(comp, c);
c.gridy++;
}
}
276,13 → 283,13
}
 
}
if (id.equals(startTabAfter)) {
if (tabGroup) {
if (id.equals(this.startTabAfter)) {
if (this.tabGroup) {
throw new IllegalArgumentException("ID " + id + " already set as tab");
}
tabGroup = true;
tabDepth = level;
pane = new JTabbedPane();
this.tabGroup = true;
this.tabDepth = level;
this.pane = new JTabbedPane();
c.gridx = 0;
c.gridy++;
c.weightx = 1;
289,7 → 296,7
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 4;
panel.add(pane, c);
panel.add(this.pane, c);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
57,10 → 57,10
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.ui.light.CustomRowEditor;
import org.openconcerto.sql.ui.light.GroupToLightUIConvertor;
import org.openconcerto.sql.ui.light.LightEditFrame;
import org.openconcerto.sql.ui.light.LightUIPanelFiller;
import org.openconcerto.sql.ui.light.SavableCustomEditorProvider;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
74,7 → 74,6
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.light.ComboValueConvertor;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.IntValueConvertor;
import org.openconcerto.ui.light.LightUIComboBox;
import org.openconcerto.ui.light.LightUIElement;
337,10 → 336,10
editFrame.createTitlePanel(this.getCreationFrameTitle());
} else if (editMode.equals(EditMode.MODIFICATION)) {
editFrame.createTitlePanel(this.getModificationFrameTitle(sqlRow));
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, sqlRow);
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, this, sqlRow, sessionSecurityToken);
} else if (editMode.equals(EditMode.READONLY)) {
editFrame.createTitlePanel(this.getReadOnlyFrameTitle(sqlRow));
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, sqlRow);
new LightUIPanelFiller(editFrame.getContentPanel()).fillFromRow(configuration, this, sqlRow, sessionSecurityToken);
}
 
this.setEditFrameModifiers(editFrame, sessionSecurityToken);
389,11 → 388,12
*/
public GroupToLightUIConvertor getGroupToLightUIConvertor(final PropsConfiguration configuration, final EditMode editMode, final SQLRowAccessor sqlRow, final String token) {
final GroupToLightUIConvertor convertor = new GroupToLightUIConvertor(configuration);
if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForCreation(configuration, token));
} else {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForModification(configuration, sqlRow, token));
}
// if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomRowEditors(configuration, token));
// } else {
// convertor.putAllCustomEditorProvider(this.getCustomRowEditors(configuration, sqlRow,
// token));
// }
return convertor;
}
 
418,76 → 418,55
public void setEditFrameModifiers(final LightEditFrame frame, final String sessionToken) {
}
 
public final Map<String, CustomEditorProvider> getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) {
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, null, sessionToken);
map.putAll(this._getCustomEditorProviderForCreation(configuration, sessionToken));
return map;
}
 
public final Map<String, CustomEditorProvider> getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken);
map.putAll(this._getCustomEditorProviderForModification(configuration, sqlRow, sessionToken));
return map;
}
 
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
protected Map<String, CustomEditorProvider> _getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
return new HashMap<String, CustomEditorProvider>();
}
 
private final Map<String, CustomEditorProvider> getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) {
public List<CustomRowEditor> getCustomRowEditors(final Configuration configuration, final String sessionToken) {
final Map<String, ComboValueConvertor<?>> comboConvertors = this.getComboConvertors();
final Map<String, CustomEditorProvider> result = new HashMap<String, CustomEditorProvider>();
final List<CustomRowEditor> result = new ArrayList<>();
for (final Entry<String, ComboValueConvertor<?>> entry : comboConvertors.entrySet()) {
result.put(entry.getKey(), new SavableCustomEditorProvider() {
 
final String itemId = entry.getKey();
result.add(new CustomRowEditor(itemId) {
final ComboValueConvertor<?> convertor = entry.getValue();
 
@Override
public LightUIElement createUIElement(final String elementId) {
final LightUIComboBox uiCombo = new LightUIComboBox(elementId);
public LightUIElement createUIElement() {
final LightUIComboBox uiCombo = new LightUIComboBox(getItemId());
this.convertor.fillCombo(uiCombo, null);
return uiCombo;
}
 
if (sqlRow == null) {
this.convertor.fillCombo(uiCombo, null);
} else {
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(elementId);
@Override
public void fillFrom(LightUIElement uiElement, SQLRowAccessor sqlRow) {
final LightUIComboBox uiCombo = (LightUIComboBox) uiElement;
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(getItemId());
if (this.convertor instanceof StringValueConvertor) {
((StringValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getString(field.getFieldName()));
} else if (this.convertor instanceof IntValueConvertor) {
if (sqlRow.getObject(field.getFieldName()) == null) {
this.convertor.fillCombo(uiCombo, null);
} else {
if (sqlRow.getObject(field.getFieldName()) != null) {
((IntValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getInt(field.getFieldName()));
}
}
 
}
return uiCombo;
}
 
@Override
protected void _save(final SQLRowValues sqlRow, final SQLField sqlField, final LightUIElement uiElement) {
final LightUIComboBox combo = (LightUIComboBox) uiElement;
if (combo.hasSelectedValue()) {
public void store(LightUIElement uiElement, SQLRowValues sqlRow) {
final LightUIComboBox combobox = (LightUIComboBox) uiElement;
final String fieldName = configuration.getFieldMapper().getSQLFieldForItem(getItemId()).getName();
if (combobox.hasSelectedValue()) {
if (this.convertor instanceof StringValueConvertor) {
sqlRow.put(sqlField.getName(), ((StringValueConvertor) this.convertor).getIdFromIndex(combo.getSelectedValue().getId()));
sqlRow.put(fieldName, ((StringValueConvertor) this.convertor).getIdFromIndex(combobox.getSelectedValue().getId()));
} else if (this.convertor instanceof IntValueConvertor) {
sqlRow.put(sqlField.getName(), combo.getSelectedValue().getId());
sqlRow.put(fieldName, combobox.getSelectedValue().getId());
} else {
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui element id: " + uiElement.getId());
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui id: " + getItemId());
}
} else {
sqlRow.put(sqlField.getName(), null);
sqlRow.put(fieldName, null);
}
 
}
});
}
result.putAll(this._getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken));
return result;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
434,7 → 434,13
if (!(this instanceof GroupSQLComponent)) {
 
for (final Entry<String, JComponent> e : this.getElement().getAdditionalFields().entrySet()) {
final SpecParser spec = new SpecParser(null, true);
final SpecParser spec;
// FIXME Required à spécifier directement depuis le module
if (this.requiredNames != null && this.requiredNames.contains(e.getKey())) {
spec = new SpecParser(REQ, true);
} else {
spec = new SpecParser(null, true);
}
final JComponent comp = e.getValue();
if (comp == null)
// infer component
726,7 → 732,6
return this.getRequest().setLastKnownDBVals(current, this.getRequest().fetchRow(current.getID(), ls));
}
 
 
@Override
public final void select(int id) {
// TODO in an executor outside of the EDT
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/SQLUtils.java
372,9 → 372,8
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute, afterHandle;
final Statement stmt = conn.createStatement();
int count = 0;
try {
try (final Statement stmt = conn.createStatement()){
if (Thread.currentThread().isInterrupted())
throw new RTInterruptedException("Interrupted before executing : " + query);
stmt.execute(query);
392,8 → 391,6
stmt.getMoreResults();
}
afterHandle = System.nanoTime();
} finally {
stmt.close();
}
SQLRequestLog.log(query, "executeMultiple", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), count);
return null;
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
1006,7 → 1006,7
}
 
// TODO support java.time.LocalDateTime in Java 8
static private <T, U> U convert(final Class<T> source, final Object value, final Class<U> dest) {
public static <T, U> U convert(final Class<T> source, final Object value, final Class<U> dest) {
final ValueConvertor<T, U> conv = ValueConvertorFactory.find(source, dest);
if (conv == null)
throw new IllegalArgumentException("No convertor to " + dest + " from " + source);
2447,7 → 2447,6
return insert(t, sql, ReturnMode.NO_FIELDS).getCount();
}
 
// if scalar is null primary keys aren't fetched
private static final Insertion<?> insert(final SQLTable t, final String sql, final ReturnMode mode) throws SQLException {
return new Inserter(t).insert(sql, mode, true);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCacheItem.java
28,6 → 28,11
public SQLBackgroundTableCacheItem(final SQLTable t, final int second) {
this.table = t;
this.timeout = second;
 
if (second == -1) {
reloadFromDB();
}
 
this.table.addTableModifiedListener(new SQLTableModifiedListener() {
 
@Override
44,16 → 49,20
this.enableReloadIfTableModified = enableReloadIfTableModified;
}
 
@SuppressWarnings("unchecked")
public synchronized void reloadFromDbIfNeeded() {
final long delta = System.currentTimeMillis() - this.lastReload;
if (delta / 1000 > this.timeout) {
if (this.timeout >= 0 && delta / 1000 > this.timeout) {
reloadFromDB();
}
}
 
@SuppressWarnings("unchecked")
private void reloadFromDB() {
final SQLSelect sel = new SQLSelect();
sel.addSelectStar(this.table);
this.rows = Collections.unmodifiableList((List<SQLRow>) this.table.getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, this.table)));
this.lastReload = System.currentTimeMillis();
}
}
 
public synchronized SQLRow getFirstRowContains(final int value, final SQLField field) {
for (SQLRow r : this.rows) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBackgroundTableCache.java
19,7 → 19,7
 
public class SQLBackgroundTableCache {
private static SQLBackgroundTableCache instance;
private Map<SQLTable, SQLBackgroundTableCacheItem> list = new HashMap<SQLTable, SQLBackgroundTableCacheItem>();
private Map<SQLTable, SQLBackgroundTableCacheItem> list = new HashMap<>();
 
/**
* @param args
90,7 → 90,8
item.reloadFromDbIfNeeded();
} else {
System.err.println("SQLBackgroundTableCache.getCacheForTable() WARNING " + t.getName() + " is not registered (use add to register)");
this.add(t, 0);
// Start cache without autorefresh for Caisse offline
this.add(t, -1);
item = this.list.get(t);
item.reloadFromDbIfNeeded();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLUpdate.java
New file
0,0 → 1,115
/*
* 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.model;
 
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
public class SQLUpdate {
private List<SQLField> fields = new ArrayList<>();
private List<Object> values = new ArrayList<>();
private SQLTable table;
private Where where;
 
public SQLUpdate(Where where) {
this.where = where;
}
 
public void add(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
this.fields.add(field);
this.values.add(value);
}
 
public void set(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
this.values.set(index, value);
}
 
public boolean contains(SQLField field) {
return this.fields.indexOf(field) >= 0;
}
 
public Object getValue(SQLField field) {
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
return this.values.get(index);
}
 
public String asString() {
if (this.fields.isEmpty()) {
throw new IllegalStateException("not fields added");
}
final StringBuilder builder = new StringBuilder();
builder.append("UPDATE ");
builder.append(this.table.getSQLName());
builder.append(" SET ");
//
int stop = this.fields.size();
for (int i = 0; i < stop; i++) {
final SQLField field = this.fields.get(i);
builder.append(field.getQuotedName());
builder.append("=");
 
Object value = this.values.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
builder.append(field.getType().toString(str));
if (i < stop - 1) {
builder.append(',');
}
}
builder.append(" WHERE ");
builder.append(this.where.getClause());
return builder.toString();
}
 
/**
* Update multiple rows with a batch. Rows can be from different tables.
*
* Speed : 5000 /s
*/
public static long executeMultipleWithBatch(final DBSystemRoot sysRoot, final List<SQLUpdate> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no updates");
}
final List<String> l = new ArrayList<>(queries.size());
for (final SQLUpdate i : queries)
l.add(i.asString());
return sysRoot.getDataSource().executeBatch(l, true).get0();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
122,7 → 122,7
};
 
@SuppressWarnings("unchecked")
private static final Map<String, Number> getUndefIDs(final SQLSchema schema) {
public static final Map<String, Number> getUndefIDs(final SQLSchema schema) {
if (!UNDEFINED_IDs.containsKey(schema)) {
final Map<String, Number> r;
if (schema.contains(undefTable)) {
556,7 → 556,10
return undef.intValue();
}
} else if ("inDB".equals(policy)) {
throw new IllegalStateException("Not in " + new SQLName(this.getDBRoot().getName(), undefTable) + " : " + this.getName());
return SQLRow.NONEXISTANT_ID;
// FIXME : BUG A INVESTIGUER DANS LA CREATION DE MODULE throw new
// throw new IllegalStateException("Not in " + new SQLName(this.getDBRoot().getName(),
// undefTable) + " : " + this.getName());
} else if (policy != null && !"nonexistant".equals(policy)) {
final int res = Integer.parseInt(policy);
if (res < SQLRow.MIN_VALID_ID)
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLDataSource.java
16,11 → 16,13
import org.openconcerto.sql.Log;
import org.openconcerto.sql.State;
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.ThreadFactory;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICacheSupport;
 
48,6 → 50,8
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
 
import org.apache.commons.dbcp.AbandonedConfig;
993,7 → 997,66
return res;
}
 
private static final Tuple2<Long, int[]> NO_QUERIES_RES = Tuple2.create(0l, new int[0]);
 
/**
* Execute multiple queries in batch.
*
* @param queries what to execute.
* @param atomic <code>true</code> if all queries should be executed in a transaction.
* @return the total update count (&lt; 0 if unknown), followed by the individual update counts.
* @throws SQLException if an error occurs.
* @see Statement#executeBatch()
*/
public final Tuple2<Long, int[]> executeBatch(final List<String> queries, final boolean atomic) throws SQLException {
if (queries.isEmpty())
return NO_QUERIES_RES;
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
final AtomicLong afterQueryInfo = new AtomicLong();
final AtomicLong afterExecute = new AtomicLong();
final AtomicReference<Connection> conn = new AtomicReference<>();
final ConnectionHandlerNoSetup<int[], SQLException> handler = new ConnectionHandlerNoSetup<int[], SQLException>() {
@Override
public int[] handle(SQLDataSource ds) throws SQLException {
afterQueryInfo.set(System.nanoTime());
conn.set(ds.getConnection());
final int[] res;
try (final Statement stmt = conn.get().createStatement()) {
for (final String s : queries) {
stmt.addBatch(s);
}
if (Thread.currentThread().isInterrupted())
throw new RTInterruptedException("Interrupted before executing : " + queries);
res = stmt.executeBatch();
}
afterExecute.set(System.nanoTime());
return res;
}
};
final int[] res = atomic ? SQLUtils.executeAtomic(this, handler) : this.useConnection(handler);
long totalCount = 0;
int i = 0;
for (final int count : res) {
if (count == Statement.SUCCESS_NO_INFO) {
totalCount = -1;
break;
} else {
if (count < 0)
throw new SQLException("Invalid count (" + count + ") for query " + i + " : " + queries.get(i));
totalCount += count;
}
i++;
}
if (SQLRequestLog.isEnabled()) {
final long afterHandle = System.nanoTime();
SQLRequestLog.log(queries.toString(), "executeBatch", conn.get(), timeMs, time, afterCache, afterQueryInfo.get(), afterExecute.get(), afterHandle, afterHandle, (int) totalCount);
}
return Tuple2.create(totalCount, res);
}
 
/**
* Try to execute a {@link #getValidationQuery() simple query} on the database server. This
* method even works when the pool is exhausted.
*
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowListRSH.java
19,10 → 19,12
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
 
import org.apache.commons.dbutils.ResultSetHandler;
 
37,16 → 39,18
// ATTN doesn't check that the types of columns are coherent with the types of the fields
public RSH(final SQLTable t, final List<String> names) {
this(Tuple2.create(t, names));
if (!t.getFieldsName().containsAll(names))
throw new IllegalArgumentException("Not all names are fields of " + t + " : " + names);
// null are OK (they're ignored)
final List<String> unknown = names.stream().filter(n -> n != null && !t.getFieldsName().contains(n)).collect(Collectors.toList());
if (!unknown.isEmpty())
throw new IllegalArgumentException("Not all names are fields of " + t + " : " + unknown);
}
 
private RSH(Tuple2<SQLTable, List<String>> names) {
private RSH(final Tuple2<SQLTable, List<String>> names) {
this.names = names;
}
 
@Override
public List<SQLRow> handle(ResultSet rs) throws SQLException {
public List<SQLRow> handle(final ResultSet rs) throws SQLException {
// since the result will be cached, disallow its modification (e.g.avoid
// ConcurrentModificationException)
return Collections.unmodifiableList(SQLRow.createListFromRS(this.names.get0(), rs, this.names.get1()));
58,7 → 62,7
}
 
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
78,7 → 82,7
return t;
}
 
static Tuple2<SQLTable, List<String>> getIndexes(SQLSelect sel, final TableRef passedTable, final boolean findTable) {
static Tuple2<SQLTable, List<String>> getIndexes(final SQLSelect sel, final TableRef passedTable, final boolean findTable) {
final List<FieldRef> selectFields = sel.getSelectFields();
final int size = selectFields.size();
if (size == 0)
124,6 → 128,7
* @return a handler creating a list of {@link SQLRow}.
* @deprecated use {@link SQLSelectHandlerBuilder}
*/
@Deprecated
static public ResultSetHandler createFromSelect(final SQLSelect sel) {
return create(getIndexes(sel, null, true));
}
137,6 → 142,7
* @return a handler creating a list of {@link SQLRow}.
* @deprecated use {@link SQLSelectHandlerBuilder}
*/
@Deprecated
static public ResultSetHandler createFromSelect(final SQLSelect sel, final TableRef t) {
return create(getIndexes(sel, t, false));
}
145,6 → 151,20
return new RSH(names);
}
 
static public List<SQLRow> fetch(final SQLTable t, final Collection<? extends Number> ids) throws IllegalArgumentException {
return fetch(t, ids, null);
}
 
static public List<SQLRow> fetch(final SQLTable t, final Collection<? extends Number> ids, final Collection<String> fields) throws IllegalArgumentException {
final SQLSelect sel = new SQLSelect();
if (fields == null)
sel.addSelectStar(t);
else
sel.addAllSelect(t, fields);
sel.setWhere(new Where(t.getKey(), ids));
return execute(sel);
}
 
/**
* Execute the passed select and return rows. NOTE if there's more than one table in the query
* {@link #execute(SQLSelect, TableRef)} must be used.
195,17 → 215,18
private final SQLTable t;
private final boolean tableOnly;
 
public SQLRowListRSH(SQLTable t) {
public SQLRowListRSH(final SQLTable t) {
this(t, false);
}
 
public SQLRowListRSH(SQLTable t, final boolean tableOnly) {
public SQLRowListRSH(final SQLTable t, final boolean tableOnly) {
super();
this.t = t;
this.tableOnly = tableOnly;
}
 
public Object handle(ResultSet rs) throws SQLException {
@Override
public List<SQLRow> handle(final ResultSet rs) throws SQLException {
return SQLRow.createListFromRS(this.t, rs, this.tableOnly);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRequestLog.java
25,6 → 25,7
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.DateFormat;
60,7 → 61,23
private static final String ACTIVER_LA_CAPTURE = "Enable monitoring";
private static final String DESACTIVER_LA_CAPTURE = "Disable monitoring";
private static Vector<SQLRequestLog> list = new Vector<SQLRequestLog>(500);
@GuardedBy("this")
private static boolean enabled;
 
public static synchronized void setEnabled(boolean enable) {
enabled = enable;
}
 
public static synchronized boolean toggleEnabled() {
final boolean newVal = !isEnabled();
setEnabled(newVal);
return newVal;
}
 
public static synchronized boolean isEnabled() {
return enabled;
}
 
private String query;
private String comment;
private long startAsMs;
85,10 → 102,6
return l == 0 ? "" : dformat.format(l / 1000000D) + " ms";
}
 
public static void setEnabled(boolean enable) {
enabled = enable;
}
 
public SQLRequestLog(String query, String comment, int connectionId, long starAtMs, String ex, boolean inSwing, long startTime, long afterCache, long afterQueryInfo, long afterExecute,
long afterHandle, long endTime, int count) {
this.query = query;
116,7 → 129,7
public static void log(String query, String comment, int connectionId, long starAtMs, long startTime, long afterCache, long afterQueryInfo, long afterExecute, long afterHandle, long endTime,
int count) {
 
if (enabled) {
if (isEnabled()) {
if (list.size() < 50000) {
final String ex = ExceptionUtils.getStackTrace(new Exception());
 
135,7 → 148,7
 
public static void log(PreparedStatement pStmt, String comment, long timeMs, long startTime, long afterCache, long afterQueryInfo, long afterExecute, long afterHandle, long endTime) {
// only call potentially expensive and/or exceptions throwing methods if necessary
if (enabled) {
if (isEnabled()) {
try {
log(pStmt.toString(), comment, pStmt.getConnection(), timeMs, startTime, afterCache, afterQueryInfo, afterExecute, afterHandle, endTime, 0);
} catch (Exception e) {
433,7 → 446,7
JPanel bar = new JPanel(new FlowLayout());
 
final JButton b0 = new JButton();
if (enabled) {
if (isEnabled()) {
b0.setText(DESACTIVER_LA_CAPTURE);
} else {
b0.setText(ACTIVER_LA_CAPTURE);
441,11 → 454,9
b0.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (enabled) {
enabled = false;
if (!toggleEnabled()) {
b0.setText(ACTIVER_LA_CAPTURE);
} else {
enabled = true;
b0.setText(DESACTIVER_LA_CAPTURE);
}
 
620,4 → 631,15
model.fireTableRowsUpdated(0, model.getRowCount() - 1);
}
}
 
public static void dump(PrintStream out) {
final DecimalFormat dformat = new DecimalFormat("##0.00");
for (SQLRequestLog log : list) {
out.print(dformat.format(log.getDurationTotalNano() / 1000000D) + " ms ");
out.print("\t");
out.print(log.getQuery());
out.println();
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInsert.java
New file
0,0 → 1,314
/*
* 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.model;
 
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
 
import org.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;
import org.postgresql.jdbc.PgConnection;
 
public class SQLInsert {
private List<SQLField> fields = new ArrayList<>();
private List<Object> values = new ArrayList<>();
private SQLTable table;
 
public void add(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
this.fields.add(field);
this.values.add(value);
}
 
public void set(SQLField field, Object value) {
if (this.table == null) {
this.table = field.getTable();
} else {
if (!this.table.equals(field.getTable())) {
throw new IllegalArgumentException(field + " is not in table " + this.table.toString());
}
}
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
this.values.set(index, value);
}
 
public boolean contains(SQLField field) {
return this.fields.indexOf(field) >= 0;
}
 
public Object getValue(SQLField field) {
int index = this.fields.indexOf(field);
if (index < 0) {
throw new IllegalArgumentException(field + " not in field list");
}
return this.values.get(index);
}
 
public String asString() {
if (this.fields.isEmpty()) {
throw new IllegalStateException("not fields added");
}
final StringBuilder builder = new StringBuilder();
builder.append("INSERT INTO ");
builder.append(this.table.getSQLName());
builder.append(" (");
//
int stop = this.fields.size();
for (int i = 0; i < stop; i++) {
builder.append(this.fields.get(i).getQuotedName());
if (i < stop - 1) {
builder.append(',');
}
}
 
builder.append(") VALUES (");
 
for (int i = 0; i < stop; i++) {
Object value = this.values.get(i);
final SQLField field = this.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (value != null && !javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
builder.append(field.getType().toString(str));
 
if (i < stop - 1) {
builder.append(',');
}
}
 
builder.append(")");
return builder.toString();
}
 
/**
* Insert multiple rows. Rows can be from different tables.
*
* Speed : 19 000 inserts /s on PostgreSQL
*/
public static void executeMultiple(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
final Map<SQLTable, List<SQLInsert>> map = new HashMap<>();
for (final SQLInsert q : queries) {
List<SQLInsert> list = map.get(q.table);
if (list == null) {
list = new ArrayList<>();
map.put(q.table, list);
}
list.add(q);
}
for (Entry<SQLTable, List<SQLInsert>> entry : map.entrySet()) {
executeSimilarInserts(sysRoot, entry.getValue(), false);
}
}
 
/**
* Insert multiple rows with a batch. Rows can be from different tables.
*
* Speed : 8 000 inserts /s on PostgreSQL
*/
public static long executeMultipleWithBatch(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
final List<String> l = new ArrayList<>(queries.size());
for (final SQLInsert i : queries)
l.add(i.asString());
return sysRoot.getDataSource().executeBatch(l, true).get0();
}
 
/**
* Insert multiple rows in the same table, using COPY on PostgreSQL for the maximum speed
*
* Speed : 26 000 inserts /s on PostgreSQL
*/
public static long executeSimilarWithCopy(final DBSystemRoot sysRoot, final List<SQLInsert> queries) throws SQLException {
SQLDataSource dataSource = sysRoot.getDataSource();
if (dataSource.getSystem() != SQLSystem.POSTGRESQL) {
return executeSimilarInserts(sysRoot, queries, true).size();
}
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
SQLInsert insert0 = queries.get(0);
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
 
final String query = insert0 + "..." + queries.size() + " queries";
 
return dataSource.useConnection(new ConnectionHandlerNoSetup<Long, SQLException>() {
@Override
public Long handle(SQLDataSource ds) throws SQLException {
final Connection conn = ds.getConnection().unwrap(PgConnection.class);
final CopyManager copyManager = new CopyManager((BaseConnection) conn);
final StringBuilder allValues = new StringBuilder(insert0.fields.size() * 10 * queries.size());
final List<String> fi = new ArrayList<>();
for (SQLField f : insert0.fields) {
fi.add(f.getQuotedName());
}
for (final SQLInsert q : queries) {
if (!q.table.equals(insert0.table)) {
throw new IllegalArgumentException("table " + q.table.getName() + " is not " + insert0.table.getTable());
}
if (!q.fields.equals(insert0.fields)) {
throw new IllegalArgumentException("fields" + q.fields + " not equals to " + insert0.fields);
}
int stop = q.values.size();
for (int i = 0; i < stop; i++) {
Object value = q.values.get(i);
final SQLField field = q.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
// FIXME null, escapes (see SQLSyntaxPG)
allValues.append(field.getType().toString(str));
if (i < stop - 1) {
allValues.append('\t');
}
}
allValues.append('\n');
}
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute;
final long afterHandle;
final long count;
try {
count = copyManager.copyIn("COPY " + insert0.table.getSQLName() + "(" + String.join(",", fi) + ") FROM STDIN WITH (ENCODING 'UTF-8') ", new StringReader(allValues.toString()));
} catch (IOException e) {
throw new SQLException(e);
}
afterExecute = System.nanoTime();
afterHandle = afterExecute;
SQLRequestLog.log(query, "multiple similar with copy", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), queries.size());
 
return count;
}
});
}
 
/**
* Insert multiple rows in the same table
*
* Speed : 20 000 inserts /s on PostgreSQL
*/
public static List<Number> executeSimilarInserts(final DBSystemRoot sysRoot, final List<SQLInsert> queries, boolean returnIds) throws SQLException {
SQLDataSource dataSource = sysRoot.getDataSource();
 
if (queries.isEmpty()) {
throw new IllegalArgumentException("no inserts");
}
SQLInsert insert0 = queries.get(0);
final long timeMs = System.currentTimeMillis();
final long time = System.nanoTime();
final long afterCache = time;
 
final String query = insert0 + "..." + queries.size() + " queries";
if (sysRoot.getServer().getSQLSystem() != SQLSystem.POSTGRESQL) {
List<Number> res = new ArrayList<>();
for (SQLInsert sqlInsert : queries) {
res.add((Number) sysRoot.getDataSource().executeScalar(sqlInsert.asString()));
}
return res;
} else {
return dataSource.useConnection(new ConnectionHandlerNoSetup<List<Number>, SQLException>() {
@Override
public List<Number> handle(SQLDataSource ds) throws SQLException {
final Connection conn = ds.getConnection();
final List<String> fi = new ArrayList<>();
for (SQLField f : insert0.fields) {
fi.add(f.getQuotedName());
}
 
final long afterQueryInfo = System.nanoTime();
final long afterExecute;
final long afterHandle;
final StringBuilder sql = new StringBuilder(insert0.fields.size() * 10 * (queries.size() + 1));
sql.append("(" + String.join(",", fi) + ")");
sql.append(" VALUES ");
int size = queries.size();
for (int j = 0; j < size; j++) {
final SQLInsert q = queries.get(j);
if (!q.table.equals(insert0.table)) {
throw new IllegalArgumentException("table " + q.table.getName() + " is not " + insert0.table.getTable());
}
if (!q.fields.equals(insert0.fields)) {
throw new IllegalArgumentException("fields" + q.fields + " not equals to " + insert0.fields);
}
sql.append("(");
int stop = q.values.size();
for (int i = 0; i < stop; i++) {
Object value = q.values.get(i);
final SQLField field = q.fields.get(i);
final Class<?> javaType = field.getType().getJavaType();
Object str = value;
if (!field.isNullable() && value == null) {
throw new IllegalStateException("null value for " + field);
}
if (value != null && !javaType.isInstance(value)) {
str = SQLRowValues.convert(value.getClass(), value, javaType);
}
// FIXME : escape ' (quote)
sql.append(field.getType().toString(str));
 
if (i < stop - 1) {
sql.append(',');
}
}
sql.append(")");
if (j < size - 1) {
sql.append(',');
}
}
List<Number> res;
if (!returnIds) {
// TODO return count
SQLRowValues.insertCount(insert0.table, sql.toString());
res = null;
} else {
res = SQLRowValues.insertIDs(insert0.table, sql.toString());
}
afterExecute = System.nanoTime();
afterHandle = afterExecute;
SQLRequestLog.log(query, "multiple similar insert", conn, timeMs, time, afterCache, afterQueryInfo, afterExecute, afterHandle, System.nanoTime(), queries.size());
 
return res;
}
});
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInjector.java
166,18 → 166,28
rowVals.put(field.getName(), value);
}
 
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, String from, String to) {
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField, String from, String to) {
 
String label = rowVals.getString(to);
SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
 
if (prefs.getBoolean("TransfertRef", true) || !to.equals("NOM")) {
if (label != null && label.trim().length() > 0) {
rowVals.put(to, label + ", " + srcRow.getString(from));
} else {
rowVals.put(to, srcRow.getString(from));
}
} else if (prefs.getBoolean("TransfertMultiRef", false)) {
SQLRowValues rowValsHeader = new SQLRowValues(UndefinedRowValuesCache.getInstance().getDefaultRowValues(tableElementDestination));
// TODO taxe may be undefined set it to default
rowValsHeader.put("NOM", srcRow.getString(from));
rowValsHeader.put(refField, rowVals);
}
 
}
 
protected void transfertNumberReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField) {
SQLPreferences prefs = new SQLPreferences(srcRow.getTable().getDBRoot());
SQLPreferences prefs = SQLPreferences.getMemCached(srcRow.getTable().getDBRoot());
 
if (prefs.getBoolean("TransfertRef", true)) {
String label = rowVals.getString("NOM");
412,7 → 422,7
* register manually a transfer, use with caution
*
* @throws SQLException
* */
*/
public void addTransfert(int idFrom, int idTo) throws SQLException {
final SQLTable tableTransfert = getSource().getTable(getTableTranferName());
final SQLRowValues rowTransfer = new SQLRowValues(tableTransfert);
/trunk/OpenConcerto/src/org/openconcerto/sql/users/User.java
15,6 → 15,8
 
import org.openconcerto.sql.model.SQLRowAccessor;
 
import java.awt.Color;
 
import net.jcip.annotations.Immutable;
 
@Immutable
22,6 → 24,7
private final int id;
private final String name, firstName, nickName;
private final Boolean active;
private final Color color;
 
public User(final SQLRowAccessor r) {
this.id = r.getID();
33,7 → 36,12
} else {
this.active = null;
}
if (r.contains("COLOR")) {
this.color = new Color(r.getInt("COLOR"));
} else {
this.color = null;
}
}
 
public String getName() {
return this.name;
63,4 → 71,8
public boolean isActive() {
return this.active;
}
 
public Color getColor() {
return this.color;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/SQLTableRightEditor.java
13,6 → 13,7
package org.openconcerto.sql.users.rights;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
27,7 → 28,6
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
 
import javax.swing.JComponent;
import javax.swing.JTextField;
41,15 → 41,12
 
@Override
public JComponent getRightEditor(final String right, final DBRoot root, final SQLElementDirectory directory, final JTextField fieldObject) {
final ISearchableCombo<SQLTableComboItem> comboMenu = new ISearchableCombo<SQLTableComboItem>();
DefaultIMutableListModel<SQLTableComboItem> comboItems = new DefaultIMutableListModel<SQLTableComboItem>();
Set<SQLTable> set = root.getTables();
 
List<SQLTableComboItem> result = new ArrayList<SQLTableComboItem>(set.size());
final ISearchableCombo<SQLTableComboItem> comboMenu = new ISearchableCombo<>();
final DefaultIMutableListModel<SQLTableComboItem> comboItems = new DefaultIMutableListModel<>();
final List<SQLTableComboItem> result = new ArrayList<>();
result.add(SQLTableComboItem.createFromTable(null));
for (SQLTable table : set) {
final SQLElement elt = directory.getElement(table);
result.add(SQLTableComboItem.create(table, elt));
for (SQLElement elt : directory.getElements()) {
result.add(SQLTableComboItem.create(elt.getTable(), elt));
}
comboItems.addAll(result);
comboMenu.initCache(comboItems);
57,7 → 54,7
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
final SQLTableComboItem selectedItem = (SQLTableComboItem) comboMenu.getSelectedItem();
final SQLTableComboItem selectedItem = comboMenu.getSelectedItem();
if (selectedItem != null) {
fieldObject.setText(selectedItem.getValue());
}
72,22 → 69,28
RightEditorManager.getInstance().register(code, editor);
}
 
static public class SQLTableComboItem {
public static class SQLTableComboItem {
 
static public SQLTableComboItem create(final SQLTable t, final SQLElement elt) {
public static SQLTableComboItem create(final SQLTable t, final SQLElement elt) {
assert elt == null || elt.getTable() == t;
return elt != null ? createFromElement(elt) : createFromTable(t);
}
 
static public SQLTableComboItem createFromElement(final SQLElement elt) {
return new SQLTableComboItem(elt.getTable(), elt.getName().getVariant(Grammar.SINGULAR));
public static SQLTableComboItem createFromElement(final SQLElement elt) {
String variant = elt.getName().getVariant(Grammar.SINGULAR);
if (variant.contains("_")) {
// quick patch for not translated tables
Log.get().warning(elt.getName() + " not translated");
variant = variant.replace('_', ' ').toLowerCase();
}
return new SQLTableComboItem(elt.getTable(), variant);
}
 
static public SQLTableComboItem createFromTable(final SQLTable t) {
return new SQLTableComboItem(t, t == null ? TM.tr("rights.allTables") : t.getName());
public static SQLTableComboItem createFromTable(final SQLTable t) {
return new SQLTableComboItem(t, t == null ? TM.tr("rights.allTables") : t.getName().toLowerCase().replace('_', ' '));
}
 
static public SQLTableComboItem createFromString(final String s, final DBRoot r, final SQLElementDirectory dir) {
public static SQLTableComboItem createFromString(final String s, final DBRoot r, final SQLElementDirectory dir) {
if (s == null)
return createFromTable(null);
final SQLName n = SQLName.parse(s);
96,7 → 99,7
final SQLTable t = r.findTable(n.getName());
if (t == null)
// allow to use unknown table (e.g. not yet created)
return new SQLTableComboItem(s, n.getName());
return new SQLTableComboItem(s, n.getName().toLowerCase().replace('_', ' '));
else
return create(t, dir.getElement(t));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/TableAllRights.java
31,9 → 31,11
public static final String ADD_ROW_TABLE = "INSERT_ROW";
public static final String VIEW_ROW_TABLE = "SELECT_ROW";
public static final String SAVE_ROW_TABLE = "SAVE_ROW";
public static final String USER_UI_LOCK_ROW = "LIST_UI_LOCK_ROWS";
public static final String USER_UI_UNLOCK_ROW = "LIST_UI_UNLOCK_ROWS";
 
public static final List<String> getCodes() {
return Arrays.asList(CODE, CODE_MODIF, DELETE_ROW_TABLE, MODIFY_ROW_TABLE, ADD_ROW_TABLE, VIEW_ROW_TABLE, SAVE_ROW_TABLE);
return Arrays.asList(CODE, CODE_MODIF, DELETE_ROW_TABLE, MODIFY_ROW_TABLE, ADD_ROW_TABLE, VIEW_ROW_TABLE, SAVE_ROW_TABLE, USER_UI_UNLOCK_ROW, USER_UI_LOCK_ROW);
}
 
public static RightTuple createRight(final SQLTable t, final boolean b) {
119,6 → 121,8
res.add(new RightTuple(DELETE_ROW_TABLE, object, haveRight));
res.add(new RightTuple(MODIFY_ROW_TABLE, object, haveRight));
res.add(new RightTuple(ADD_ROW_TABLE, object, haveRight));
res.add(new RightTuple(USER_UI_LOCK_ROW, object, haveRight));
res.add(new RightTuple(USER_UI_UNLOCK_ROW, object, haveRight));
if (getCode() == CODE)
res.add(new RightTuple(VIEW_ROW_TABLE, object, haveRight));
return res;
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java
28,6 → 28,7
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.itemview.SimpleRowItemView;
import org.openconcerto.sql.ui.IColorChooser;
import org.openconcerto.sql.ui.Login;
import org.openconcerto.sql.view.QuickAssignPanel;
import org.openconcerto.sql.view.list.ITableModel;
220,8 → 221,7
// Login
c.gridx = 0;
c.insets = new Insets(2, 2, 1, 2);
final JLabel labelLogin = new JLabel(getLabelFor("LOGIN"));
labelLogin.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelLogin = new JLabel(getLabelFor("LOGIN"), SwingConstants.RIGHT);
this.add(labelLogin, c);
final JTextField textLogin = new JTextField();
c.gridx++;
242,8 → 242,7
c.gridx = 0;
c.weightx = 0;
c.insets = new Insets(2, 2, 1, 2);
final JLabel labelPass = new JLabel(getLabelFor("PASSWORD"));
labelPass.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelPass = new JLabel(getLabelFor("PASSWORD"), SwingConstants.RIGHT);
this.add(labelPass, c);
this.passField = new JPasswordField(15);
c.gridx++;
254,8 → 253,7
// Confirmation password
c.gridx++;
c.weightx = 0;
final JLabel labelConfirmationPass = new JLabel(getLabelFor("PASSWORD_CONFIRM"));
labelConfirmationPass.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelConfirmationPass = new JLabel(getLabelFor("PASSWORD_CONFIRM"), SwingConstants.RIGHT);
this.add(labelConfirmationPass, c);
this.passFieldConfirm = new JPasswordField(15);
c.gridx++;
267,8 → 265,7
c.gridx = 0;
c.gridy++;
c.weightx = 0;
final JLabel labelNom = new JLabel(getLabelFor("NOM"));
labelNom.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelNom = new JLabel(getLabelFor("NOM"), SwingConstants.RIGHT);
this.add(labelNom, c);
final JTextField textNom = new JTextField();
c.gridx++;
278,8 → 275,7
// Prenom
c.gridx++;
c.weightx = 0;
final JLabel labelPrenom = new JLabel(getLabelFor("PRENOM"));
labelPrenom.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelPrenom = new JLabel(getLabelFor("PRENOM"), SwingConstants.RIGHT);
this.add(labelPrenom, c);
final JTextField textPrenom = new JTextField();
c.gridx++;
290,8 → 286,7
c.gridx = 0;
c.gridy++;
c.weightx = 0;
final JLabel labelSurnom = new JLabel(getLabelFor("SURNOM"));
labelSurnom.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelSurnom = new JLabel(getLabelFor("SURNOM"), SwingConstants.RIGHT);
this.add(labelSurnom, c);
final JTextField textSurnom = new JTextField();
c.gridx++;
313,8 → 308,7
c.weightx = 0;
 
if (getTable().contains("MAIL")) {
final JLabel labelMail = new JLabel(getLabelFor("MAIL"));
labelMail.setHorizontalAlignment(SwingConstants.RIGHT);
final JLabel labelMail = new JLabel(getLabelFor("MAIL"), SwingConstants.RIGHT);
c.anchor = GridBagConstraints.NORTHWEST;
this.add(labelMail, c);
c.gridx++;
325,6 → 319,7
this.add(textMail, c);
this.addView(textMail, "MAIL");
}
 
if (getTable().contains("OUT")) {
c.gridx++;
final JCheckBox boxOut = new JCheckBox(getLabelFor("OUT"));
345,9 → 340,24
}
}
c.gridy++;
 
if (getTable().contains("COMPTE_NUMERO")) {
final JLabel labelMail = new JLabel(getLabelFor("COMPTE_NUMERO"));
labelMail.setHorizontalAlignment(SwingConstants.RIGHT);
c.anchor = GridBagConstraints.NORTHWEST;
this.add(labelMail, c);
c.gridx++;
final JTextField textMail = new JTextField();
c.gridwidth = 1;
c.weightx = 1;
c.gridy++;
this.add(textMail, c);
this.addView(textMail, "COMPTE_NUMERO");
}
 
if (getTable().contains("TEL")) {
c.gridx = 0;
final JLabel labelTel = new JLabel(getLabelFor("TEL"));
final JLabel labelTel = new JLabel(getLabelFor("TEL"), SwingConstants.RIGHT);
c.gridwidth = 1;
c.weightx = 0;
this.add(labelTel, c);
365,6 → 375,20
this.add(boxCalUser, c);
this.addView(boxCalUser, "CALENDAR_USER");
}
if (getTable().contains("COLOR")) {
c.gridy++;
c.gridx = 0;
final JLabel labelTel = new JLabel(getLabelFor("COLOR"), SwingConstants.RIGHT);
c.gridwidth = 1;
c.weightx = 0;
this.add(labelTel, c);
final IColorChooser colorChooser = new IColorChooser(getLabelFor("COLOR"));
c.gridx++;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
this.add(colorChooser, c);
this.addView(colorChooser, "COLOR");
}
 
final boolean gestionHoraire = false;
if (Configuration.getInstance().getAppName().startsWith("OpenConcerto") && gestionHoraire) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTextComboTableCellEditor.java
34,6 → 34,7
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;
import java.util.List;
 
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
56,7 → 57,7
private IListFrame listFrame = null;
 
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined) {
this(elt, addUndefined, false);
this(elt, addUndefined, false,null);
}
 
/**
66,6 → 67,16
* @param chooseInListe possibilité de choisir via une IListe
*/
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined, boolean chooseInListe) {
this(elt, addUndefined, chooseInListe, null);
}
 
/**
*
* @param elt Element à afficher dans la combo
* @param addUndefined ajout de l'indéfini
* @param chooseInListe possibilité de choisir via une IListe
*/
public SQLTextComboTableCellEditor(final SQLElement elt, final boolean addUndefined, boolean chooseInListe, List<String> fieldsInCombo) {
super();
 
this.addUndefined = addUndefined;
77,7 → 88,7
this.comboBox.setBorder(new LineBorder(Color.black));
this.comboBox.getPulseComponents().iterator().next().setBorder(null);
 
ComboSQLRequest c = elt.getComboRequest(true);
ComboSQLRequest c = fieldsInCombo == null || fieldsInCombo.isEmpty() ? elt.getComboRequest(true) : elt.createComboRequest(fieldsInCombo, null);
this.comboBox.uiInit(c);
 
if (chooseInListe) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableModel.java
20,6 → 20,7
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.SQLSyntax.ConstraintType;
import org.openconcerto.sql.model.SQLTable;
300,7 → 301,7
for (int i = 0; i < size; i++) {
final SQLRowValues r = rowsToCommmit.get(i);
r.put(r.getTable().getOrderField().getFieldName(), o.add(new BigDecimal(i + 1)));
final SQLRow row = r.commit();
final SQLRow row = r.getGraph().store(StoreMode.COMMIT).getStoredRow(r);
r.setID(row.getIDNumber());
}
} catch (SQLException e) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/KeyTableCellRenderer.java
20,6 → 20,7
import org.openconcerto.sql.model.SQLTableEvent;
import org.openconcerto.sql.model.SQLTableEvent.Mode;
import org.openconcerto.sql.model.SQLTableModifiedListener;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.IComboSelectionItem;
 
import java.awt.Component;
37,13 → 38,18
private Object toSelect;
private boolean isLoading = false;
private final SQLElement el;
private final List<String> fields;
private JTable t;
static private final Map<SQLElement, Map<Integer, IComboSelectionItem>> cacheMap = new HashMap<SQLElement, Map<Integer, IComboSelectionItem>>();
 
public KeyTableCellRenderer(final SQLElement el) {
this(el, null);
}
 
public KeyTableCellRenderer(final SQLElement el, final List<String> fields) {
super();
this.el = el;
 
this.fields = fields;
if (cacheMap.get(this.el) == null) {
loadCacheAsynchronous();
}
107,7 → 113,9
Configuration.getInstance().getNonInteractiveSQLExecutor().execute(new Runnable() {
public void run() {
 
List<IComboSelectionItem> items = KeyTableCellRenderer.this.el.getComboRequest().getComboItems();
final ComboSQLRequest comboRequest = KeyTableCellRenderer.this.fields == null || KeyTableCellRenderer.this.fields.isEmpty() ? KeyTableCellRenderer.this.el.getComboRequest()
: KeyTableCellRenderer.this.el.createComboRequest(KeyTableCellRenderer.this.fields, null);
List<IComboSelectionItem> items = comboRequest.getComboItems();
final Map<Integer, IComboSelectionItem> m = new HashMap<Integer, IComboSelectionItem>();
for (IComboSelectionItem comboSelectionItem : items) {
m.put(comboSelectionItem.getId(), comboSelectionItem);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
30,6 → 30,7
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.users.User;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.users.rights.TableAllRights;
import org.openconcerto.sql.view.FileTransfertHandler;
import org.openconcerto.sql.view.IListener;
import org.openconcerto.sql.view.list.IListeAction.ButtonsBuilder;
146,6 → 147,8
public final class IListe extends JPanel {
 
static private final class LockAction extends RowAction {
private final boolean lock;
 
public LockAction(final boolean lock) {
super(new AbstractAction(TM.tr(lock ? "ilist.lockRows" : "ilist.unlockRows")) {
@Override
167,12 → 170,13
t.fireTableModified(fireID.intValue(), update.getFieldsNames());
}
}, false, true);
this.lock = lock;
}
 
@Override
public boolean enabledFor(IListeEvent evt) {
// TODO use right
return evt.getSelectedRows().size() > 0;
boolean hasRight = TableAllRights.currentUserHasRight(this.lock ? TableAllRights.USER_UI_LOCK_ROW : TableAllRights.USER_UI_UNLOCK_ROW, evt.getTable());
return !evt.getSelectedRows().isEmpty() && hasRight;
}
}
 
1204,8 → 1208,7
try {
res.add(getRow(i, clazz));
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException(
"The selected row at " + i
throw new IllegalStateException("The selected row at " + i
+ " is not in the model : it has been changed before Swing could update the selection. E.g. the DB was changed on mousePressed and Swing updated the selection on mouseReleased.",
e);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_en.xml
12,7 → 12,8
<FIELD name="ID_USER_RIGHT_COMMON" label="User rights" />
<FIELD name="MAIL" label="E-Mail" />
<FIELD name="DISABLED" label="Account disabled" />
<FIELD name="TEL" label="Phone" titlelabel="Phone" />
<FIELD name="TEL" label="Phone" />
<FIELD name="COLOR" label="Color" />
</element>
<element refid="sql.right">
<name base="right" />
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/SavableCustomEditorProvider.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightForeignRowValuesTableOffline.java
16,11 → 16,12
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.SQLTableModelLinesSourceOffline;
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableContent;
import org.openconcerto.ui.light.UserSearch;
 
import java.util.concurrent.Future;
 
31,14 → 32,19
private SQLField foreignField;
private Number parentRowId;
 
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField, final Number parentRowId) {
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField) {
super(configuration, userId, id, model);
 
this.foreignField = foreignField;
this.parentRowId = parentRowId;
this.init();
}
 
public void setParentRowId(Number parentRowId) {
this.parentRowId = parentRowId;
// FIXME : d'apres Sylvain, on pourrait ne pas a utiliser le ITableMobel car on veut du
// synchrone
this.getModel().getReq().getReq().setWhere(new Where(this.foreignField, "=", parentRowId));
}
 
public LightForeignRowValuesTableOffline(final LightForeignRowValuesTableOffline table) {
super(table);
 
70,7 → 76,7
}
 
@Override
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) {
public void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset) {
// TODO: Implement search in offline table
this.getModel().fireTableRowsInserted(0, Integer.MAX_VALUE);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/GroupToLightUIConvertor.java
23,7 → 23,6
import org.openconcerto.ui.group.Group;
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;
43,6 → 42,7
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class GroupToLightUIConvertor {
49,7 → 49,7
private final int maxColumnCount;
private PropsConfiguration configuration;
private FieldMapper mapper;
private Map<String, CustomEditorProvider> customEditorProviders = new HashMap<String, CustomEditorProvider>();
private Map<String, CustomRowEditor> customRowEditors = new HashMap<>();
 
public GroupToLightUIConvertor(PropsConfiguration conf) {
this(conf, 4);
73,6 → 73,15
}
 
final SQLElement sqlElement = this.configuration.getDirectory().getElement(defaultRow.getTable());
if (sqlElement == null) {
throw new IllegalArgumentException("not SQLElement found for default row table : " + defaultRow.getTable().getName());
}
if (sqlElement.getGroupForCreation() == null) {
throw new IllegalArgumentException("no group for creation defined in " + sqlElement.getClass().getName());
}
if (sqlElement.getGroupForModification() == null) {
throw new IllegalArgumentException("no group for creation defined in " + sqlElement.getClass().getName());
}
if (!sqlElement.getGroupForCreation().equals(group) && sqlElement.getGroupForModification().equals(group)) {
throw new IllegalArgumentException("This group isn't attached to this SQLElement, group ID: " + group.getId() + " element code: " + sqlElement.getCode());
}
313,11 → 322,14
}
 
private LightUIElement getCustomEditor(final String id) {
final CustomEditorProvider customEditorProvider = this.customEditorProviders.get(id);
if (id == null) {
throw new IllegalArgumentException("null id");
}
final CustomRowEditor customEditorProvider = this.customRowEditors.get(id);
if (customEditorProvider != null) {
final LightUIElement element = customEditorProvider.createUIElement(id);
final LightUIElement element = customEditorProvider.createUIElement();
if (element.getId() == null) {
throw new IllegalStateException("Null id for custom editor for id: " + id);
throw new IllegalStateException("Null id for custom editor for id: " + id + " element : " + element);
}
return element;
}
324,11 → 336,12
return null;
}
 
public void putCustomEditorProvider(final String id, final CustomEditorProvider provider) {
this.customEditorProviders.put(id, provider);
public void putCustomEditorProvider(final CustomRowEditor e) {
this.customRowEditors.put(e.getItemId(), e);
}
 
public void putAllCustomEditorProvider(final Map<String, CustomEditorProvider> map) {
this.customEditorProviders.putAll(map);
public void putAllCustomEditorProvider(final List<CustomRowEditor> editors) {
for (CustomRowEditor e : editors)
this.customRowEditors.put(e.getItemId(), e);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTable.java
14,8 → 14,14
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.ListSQLLine;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
26,12 → 32,21
import org.openconcerto.ui.light.LightUIElement;
import org.openconcerto.ui.light.LightUITable;
import org.openconcerto.ui.light.Row;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableSearchParameter;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
 
import javax.swing.SwingUtilities;
55,8 → 70,10
 
private transient ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
private transient List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
private transient List<TableModelListener> tableModelListeners = new ArrayList<>();
 
private Map<TableSearchParameter, TableSearchMatcher> searchMap = new HashMap<>();
 
public LightRowValuesTable() {
// Serialization
}
72,6 → 89,74
if (model.getReq() instanceof SQLTableModelSourceOnline) {
final SQLTableModelSourceOnline source = (SQLTableModelSourceOnline) model.getReq();
this.orginTransformer = source.getReq().getSelectTransf();
 
List<SQLTableModelColumn> columns = model.getReq().getColumns();
// all
// TODO : traduire
TableSearchParameter tableSearchParameterAll = new TableSearchParameter("all", "Tous");
 
TableSearchMatcher m = new TableSearchMatcher() {
 
@Override
public boolean useMatch() {
return false;
}
 
@Override
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt) {
return true;
}
 
@Override
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt) {
final Set<FieldPath> fields = new HashSet<>();
for (SQLTableModelColumn col : columns) {
fields.addAll(col.getPaths());
}
final List<Where> wFields = new ArrayList<>(fields.size());
for (final FieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final FieldRef fieldRef = sel.followFieldPath(fpath);
if (type.getType().equals(UserSearchItem.TYPE_CONTAINS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", "%" + txt.toLowerCase() + "%");
wFields.add(w);
}
if (type.getType().equals(UserSearchItem.TYPE_STARTS_WITH)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase() + "%");
wFields.add(w);
}
if (type.getType().equals(UserSearchItem.TYPE_IS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase());
wFields.add(w);
}
}
}
return Where.or(wFields);
}
 
@Override
public List<FieldPath> getAdditionnalFieldsToFetch() {
return Collections.emptyList();
}
};
tableSearchParameterAll.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
tableSearchParameterAll.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));
 
this.addSearchParameter(tableSearchParameterAll, m);
 
//
for (int i = 0; i < columns.size(); i++) {
SQLTableModelColumn col = columns.get(i);
TableSearchParameter tableSearchParameter = new TableSearchParameter("col" + i, col.getName());
// FIXME : locale à recuperer depuis le user
// TODO : mettre d'autres TableSearchParameterType en fonction du type de la colonne
tableSearchParameter.add(TableSearchParameterType.getContainsStringInstance(Locale.FRENCH));
tableSearchParameter.add(TableSearchParameterType.getIsStringInstance(Locale.FRENCH));
 
TableSearchMatcher tableSearchMatcher = new TableSearchColumnMatcher(col);
this.addSearchParameter(tableSearchParameter, tableSearchMatcher);
}
 
} else {
this.orginTransformer = null;
}
108,9 → 193,15
 
public final void addTableModelListener(final TableModelListener tableModelListener) {
this.tableModelListeners.add(tableModelListener);
this.model.addTableModelListener(tableModelListener);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
LightRowValuesTable.this.model.addTableModelListener(tableModelListener);
}
});
 
}
 
public final void removeTableModelListener(final TableModelListener tableModelListener) {
this.tableModelListeners.remove(tableModelListener);
this.model.removeTableModelListener(tableModelListener);
270,8 → 361,26
}
 
// TODO: merge with OpenConcerto List search system
public abstract void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset);
public abstract void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset);
 
public void addSearchParameter(TableSearchParameter tableSearchParameter, TableSearchMatcher tableSearchMatcher) {
this.searchMap.put(tableSearchParameter, tableSearchMatcher);
this.getTableSpec().addSearchParameter(tableSearchParameter);
}
 
protected TableSearchMatcher getSearchMatcher(String colId, String searchType) {
for (TableSearchParameter p : this.searchMap.keySet()) {
if (p.getId().equals(colId)) {
for (TableSearchParameterType t : p.getTypes()) {
if (t.getType().equals(searchType)) {
return this.searchMap.get(p);
}
}
}
}
return null;
}
 
@Override
public Row getRowById(Number rowId) {
for (int i = 0; i < this.model.getRowCount(); i++) {
314,9 → 423,10
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
final List<TableModelListener> tableModelListeners = LightRowValuesTable.this.tableModelListeners;
for (int i = tableModelListeners.size() - 1; i > -1; i--) {
LightRowValuesTable.this.removeTableModelListener(tableModelListeners.get(i));
 
final List<TableModelListener> listeners = LightRowValuesTable.this.tableModelListeners;
for (int i = listeners.size() - 1; i > -1; i--) {
LightRowValuesTable.this.removeTableModelListener(listeners.get(i));
}
}
});
325,5 → 435,6
}
 
this.clearRows();
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java
41,6 → 41,8
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
 
145,19 → 147,18
 
final SQLElement sqlElement = configuration.getDirectory().getElement(this.sqlRow.getTable());
 
final Map<String, CustomEditorProvider> customEditors;
if (this.editMode.equals(EditMode.CREATION)) {
customEditors = sqlElement.getCustomEditorProviderForCreation(configuration, sessionSecurityToken);
} else {
customEditors = sqlElement.getCustomEditorProviderForModification(configuration, this.sqlRow, sessionSecurityToken);
final List<CustomRowEditor> customRowEditors = sqlElement.getCustomRowEditors(configuration, sessionSecurityToken);
 
final Map<String, CustomRowEditor> customEditors = new HashMap<>(customRowEditors.size());
for (CustomRowEditor e : customRowEditors) {
customEditors.put(e.getItemId(), e);
}
 
this.createRowValues(configuration, sqlElement, fieldMapper, this.group, customEditors);
this.setMetaData(userId);
}
 
final protected void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group,
final Map<String, CustomEditorProvider> customEditors) {
protected final void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group,
final Map<String, CustomRowEditor> customEditors) {
final int itemCount = group.getSize();
for (int i = 0; i < itemCount; i++) {
final Item item = group.getItem(i);
176,26 → 177,29
this.putValueFromUserControl(configuration, sqlElement, field, uiElement, customEditors);
}
} else {
final LightUIElement uiElement = this.findChildByID(item.getId(), LightUIElement.class);
if (uiElement == null) {
throw new IllegalArgumentException("Impossible to find UI Element with id: " + item.getId());
}
if (customEditors.containsKey(uiElement.getId())) {
final CustomRowEditor customEditor = customEditors.get(uiElement.getId());
customEditor.store(uiElement, this.sqlRow);
} else {
Log.get().warning("No field attached to " + item.getId());
}
}
}
}
}
 
protected final void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
final Map<String, CustomEditorProvider> customEditors) {
final Map<String, CustomRowEditor> 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);
useElementValue = false;
}
}
 
if (useElementValue) {
final CustomRowEditor customEditor = customEditors.get(uiElement.getId());
customEditor.store(uiElement, this.sqlRow);
} else {
final String fieldName = sqlField.getFieldName();
if (sqlField.isKey()) {
if (!(uiElement instanceof LightUIComboBox)) {
268,11 → 272,13
* @param row Element saved row
* @param customEditors List of custom editors used in element edit frame
*/
final public void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) {
@Deprecated
public final void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) {
this.saveReferentRows(configuration, this.group, parentSqlRow, customEditors, sessionSecurityToken);
}
 
final private void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors,
@Deprecated
private final void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors,
final String sessionSecurityToken) {
for (int i = 0; i < group.getSize(); i++) {
final Item item = group.getItem(i);
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/CustomRowEditor.java
New file
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.sql.ui.light;
 
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.ui.light.LightUIElement;
 
public abstract class CustomRowEditor {
private final String itemId;
 
public CustomRowEditor(String itemId) {
this.itemId = itemId;
}
 
public String getItemId() {
return this.itemId;
}
 
/**
* Create the UI element filled with the row
*
*/
public abstract LightUIElement createUIElement();
 
public abstract void fillFrom(final LightUIElement uiElement, final SQLRowAccessor row);
 
/**
* Store the values in the row from the UI element
*/
public abstract void store(final LightUIElement uiElement, final SQLRowValues row);
 
public void afterCommit(LightUIElement uiElement, SQLRow insertedRow) {
// nothing
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java
14,29 → 14,23
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.IFieldPath;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSource;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearch;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.utils.cc.ITransformer;
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
 
import javax.swing.SwingUtilities;
 
import net.minidev.json.JSONObject;
 
public class LightRowValuesTableOnline extends LightRowValuesTable {
48,7 → 42,6
 
public LightRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(configuration, userId, id, model);
 
this.orginTransformer = ((SQLTableModelSourceOnline) model.getReq()).getReq().getSelectTransf();
}
 
55,7 → 48,6
// Clone constructor
public LightRowValuesTableOnline(final LightRowValuesTableOnline tableElement) {
super(tableElement);
 
this.orginTransformer = tableElement.orginTransformer;
}
 
66,19 → 58,31
}
 
@Override
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) {
public void doSearch(final Configuration configuration, final UserSearch searchSpec, final int offset) {
 
this.getTableSpec().setSearch(searchSpec);
 
this.setOffset(offset);
 
final SQLTableModelSource tableSource = this.getModel().getReq();
final SearchInfo sInfo = (searchSpec != null) ? new SearchInfo(searchSpec) : null;
final ListSQLRequest req = tableSource.getReq();
final List<UserSearchItem> content = new ArrayList<>();
if (searchSpec != null) {
content.addAll(searchSpec.getContent());
 
final FutureTask<ListSQLRequest> f = new FutureTask<ListSQLRequest>(new Callable<ListSQLRequest>() {
@Override
public ListSQLRequest call() throws Exception {
final ListSQLRequest req = tableSource.getReq();
final List<SQLTableModelColumn> columns = tableSource.getColumns();
for (UserSearchItem item : content) {
// ex "col0"
String colId = item.getColumn();
// ex "contains"
String searchType = item.getType();
TableSearchMatcher m = LightRowValuesTableOnline.this.getSearchMatcher(colId, searchType);
if (m != null && m.getAdditionnalFieldsToFetch() != null) {
for (FieldPath p : m.getAdditionnalFieldsToFetch()) {
req.addToGraphToFetch(p.getPath(), Arrays.asList(p.getField().getFieldName()));
}
}
}
}
req.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(final SQLSelect sel) {
85,60 → 89,30
if (LightRowValuesTableOnline.this.orginTransformer != null) {
LightRowValuesTableOnline.this.orginTransformer.transformChecked(sel);
}
setWhere(sel, sInfo, columns);
return sel;
if (searchSpec != null) {
//
final List<Where> wheres = new ArrayList<>();
for (UserSearchItem item : content) {
// ex "col0"
String colId = item.getColumn();
// ex "hello"
String userText = item.getText();
// ex "contains"
String searchType = item.getType();
TableSearchMatcher m = LightRowValuesTableOnline.this.getSearchMatcher(colId, searchType);
if (m != null) {
final Where where = m.getWhere(sel, new TableSearchParameterType(searchType), userText);
if (where != null) {
wheres.add(where);
}
});
return req;
} else {
Log.get().warning("no TableSearchMatcher for " + item);
}
});
 
// TODO: clean swing
SwingUtilities.invokeLater(f);
 
try {
final ListSQLRequest req = f.get();
 
// get values
long t4 = System.currentTimeMillis();
final List<SQLRowValues> rowValues = req.getValues();
final int size = rowValues.size();
long t5 = System.currentTimeMillis();
 
System.err.println("DefaultTableContentHandler.handle() getValues() :" + size + " : " + (t5 - t4) + " ms");
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
 
/**
* Apply filter on ListSQLRequest
*
* @param sel - The ListSQLRequest select
* @param sInfo - Search parameters
*/
private final void setWhere(final SQLSelect sel, final SearchInfo sInfo, final List<SQLTableModelColumn> cols) {
if (sInfo != null) {
final Set<IFieldPath> fields = new HashSet<>(cols.size() * 2);
for (final SQLTableModelColumn sqlTableModelColumn : cols) {
fields.addAll(sqlTableModelColumn.getPaths());
}
final List<Where> wheres = new ArrayList<>();
final List<Where> wFields = new ArrayList<>();
 
final List<String> texts = sInfo.getTexts();
for (String string : texts) {
wFields.clear();
for (final IFieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, sel.followFieldPath(fpath)), "LIKE", "%" + string.toLowerCase() + "%");
wFields.add(w);
}
}
wheres.add(Where.or(wFields));
}
 
final Where w;
if (!wheres.isEmpty()) {
if (sel.getWhere() != null) {
w = Where.and(sel.getWhere(), Where.and(wheres));
} else {
147,4 → 121,10
sel.setWhere(w);
}
}
return sel;
}
});
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/TableSearchColumnMatcher.java
New file
0,0 → 1,76
/*
* 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.FieldPath;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLFunctionField;
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.ui.light.TableSearchParameterType;
import org.openconcerto.ui.light.UserSearchItem;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
 
public class TableSearchColumnMatcher implements TableSearchMatcher {
private final SQLTableModelColumn col;
 
public TableSearchColumnMatcher(SQLTableModelColumn col) {
this.col = col;
}
 
@Override
public boolean useMatch() {
return false;
}
 
@Override
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt) {
return true;
}
 
@Override
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt) {
final Set<FieldPath> fields = this.col.getPaths();
final List<Where> wFields = new ArrayList<>(fields.size());
for (final FieldPath fpath : fields) {
if (fpath.getField().getType().getJavaType().equals(String.class)) {
final FieldRef fieldRef = sel.followFieldPath(fpath);
if (type.getType().equals(UserSearchItem.TYPE_CONTAINS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", "%" + txt.toLowerCase() + "%");
wFields.add(w);
} else if (type.getType().equals(UserSearchItem.TYPE_STARTS_WITH)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase() + "%");
wFields.add(w);
} else if (type.getType().equals(UserSearchItem.TYPE_IS)) {
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, fieldRef), "LIKE", txt.toLowerCase());
wFields.add(w);
}
}
}
return Where.or(wFields);
}
 
@Override
public List<FieldPath> getAdditionnalFieldsToFetch() {
return Collections.emptyList();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/SearchInfo.java
17,8 → 17,8
import org.openconcerto.sql.view.search.SearchList;
import org.openconcerto.sql.view.search.TextSearchSpec;
import org.openconcerto.sql.view.search.TextSearchSpec.Mode;
import org.openconcerto.ui.light.SearchContent;
import org.openconcerto.ui.light.SearchSpec;
import org.openconcerto.ui.light.UserSearchItem;
import org.openconcerto.ui.light.UserSearch;
 
import java.util.ArrayList;
import java.util.List;
28,10 → 28,10
private final SearchList list = new SearchList();
private final List<String> texts = new ArrayList<String>();
 
public SearchInfo(final SearchSpec params) {
public SearchInfo(final UserSearch params) {
int stop = params.getContent().size();
for (int i = 0; i < stop; i++) {
final SearchContent param = params.getContent().get(i);
final UserSearchItem param = params.getContent().get(i);
final String col = param.getColumn();
final String type = param.getType();
final String[] tTexts = param.getText().split(" ");
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/TableSearchMatcher.java
New file
0,0 → 1,51
/*
* 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.FieldPath;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.ui.light.TableSearchParameterType;
 
import java.util.List;
 
public interface TableSearchMatcher {
 
/**
* Where to add to prefilter the result
*/
public Where getWhere(SQLSelect sel, TableSearchParameterType type, String txt);
 
/**
* Fields to fetch for this matcher. The fields will be accessed in the match method, from the
* SQLRowValues
*
* @return the fields paths
* @return null or emtpy List is nothing to fetch
*/
public List<FieldPath> getAdditionnalFieldsToFetch();
 
/**
* @return true is the match method must be used
*/
public boolean useMatch();
 
/**
* Match the SQLRowValues retrieve from the database (filtered by the Where from getWhere) using
* the type and the user text
*/
public boolean match(SQLRowValues r, TableSearchParameterType type, String txt);
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightUIPanelFiller.java
15,6 → 15,7
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.Constraint;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRowAccessor;
31,6 → 32,9
 
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
/**
58,11 → 62,17
}
}
 
public void fillFromRow(final PropsConfiguration configuration, final SQLRowAccessor row) {
this.fillFromRow(this.panel, configuration, row);
public void fillFromRow(final PropsConfiguration configuration, SQLElement element, final SQLRowAccessor row, String sessionSecurityToken) {
this.fillFromRow(this.panel, configuration, element, row, sessionSecurityToken);
}
 
private void fillFromRow(final LightUIPanel panel, final PropsConfiguration configuration, SQLRowAccessor sqlRow) {
private void fillFromRow(final LightUIPanel panel, final PropsConfiguration configuration, SQLElement sqlElement, SQLRowAccessor sqlRow, String sessionSecurityToken) {
List<CustomRowEditor> editors = sqlElement.getCustomRowEditors(configuration, sessionSecurityToken);
Map<String, CustomRowEditor> mapEditor = new HashMap<>(editors.size());
for (CustomRowEditor e : editors) {
mapEditor.put(e.getItemId(), e);
}
 
final int panelChildCount = panel.getChildrenCount();
// Convert as sqlrow if possible to get all values from db
if (sqlRow.hasID()) {
73,6 → 83,10
final int lineChildCount = panelChild.getChildrenCount();
for (int j = 0; j < lineChildCount; j++) {
final LightUIElement element = panelChild.getChild(j);
if (mapEditor.containsKey(element.getId())) {
mapEditor.get(element.getId()).fillFrom(element, sqlRow);
} else {
 
final SQLField sqlField = configuration.getFieldMapper().getSQLFieldForItem(element.getId());
 
SQLRowAccessor sqlRowTmp = this.getSQLRowForField(sqlRow, sqlField);
115,7 → 129,7
element.setValue(JSONConverter.getJSON(date).toString());
}
} else if (type == LightUIElement.TYPE_PANEL) {
this.fillFromRow((LightUIPanel) element, configuration, sqlRowTmp);
this.fillFromRow((LightUIPanel) element, configuration, sqlElement, sqlRowTmp, sessionSecurityToken);
} else if (type == LightUIElement.TYPE_SLIDER) {
final Integer value = sqlRowTmp.getInt(sqlField.getName());
if (value != null) {
125,6 → 139,7
}
}
}
}
 
public SQLRowAccessor getSQLRowForField(final SQLRowAccessor sqlRow, final SQLField sqlField) {
SQLRowAccessor sqlRowResult = sqlRow;
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/IColorChooser.java
New file
0,0 → 1,85
/*
* 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;
 
import org.openconcerto.ui.ColorField;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Color;
import java.beans.PropertyChangeListener;
 
import javax.swing.JComponent;
 
public class IColorChooser extends ColorField implements ValueWrapper<Integer> {
 
public IColorChooser(String title) {
super(title);
}
 
@Override
public JComponent getComp() {
return this;
}
 
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
@Override
public void setValue(Integer val) {
if (val == null) {
val = Color.WHITE.getRGB();
}
setColor(new Color(val));
}
 
@Override
public Integer getValue() {
if (getColor() == null) {
return null;
} else {
return getColor().getRGB();
}
}
 
@Override
public void addValidListener(ValidListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public void removeValidListener(ValidListener l) {
// TODO Auto-generated method stub
 
}
 
@Override
public void resetValue() {
this.setColor(null);
}
 
@Override
public final void addValueListener(final PropertyChangeListener l) {
this.addPropertyChangeListener("value", l);
}
 
@Override
public void rmValueListener(final PropertyChangeListener l) {
this.removePropertyChangeListener("value", l);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionUtils.java
18,6 → 18,7
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.IdentityHashSet;
import org.openconcerto.utils.cc.IdentitySet;
import org.openconcerto.utils.cc.LinkedIdentitySet;
import org.openconcerto.utils.cc.Transformer;
 
import java.io.Serializable;
643,14 → 644,16
return collector;
}
 
@SuppressWarnings("unchecked")
public static <T> Collection<T> subtract(final Collection<T> a, final Collection<? extends T> b) {
return org.apache.commons.collections.CollectionUtils.subtract(a, b);
final Collection<T> res = a instanceof IdentitySet ? new LinkedIdentitySet<>(a) : new ArrayList<>(a);
for (Iterator<? extends T> it = b.iterator(); it.hasNext();) {
res.remove(it.next());
}
return res;
}
 
@SuppressWarnings("unchecked")
public static <T> Collection<T> substract(final Collection<T> a, final Collection<? extends T> b) {
return org.apache.commons.collections.CollectionUtils.subtract(a, b);
return subtract(a, b);
}
 
public static final <T> T coalesce(T o1, T o2) {
935,10 → 938,11
* @param <K> type of key.
* @param <V> type of value.
* @param keys the keys of the map.
* @return a new map, if <code>keys</code> is a {@link List} it will be ordered.
* @return a new ordered map.
*/
public static <K, V> Map<K, V> createMap(Collection<? extends K> keys) {
return fillMap(keys instanceof List ? new LinkedHashMap<K, V>(keys.size()) : new HashMap<K, V>(keys.size()), keys);
// there's no way to tell if a Collection is ordered, so always use ordered map.
return fillMap(new LinkedHashMap<K, V>(keys.size()), keys);
}
 
/**
/trunk/OpenConcerto/src/org/openconcerto/utils/FileUtils.java
695,6 → 695,7
* @see StreamUtils#createXMLWriter(java.io.OutputStream)
*/
public static BufferedWriter createXMLWriter(final File f) throws IOException {
FileUtils.mkParentDirs(f);
final FileOutputStream outs = new FileOutputStream(f);
try {
return StreamUtils.createXMLWriter(outs);
/trunk/OpenConcerto/src/org/openconcerto/utils/StringUtils.java
28,6 → 28,7
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
820,4 → 821,13
}
return b.toString();
}
 
public static final Matcher findFirstContaining(final String s, final Pattern... patterns) {
for (final Pattern p : patterns) {
final Matcher matcher = p.matcher(s);
if (matcher.find())
return matcher;
}
return null;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/sync/HashWriter.java
13,6 → 13,8
package org.openconcerto.utils.sync;
 
import org.openconcerto.utils.MessageDigestUtils;
 
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
38,8 → 40,8
}
final DataOutputStream bOut = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
bOut.writeInt((int) this.in.length());
final MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
final MessageDigest md5 = MessageDigest.getInstance("MD5");
final MessageDigest hashSum = MessageDigestUtils.getSHA256();
final MessageDigest md5 = MessageDigestUtils.getMD5();
fb = new BufferedInputStream(new FileInputStream(in));
final RollingChecksum32 r32 = new RollingChecksum32();
final byte[] buffer = new byte[BLOCK_SIZE];
74,8 → 76,8
}
}
 
public static byte[] getHash(File f) throws Exception {
final MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
public static byte[] getHash(File f) throws IOException {
final MessageDigest hashSum = MessageDigestUtils.getSHA256();
FileInputStream fIn = null;
try {
fIn = new FileInputStream(f);
123,4 → 125,15
return true;
}
 
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
 
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/sync/SimpleSyncClient.java
New file
0,0 → 1,413
/*
* 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.sync;
 
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.MessageDigestUtils;
import org.openconcerto.utils.StreamUtils;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileTime;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
 
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
 
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.parser.JSONParser;
 
public final class SimpleSyncClient {
 
private static final int MIN_GZIP_SIZE = 64;
 
static protected final long getLong(final Object o) {
return ((Number) o).longValue();
}
 
static protected final Instant getInstant(final Object o) {
return Instant.ofEpochMilli(getLong(o));
}
 
static public class ServerException extends RuntimeException {
private final int responseCode;
private final boolean authenticateError;
 
protected ServerException(int responseCode, boolean authenticateError) {
super("Response code was " + responseCode);
this.responseCode = responseCode;
this.authenticateError = authenticateError;
}
 
public final int getResponseCode() {
return this.responseCode;
}
 
public final boolean isAuthenticateError() {
return this.authenticateError;
}
}
 
static public final class Response {
 
protected final static Response create(HttpsURLConnection con, final Set<Integer> okCodes) throws IOException {
final boolean success = okCodes == null ? con.getResponseCode() == 200 : okCodes.contains(con.getResponseCode());
return new Response(success, con.getResponseCode(), con.getResponseMessage(), con.getContentEncoding(), con.getContentType());
}
 
private final boolean success;
private final int code;
private final String message;
private final String contentEncoding, contentType;
 
protected Response(boolean success, int code, String message, String contentEncoding, String contentType) {
super();
this.success = success;
this.code = code;
this.message = message;
this.contentEncoding = contentEncoding;
this.contentType = contentType;
}
 
public final int getCode() {
return this.code;
}
 
public final boolean isSuccess() {
return this.success;
}
 
public final String getMessage() {
return this.message;
}
 
public final String getContentEncoding() {
return this.contentEncoding;
}
 
public final String getContentType() {
return this.contentType;
}
}
 
static protected abstract class BaseAttrs {
private final String path;
private final String name;
private final Instant lastModified;
 
protected BaseAttrs(final String path, final String name, final Instant lastModified) {
super();
this.path = path;
this.name = name;
this.lastModified = lastModified;
}
 
public final String getPath() {
return this.path;
}
 
public final String getName() {
return this.name;
}
 
public final Instant getLastModified() {
return this.lastModified;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " '" + this.getName() + "'";
}
}
 
static public final class DirAttrs extends BaseAttrs {
static protected DirAttrs fromJSON(final String path, final JSONArray array) {
return new DirAttrs(path, (String) array.get(0), getInstant(array.get(1)));
}
 
protected DirAttrs(final String path, String name, Instant lastModified) {
super(path, name, lastModified);
}
}
 
static public final class FileAttrs extends BaseAttrs {
 
static protected FileAttrs fromJSON(final String path, final JSONArray array) {
return new FileAttrs(path, (String) array.get(0), getInstant(array.get(2)), getLong(array.get(1)), (String) array.get(3));
}
 
private final long size;
private final String sha256;
 
protected FileAttrs(final String path, String name, Instant lastModified, long size, String sha256) {
super(path, name, lastModified);
this.size = size;
this.sha256 = sha256;
}
 
public final long getSize() {
return this.size;
}
 
public final String getSHA256() {
return this.sha256;
}
 
public final void saveFile(final InputStream in, final Path localFile) throws IOException {
// Save to temporary file to avoid overwriting old file with a new invalid one. In
// same folder for the move.
final Path tmpFile = Files.createTempFile(localFile.getParent(), "partial", null);
try {
final MessageDigest md = this.getSHA256() == null ? null : MessageDigestUtils.getSHA256();
try (final BufferedOutputStream fileStream = new BufferedOutputStream(Files.newOutputStream(tmpFile));
//
final OutputStream out = md == null ? fileStream : new DigestOutputStream(fileStream, md)) {
StreamUtils.copy(in, out);
}
if (this.getSize() >= 0) {
final long savedSize = Files.size(tmpFile);
if (savedSize != this.getSize())
throw new IOException("Expected " + this.getSize() + " bytes but saved " + savedSize);
}
if (md != null) {
final String savedHash = MessageDigestUtils.getHashString(md);
if (!savedHash.equalsIgnoreCase(this.getSHA256()))
throw new IOException("Expected hash was " + this.getSHA256() + " but saved " + savedHash);
}
Files.move(tmpFile, localFile, StandardCopyOption.REPLACE_EXISTING);
} finally {
Files.deleteIfExists(tmpFile);
}
if (this.getLastModified().compareTo(Instant.EPOCH) > 0)
Files.setLastModifiedTime(localFile, FileTime.from(this.getLastModified()));
}
 
@Override
public String toString() {
return super.toString() + " of size " + getSize();
}
}
 
static public final class DirContent {
private final String path;
private final JSONObject json;
 
protected DirContent(final String path, JSONObject json) {
super();
this.path = path;
this.json = json;
}
 
public final List<FileAttrs> getFiles() {
return this.getFiles(null);
}
 
public final List<FileAttrs> getFiles(final Predicate<String> namePredicate) {
return this.getContent("files", namePredicate, FileAttrs::fromJSON);
}
 
public final List<DirAttrs> getDirs() {
return this.getDirs(null);
}
 
public final List<DirAttrs> getDirs(final Predicate<String> namePredicate) {
return this.getContent("dirs", namePredicate, DirAttrs::fromJSON);
}
 
protected final <T extends BaseAttrs> List<T> getContent(final String key, final Predicate<String> namePredicate, final BiFunction<String, JSONArray, T> create) {
final JSONArray files = (JSONArray) this.json.get(key);
if (files == null)
return Collections.emptyList();
final List<T> res = new ArrayList<>();
for (final Object f : files) {
final JSONArray array = (JSONArray) f;
if (namePredicate == null || namePredicate.test((String) array.get(0))) {
res.add(create.apply(this.path, array));
}
}
return res;
}
}
 
private final String url;
private SSLSocketFactory socketFactory;
private String token;
private boolean throwException = true;
 
public SimpleSyncClient(final String url) {
this.url = url;
}
 
public final SSLSocketFactory getSocketFactory() {
return this.socketFactory;
}
 
public final void setSocketFactory(SSLSocketFactory socketFactory) {
this.socketFactory = socketFactory;
}
 
public final void setToken(String token) {
this.token = token;
}
 
public final boolean hasToken() {
return this.getToken() != null;
}
 
protected final String getToken() {
return this.token;
}
 
public final void setThrowException(boolean throwException) {
this.throwException = throwException;
}
 
public final boolean throwsException() {
return this.throwException;
}
 
protected Response checkResponseCode(final HttpsURLConnection con) throws IOException {
return checkResponseCode(con, null);
}
 
protected Response checkResponseCode(final HttpsURLConnection con, final Set<Integer> okCodes) throws IOException {
final Response res = Response.create(con, okCodes);
if (this.throwsException() && !res.isSuccess())
throw new ServerException(res.getCode(), con.getHeaderField("WWW-Authenticate") != null);
return res;
}
 
private final HttpsURLConnection openConnection(final String path) throws IOException {
final HttpsURLConnection con = (HttpsURLConnection) new URL(this.url + path).openConnection();
con.setRequestProperty("Accept-Encoding", "gzip");
if (this.getSocketFactory() != null)
con.setSSLSocketFactory(this.getSocketFactory());
if (getToken() != null)
con.setRequestProperty("Authorization", "Bearer " + Base64.getEncoder().encodeToString(getToken().getBytes(StandardCharsets.UTF_8)));
return con;
}
 
private final InputStream getInputStream(final HttpsURLConnection con) throws IOException {
return "gzip".equals(con.getContentEncoding()) ? new GZIPInputStream(con.getInputStream()) : con.getInputStream();
}
 
private final HttpsURLConnection send(final HttpsURLConnection con, final String params) throws IOException {
return this.send(con, params.getBytes(StandardCharsets.UTF_8), false);
}
 
private final HttpsURLConnection send(final HttpsURLConnection con, final byte[] toSend, final boolean allowGzip) throws IOException {
final boolean useGzip = allowGzip && toSend.length >= MIN_GZIP_SIZE;
if (useGzip)
con.setRequestProperty("Content-Encoding", "gzip");
con.setRequestMethod("POST");
con.setDoOutput(true);
try (final OutputStream o = useGzip ? new GZIPOutputStream(con.getOutputStream()) : con.getOutputStream()) {
o.write(toSend);
}
return con;
}
 
public DirContent getDir(final String path) throws Exception {
final HttpsURLConnection con = openConnection("/getDir");
final Response res = checkResponseCode(send(con, "rp=" + path + "&type=json"));
if (!res.isSuccess())
return null;
final JSONParser p = new JSONParser(JSONParser.MODE_STRICTEST);
try (final InputStream in = getInputStream(con)) {
return new DirContent(path, (JSONObject) p.parse(in));
}
}
 
@FunctionalInterface
static public interface FileConsumer {
public void accept(FileAttrs attrs, InputStream fileStream) throws IOException;
}
 
static private final Set<Integer> GETFILE_OK_CODES = CollectionUtils.createSet(200, 404);
 
public Response getFile(final String path, final String fileName, final FileConsumer fileConsumer) throws IOException {
final HttpsURLConnection con = openConnection("/get");
send(con, "rn=" + fileName + "&rp=" + path);
final Response res = checkResponseCode(con, GETFILE_OK_CODES);
if (res.getCode() == 404) {
fileConsumer.accept(null, null);
} else if (res.getCode() == 200) {
final FileAttrs fileAttrs = new FileAttrs(path, fileName, Instant.ofEpochMilli(con.getLastModified()), -1, con.getHeaderField("X-SHA256"));
try (final InputStream in = getInputStream(con)) {
fileConsumer.accept(fileAttrs, in);
}
}
return res;
}
 
// ATTN contrary to other methods, the result isn't if the request was OK : it ignores
// throwsException() and always throws. The return value is true if the file existed and was
// saved.
public boolean saveFile(final String path, final String fileName, final Path localFile) throws IOException {
final AtomicBoolean missing = new AtomicBoolean(true);
final Response res = this.getFile(path, fileName, (fileAttrs, in) -> {
missing.set(fileAttrs == null);
if (!missing.get()) {
fileAttrs.saveFile(in, localFile);
}
});
if (!res.isSuccess())
throw new IOException("Couldn't retrieve file " + fileName);
return !missing.get();
}
 
public Response deleteFile(final String path, final String fileName) throws MalformedURLException, IOException, ProtocolException, UnsupportedEncodingException {
final HttpsURLConnection con = openConnection("/delete");
return checkResponseCode(send(con, "rn=" + fileName + "&rp=" + path));
}
 
public Response sendFile(String path, File localFile) throws Exception, MalformedURLException, IOException, ProtocolException {
byte[] newsha256 = HashWriter.getHash(localFile);
long size = localFile.length();
 
final HttpsURLConnection con = openConnection("/put");
// We use Base64 because headers are not supporting UTF8
con.setRequestProperty("X_FILENAME_B64", Base64.getEncoder().encodeToString(localFile.getName().getBytes(StandardCharsets.UTF_8)));
con.setRequestProperty("X_PATH_B64", Base64.getEncoder().encodeToString(path.getBytes(StandardCharsets.UTF_8)));
con.setRequestProperty("X_FILESIZE", String.valueOf(size));
con.setRequestProperty("X_SHA256", HashWriter.bytesToHex(newsha256));
con.setRequestProperty("X-Last-Modified-ms", String.valueOf(localFile.lastModified()));
 
return checkResponseCode(send(con, Files.readAllBytes(localFile.toPath()), true));
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/TranslationManager.java
25,16 → 25,17
import java.util.Map;
import java.util.ResourceBundle.Control;
 
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
@ThreadSafe
public class TranslationManager {
private static final Locale FALLBACK_LOCALE = Locale.ENGLISH;
64,7 → 65,7
@GuardedBy("classes")
private Locale locale;
 
private final Object trMutex = new String("translations mutex");
private final Object trMutex = new Object();
@GuardedBy("trMutex")
private Map<String, String> menuTranslation;
@GuardedBy("trMutex")
73,7 → 74,7
private Map<String, String> actionTranslation;
 
private TranslationManager() {
this.classes = new ArrayList<Class<?>>();
this.classes = new ArrayList<>();
}
 
public void addTranslationStreamFromClass(Class<?> c) {
164,10 → 165,10
 
private void loadAllTranslation() {
synchronized (this.trMutex) {
this.menuTranslation = new HashMap<String, String>();
this.itemTranslation = new HashMap<String, String>();
this.actionTranslation = new HashMap<String, String>();
if (this.classes.size() == 0) {
this.menuTranslation = new HashMap<>();
this.itemTranslation = new HashMap<>();
this.actionTranslation = new HashMap<>();
if (this.classes.isEmpty()) {
Log.get().warning("TranslationManager has no resources to load (" + this.getLocale() + ")");
}
for (Class<?> c : this.classes) {
182,7 → 183,7
// return all existing (e.g fr_CA only specify differences with fr)
private List<InputStream> findStream(final Locale locale, final Class<?> c, final boolean rootLast) {
final Control cntrl = CONTROL;
final List<InputStream> res = new ArrayList<InputStream>();
final List<InputStream> res = new ArrayList<>();
final String baseName = c.getPackage().getName() + "." + BASENAME;
 
// test emptiness to not mix languages
203,7 → 204,7
// we want more specific translations to replace general ones, i.e. root Locale first
for (final InputStream input : findStream(l, c, false)) {
// create new instances to check if there's no duplicates in each resource
final Map<String, String> menuTranslation = new HashMap<String, String>(), itemTranslation = new HashMap<String, String>(), actionTranslation = new HashMap<String, String>();
final Map<String, String> menuTranslation = new HashMap<>(), itemTranslation = new HashMap<>(), actionTranslation = new HashMap<>();
loadTranslation(input, menuTranslation, itemTranslation, actionTranslation);
// on the other hand, it's OK for one resource to override another
this.menuTranslation.putAll(menuTranslation);
214,10 → 215,14
return translationLoaded;
}
 
static private void loadTranslation(final InputStream input, final Map<String, String> menuTranslation, final Map<String, String> itemTranslation, final Map<String, String> actionTranslation) {
private static void loadTranslation(final InputStream input, final Map<String, String> menuTranslation, final Map<String, String> itemTranslation, final Map<String, String> actionTranslation) {
// FIXME : l'implementation de Java est lente
// com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl : 60 ms!
// On pourrait passer à 1ms avec Piccolo...
final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
 
try {
dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
final Document doc = dBuilder.parse(input);
// Menus
239,7 → 244,7
}
}
 
static private void loadTranslation(final Document doc, final String tagName, final Map<String, String> m) {
private static void loadTranslation(final Document doc, final String tagName, final Map<String, String> m) {
final NodeList menuChildren = doc.getElementsByTagName(tagName);
final int size = menuChildren.getLength();
for (int i = 0; i < size; i++) {
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IExnFactory.java
New file
0,0 → 1,20
/*
* 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.cc;
 
public interface IExnFactory<E, X extends Exception> {
 
public abstract E createChecked() throws X;
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/Cookies.java
New file
0,0 → 1,216
/*
* 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.cc;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
 
import com.google.gson.reflect.TypeToken;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
/**
* Type-safer map (e.g. can store multiple types and collections).
*
* @author Sylvain
*/
@ThreadSafe
public class Cookies {
 
@GuardedBy("this")
private final Map<Object, Object> map;
@GuardedBy("this")
private Map<Object, Object> collectionTypes;
 
public Cookies() {
this(8);
}
 
public Cookies(final int initialCapacity) {
this.map = new HashMap<>(initialCapacity);
this.collectionTypes = null;
}
 
public Cookies(final Cookies source) {
synchronized (source) {
this.map = new HashMap<>(source.map);
this.collectionTypes = source.collectionTypes == null ? null : new HashMap<>(source.collectionTypes);
}
}
 
public final void putAll(final Cookies other) {
if (this == other)
return;
final Map<Object, Object> map;
final Map<Object, Object> collectionTypes;
synchronized (other) {
map = new HashMap<>(other.map);
collectionTypes = other.collectionTypes == null ? null : new HashMap<>(other.collectionTypes);
}
synchronized (this) {
// don't just use putAll() since it won't remove entries from collectionTypes for
// replaced items
for (final Entry<Object, Object> e : map.entrySet()) {
this.put(e.getKey(), e.getValue(), collectionTypes == null ? null : collectionTypes.get(e.getKey()));
}
}
}
 
public final Object put(Object k, Object v) {
return this.put(k, v, null);
}
 
private final Object putCollectionType(Object k, Object v, Object type) {
if (type == null)
throw new IllegalArgumentException("Null type");
return this.put(k, v, type);
}
 
private final synchronized Object put(Object k, Object v, Object type) {
if (type != null) {
if (this.collectionTypes == null)
this.collectionTypes = new HashMap<>(4);
this.collectionTypes.put(k, type);
} else if (this.collectionTypes != null) {
this.collectionTypes.remove(k);
}
return this.map.put(k, v);
}
 
public final <T> Object putCollection(Object k, Collection<T> v, Class<T> clazz) {
return this.putCollectionType(k, v, clazz);
}
 
public final <K, V> Object putMap(Object k, Map<K, V> v, Class<K> keyClass, Class<V> valueClass) {
Objects.requireNonNull(keyClass, "Key class");
Objects.requireNonNull(valueClass, "value class");
return this.putCollectionType(k, v, Arrays.asList(keyClass, valueClass));
}
 
public final <T> Object putGeneric(Object k, T v, TypeToken<T> clazz) {
return this.putCollectionType(k, v, clazz);
}
 
public final synchronized boolean containsKey(Object k) {
return this.map.containsKey(k);
}
 
public final synchronized Object getObject(Object k) {
return this.map.get(k);
}
 
public final int getInt(Object k) {
return getObjectAs(k, Number.class).intValue();
}
 
public final long getLong(Object k) {
return getObjectAs(k, Number.class).longValue();
}
 
public final Boolean getBoolean(Object k) {
return getObjectAs(k, Boolean.class);
}
 
public final boolean getBoolean(Object k, final boolean def) {
final Boolean res = getBoolean(k);
return res == null ? def : res.booleanValue();
}
 
public final String getString(Object k) {
return getObjectAs(k, String.class);
}
 
public synchronized final <T> T getContainedObjectAs(Object key, Class<T> clazz) {
if (!this.containsKey(key))
throw new IllegalArgumentException(key + " not present in this : " + this.map.keySet());
return this.getObjectAs(key, clazz);
}
 
public final <T> T getObjectAs(Object k, Class<T> clazz) {
return this.getObjectAs(k, clazz, null);
}
 
public final <T> T getObjectAs(Object k, Class<T> clazz, final T defaultVal) {
return this.getObjectAs(k, clazz, defaultVal, true);
}
 
public synchronized final <T> T getObjectAs(Object k, Class<T> clazz, final T defaultVal, final boolean useDefaultIfNullValue) {
final Object res = this.getObject(k);
if (res == null && (useDefaultIfNullValue || !this.containsKey(k)))
return defaultVal;
try {
return clazz.cast(res);
} catch (ClassCastException e) {
throw new IllegalArgumentException("Couldn't access " + k + " in " + this + " as " + clazz.getSimpleName(), e);
}
}
 
public final <T> Object checkType(Object k, Object wantedType, final String needMethodName) {
final Object object;
final Object type;
synchronized (this) {
object = this.getObject(k);
type = this.collectionTypes == null ? null : this.collectionTypes.get(k);
}
// as getObject() : don't fail on null
if (object == null)
return null;
if (type == null)
throw new IllegalStateException("Wasn't stored with " + needMethodName + " : " + k);
if (!type.equals(wantedType))
throw new IllegalArgumentException("Wasn't stored with the passed type : " + wantedType + " != " + type);
return object;
}
 
public final <T> Collection<T> getCollection(Object k, Class<T> clazz) {
final Object object = checkType(k, clazz, "putCollection()");
@SuppressWarnings("unchecked")
final Collection<T> res = (Collection<T>) object;
return res;
}
 
public final <T> List<T> getList(Object k, Class<T> clazz) {
return (List<T>) this.getCollection(k, clazz);
}
 
public final <T> Set<T> getSet(Object k, Class<T> clazz) {
return (Set<T>) this.getCollection(k, clazz);
}
 
public final <K, V> Map<K, V> getMap(Object k, Class<K> keyClass, Class<V> valueClass) {
final Object object = checkType(k, Arrays.asList(keyClass, valueClass), "putMap()");
@SuppressWarnings("unchecked")
final Map<K, V> res = (Map<K, V>) object;
return res;
}
 
public final <T> T getGeneric(Object k, TypeToken<T> clazz) {
final Object object = checkType(k, clazz, "putGeneric()");
@SuppressWarnings("unchecked")
final T res = (T) object;
return res;
}
 
@Override
public synchronized String toString() {
return this.getClass().getSimpleName() + " of " + this.map.keySet();
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IFactory.java
13,8 → 13,9
package org.openconcerto.utils.cc;
 
public interface IFactory<E> {
public interface IFactory<E> extends IExnFactory<E, RuntimeException> {
 
@Override
public abstract E createChecked();
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/CustomEquals.java
19,7 → 19,10
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.Set;
import java.util.function.BiPredicate;
 
/**
* Allow to create a proxy object which uses a {@link HashingStrategy}.
103,6 → 106,28
return CompareUtils.equals(sA, sB);
}
 
static public final <S, T1 extends S> int indexOf(final List<T1> s1, final S o, final HashingStrategy<S> s) {
return indexOf(s1, o, s::equals);
}
 
static public final <S, T1 extends S> int indexOf(final List<T1> s1, final S o, final BiPredicate<S, S> s) {
if (s1 instanceof RandomAccess) {
final int stop = s1.size();
for (int i = 0; i < stop; i++) {
if (s.test(s1.get(i), o))
return i;
}
} else {
final ListIterator<T1> listIter = s1.listIterator();
while (listIter.hasNext()) {
final T1 item = listIter.next();
if (s.test(item, o))
return listIter.previousIndex();
}
}
return -1;
}
 
static public class ProxyFull<S, E extends S> implements ProxyItf<E> {
 
static public final <S, E extends S> Set<ProxyFull<S, E>> createSet(final HashingStrategy<S> strategy, final Collection<E> coll) {
192,7 → 217,12
else
return this.strategy.equals(this.getDelegate(), delegate2);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " using strategy " + this.getStrategy() + " for " + this.getDelegate();
}
}
 
/**
* A proxy object which uses a {@link HashingStrategy}.
/trunk/OpenConcerto/src/org/openconcerto/utils/TableSorter.java
348,8 → 348,12
* @return the corresponding index in the model.
*/
public int modelIndex(int viewIndex) {
try {
return getViewToModel()[viewIndex].modelIndex;
} catch (Exception e) {
throw new IllegalStateException(this + " couldn't get model index for view index " + viewIndex + " with " + this.getTableModel().getRowCount() + " row(s) in our model", e);
}
}
 
private int[] getModelToView() {
if (!SwingUtilities.isEventDispatchThread()) {
430,6 → 434,11
this.supp.removePropertyChangeListener(l);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " on " + this.getTableModel();
}
 
// Helper classes
 
private class Row implements Comparable<Row> {
/trunk/OpenConcerto/src/org/openconcerto/utils/text/CSVReader.java
29,7 → 29,6
 
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
248,11 → 247,4
br.close();
}
 
public static void main(String[] args) throws IOException {
CSVReader reader = new CSVReader(new FileReader("n:\\Sans nom 1.csv"));
String[] s = reader.readNext();
for (int i = 0; i < s.length; i++) {
System.err.println("CSVReader.main() :" + i + " : " + s[i]);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionMap2.java
122,6 → 122,9
 
// ** copy constructors
 
// ATTN getDelegate() is not in CollectionMap2Itf, so if one copies an unmodifiableMap() this
// constructor won't be used and the delegate will be the default HashMap (even if the source
// used a LinkedHashMap).
public CollectionMap2(final CollectionMap2<K, C, ? extends V> m) {
this(CopyUtils.copy(m.getDelegate()), m);
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXDocument.java
New file
0,0 → 1,273
/*
* 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.ooxml;
 
import org.openconcerto.utils.StringInputStream;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
 
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
 
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
 
public class XLSXDocument {
 
private File file;
private final List<XLSXSheet> sheets = new ArrayList<>();
private final Map<String, String> relationships = new HashMap<>();
private final List<String> sharedString = new ArrayList<>();
private final Map<Integer, XLSXFormat> mapFormats = new HashMap<>();
private final List<XLSXFormat> customFormats = new ArrayList<>();
private final List<XLSXStyle> styles = new ArrayList<>();
private final DocumentBuilderFactory dbFactory;
 
public static XLSXDocument createFromFile(File f) throws IOException {
XLSXDocument doc = new XLSXDocument();
doc.load(f);
return doc;
}
 
public XLSXDocument() {
this.mapFormats.put(0, new XLSXFormat(0, "General", false));
this.mapFormats.put(1, new XLSXFormat(1, "0", false));
this.mapFormats.put(2, new XLSXFormat(2, "0.00", false));
this.mapFormats.put(3, new XLSXFormat(3, "#,##0", false));
this.mapFormats.put(4, new XLSXFormat(4, "#,##0.00", false));
this.mapFormats.put(9, new XLSXFormat(9, "0%", false));
this.mapFormats.put(10, new XLSXFormat(10, "0.00%", false));
this.mapFormats.put(11, new XLSXFormat(11, "0.00E+00", false));
this.mapFormats.put(12, new XLSXFormat(12, "# ?/?", false));
this.mapFormats.put(13, new XLSXFormat(13, "# ??/??", false));
this.mapFormats.put(14, new XLSXFormat(14, "mm-dd-yy", true));
this.mapFormats.put(15, new XLSXFormat(15, "d-mmm-yy", true));
this.mapFormats.put(16, new XLSXFormat(16, "d-mmm", true));
this.mapFormats.put(17, new XLSXFormat(17, "mmm-yy", true));
this.mapFormats.put(18, new XLSXFormat(18, "h:mm AM/PM", false));
this.mapFormats.put(19, new XLSXFormat(19, "h:mm:ss AM/PM", false));
this.mapFormats.put(20, new XLSXFormat(20, "h:mm", false));
this.mapFormats.put(21, new XLSXFormat(21, "h:mm:ss", false));
this.mapFormats.put(22, new XLSXFormat(22, "m/d/yy h:mm", true));
this.mapFormats.put(27, new XLSXFormat(27, "[$-404]e/m/d", true));
this.mapFormats.put(30, new XLSXFormat(30, "m/d/yy", true));
this.mapFormats.put(36, new XLSXFormat(36, "[$-404]e/m/d", true));
this.mapFormats.put(37, new XLSXFormat(37, "#,##0 ;(#,##0)", false));
this.mapFormats.put(38, new XLSXFormat(38, "#,##0 ;[Red](#,##0)", false));
this.mapFormats.put(39, new XLSXFormat(39, "#,##0.00;(#,##0.00)", false));
this.mapFormats.put(40, new XLSXFormat(40, "#,##0.00;[Red](#,##0.00)", false));
this.mapFormats.put(44, new XLSXFormat(44, "_(\"$\"* #,##0.00_);_(\"$\"* (#,##0.00);_(\"$\"* \"-\"??_);_(@_)", false));
this.mapFormats.put(45, new XLSXFormat(45, "mm:ss", false));
this.mapFormats.put(46, new XLSXFormat(46, "[h]:mm:ss", false));
this.mapFormats.put(47, new XLSXFormat(47, "mmss.0", false));
this.mapFormats.put(48, new XLSXFormat(48, "##0.0E+0", false));
this.mapFormats.put(49, new XLSXFormat(49, "@", false));
this.mapFormats.put(50, new XLSXFormat(50, "[$-404]e/m/d", true));
this.mapFormats.put(57, new XLSXFormat(57, "[$-404]e/m/d", true));
this.mapFormats.put(59, new XLSXFormat(59, "t0", false));
this.mapFormats.put(60, new XLSXFormat(60, "t0.00", false));
this.mapFormats.put(61, new XLSXFormat(61, "t#,##0", false));
this.mapFormats.put(62, new XLSXFormat(62, "t#,##0.00", false));
this.mapFormats.put(67, new XLSXFormat(67, "t0%", false));
this.mapFormats.put(68, new XLSXFormat(68, "t0.00%", false));
this.mapFormats.put(69, new XLSXFormat(69, "t# ?/?", false));
this.mapFormats.put(70, new XLSXFormat(70, "t# ??/??", false));
 
this.dbFactory = DocumentBuilderFactory.newInstance();
try {
this.dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
} catch (ParserConfigurationException e) {
throw new IllegalStateException(e);
}
try {
this.dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
this.dbFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
} catch (Exception e) {
// ignore
}
this.dbFactory.setNamespaceAware(true);
 
}
 
public File getFile() {
return this.file;
}
 
private void load(File f) throws IOException {
this.file = f;
try (ZipFile zipFile = new ZipFile(f)) {
try {
parseSharedStrings(zipFile);
parseStyles(zipFile);
parseWorkBook(zipFile);
} catch (ParserConfigurationException | SAXException e) {
throw new IOException(e);
}
 
}
}
 
private void parseWorkBook(ZipFile zipFile) throws ParserConfigurationException, SAXException, IOException {
final String relationxXML = getContent(zipFile, "xl/_rels/workbook.xml.rels");
final DocumentBuilder dBuilder1 = this.dbFactory.newDocumentBuilder();
final Document doc1 = dBuilder1.parse(new StringInputStream(relationxXML, StandardCharsets.UTF_8.name()));
doc1.getDocumentElement().normalize();
final NodeList nList = doc1.getElementsByTagName("Relationship");
for (int i = 0; i < nList.getLength(); i++) {
final NamedNodeMap attributes = nList.item(i).getAttributes();
final String rId = attributes.getNamedItem("Id").getNodeValue();
final String target = attributes.getNamedItem("Target").getNodeValue();
this.relationships.put(rId, target);
}
 
final String workbookXML = getContent(zipFile, "xl/workbook.xml");
final DocumentBuilder dBuilder2 = this.dbFactory.newDocumentBuilder();
final Document doc2 = dBuilder2.parse(new StringInputStream(workbookXML, StandardCharsets.UTF_8.name()));
doc2.getDocumentElement().normalize();
doc2.getElementsByTagName("sheets");
final NodeList nListSheet = doc2.getElementsByTagName("sheet");
for (int i = 0; i < nListSheet.getLength(); i++) {
final NamedNodeMap attributes = nListSheet.item(i).getAttributes();
final String sheetId = attributes.getNamedItem("sheetId").getNodeValue();
final String name = attributes.getNamedItem("name").getNodeValue();
final String rId = attributes.getNamedItemNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id").getNodeValue();
final String target = "xl/" + this.relationships.get(rId);
final String xml = getContent(zipFile, target);
this.sheets.add(new XLSXSheet(this, sheetId, rId, name, xml));
}
 
}
 
private void parseSharedStrings(ZipFile zipFile) throws ParserConfigurationException, SAXException, IOException {
final String relationxXML = getContent(zipFile, "xl/sharedStrings.xml");
final DocumentBuilder dBuilder1 = this.dbFactory.newDocumentBuilder();
final Document doc1 = dBuilder1.parse(new StringInputStream(relationxXML, StandardCharsets.UTF_8.name()));
doc1.getDocumentElement().normalize();
final NodeList nList = doc1.getElementsByTagName("si");
for (int i = 0; i < nList.getLength(); i++) {
final Node siNode = nList.item(i);
StringBuilder b = new StringBuilder();
NodeList list = siNode.getChildNodes();
for (int j = 0; j < list.getLength(); j++) {
Node n = list.item(j);
if (n.getLocalName().equals("t")) {
b.append(n.getTextContent());
} else {
NodeList subList = n.getChildNodes();
for (int k = 0; k < subList.getLength(); k++) {
Node nn = subList.item(k);
if (nn.getLocalName().equals("t")) {
b.append(nn.getTextContent());
}
 
}
 
}
}
this.sharedString.add(b.toString());
}
 
}
 
private void parseStyles(ZipFile zipFile) throws ParserConfigurationException, SAXException, IOException {
final String relationxXML = getContent(zipFile, "xl/styles.xml");
final DocumentBuilder dBuilder1 = this.dbFactory.newDocumentBuilder();
final Document doc1 = dBuilder1.parse(new StringInputStream(relationxXML, StandardCharsets.UTF_8.name()));
doc1.getDocumentElement().normalize();
final NodeList nListFormats = doc1.getElementsByTagName("numFmts");
for (int i = 0; i < nListFormats.getLength(); i++) {
final Node siNode = nListFormats.item(i);
NodeList list = siNode.getChildNodes();
for (int j = 0; j < list.getLength(); j++) {
Node n = list.item(j);
NamedNodeMap m = n.getAttributes();
int id = Integer.parseInt(m.getNamedItem("numFmtId").getNodeValue());
String format = m.getNamedItem("formatCode").getNodeValue();
final XLSXFormat f = new XLSXFormat(id, format);
this.mapFormats.put(id, f);
this.customFormats.add(f);
}
 
}
 
final NodeList nListCellXfs = doc1.getElementsByTagName("cellXfs");
for (int i = 0; i < nListCellXfs.getLength(); i++) {
final Node siNode = nListCellXfs.item(i);
NodeList list = siNode.getChildNodes();
for (int j = 0; j < list.getLength(); j++) {
// xf
Node n = list.item(j);
NamedNodeMap m = n.getAttributes();
int id = Integer.parseInt(m.getNamedItem("numFmtId").getNodeValue());
this.styles.add(new XLSXStyle(id));
}
 
}
 
}
 
private String getContent(ZipFile zipFile, String string) throws IOException {
final ZipEntry entry = zipFile.getEntry(string);
if (entry == null) {
throw new IOException("no entry : " + string);
}
final InputStream in = zipFile.getInputStream(entry);
final ByteArrayOutputStream b = new ByteArrayOutputStream();
final byte[] bytes = new byte[8192];
while (in.available() > 0) {
final int length = in.read(bytes);
b.write(bytes, 0, length);
}
return b.toString(StandardCharsets.UTF_8.name());
}
 
public XLSXSheet getSheet(int sheetNumber) {
return this.sheets.get(sheetNumber);
}
 
public int getSheetCount() {
return this.sheets.size();
}
 
public String getSharedString(int index) {
return this.sharedString.get(index);
}
 
public XLSXFormat getFormatFromStyle(int styleIndex) {
final XLSXStyle style = this.styles.get(styleIndex);
if (style == null) {
return null;
}
return this.mapFormats.get(style.getFormatId());
}
 
public DocumentBuilderFactory getDbFactory() {
return this.dbFactory;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXStyle.java
New file
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.utils.ooxml;
 
public class XLSXStyle {
private final int formatId;
 
public XLSXStyle(int formatId) {
this.formatId = formatId;
}
 
public int getFormatId() {
return this.formatId;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXFormat.java
New file
0,0 → 1,71
/*
* 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.ooxml;
 
import java.text.DecimalFormat;
import java.text.Format;
import java.text.SimpleDateFormat;
 
public class XLSXFormat {
private final int id;
private final String format;
private boolean isDateFormat = false;
private Format jformat;
 
public XLSXFormat(int id, String format) {
this.id = id;
this.format = format;
final String f = format.toLowerCase();
if (f.contains("mm") || f.contains("dd") || f.contains("yy")) {
this.isDateFormat = true;
}
}
 
public XLSXFormat(int id, String format, boolean date) {
this.id = id;
this.format = format;
this.isDateFormat = date;
}
 
public int getId() {
return this.id;
}
 
public String getFormat() {
return this.format;
}
 
public boolean isDateFormat() {
return this.isDateFormat;
}
 
public String format(String txt) {
if (this.format.equalsIgnoreCase("general")) {
return txt;
}
if (this.jformat == null) {
String javaFormat = this.format.replace("YYYY", "yyyy");
javaFormat = javaFormat.replace("YY", "yy");
javaFormat = javaFormat.replace("mm", "MM");
javaFormat = javaFormat.replace("dd", "DD");
if (this.isDateFormat) {
this.jformat = new SimpleDateFormat(javaFormat);
} else {
this.jformat = new DecimalFormat(javaFormat);
}
}
return this.jformat.format(txt);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ooxml/XLSXSheet.java
New file
0,0 → 1,261
/*
* 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.ooxml;
 
import org.openconcerto.utils.StringInputStream;
import org.openconcerto.utils.StringUtils;
 
import java.awt.Point;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
 
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
 
import com.ibm.icu.math.BigDecimal;
 
public class XLSXSheet {
private int columnCount;
private int startX;
private int startY;
private int endX;
private int endY;
private static final String MINCELL = "\\$?([A-Z]+)\\$?([0-9]+)";
private static final Pattern minCellPattern = Pattern.compile(MINCELL);
private final List<List<Object>> rows;
private String id;
private String rId;
private String name;
 
public XLSXSheet(XLSXDocument document, String id, String rId, String name, String xml) throws IOException, ParserConfigurationException, SAXException {
this.id = id;
this.rId = rId;
this.name = name;
 
final DocumentBuilder dBuilder = document.getDbFactory().newDocumentBuilder();
final Document doc = dBuilder.parse(new StringInputStream(xml, StandardCharsets.UTF_8.name()));
doc.getDocumentElement().normalize();
 
final NodeList nList = doc.getElementsByTagName("dimension");
final String dimension = nList.item(0).getAttributes().getNamedItem("ref").getNodeValue();
final List<String> parts = StringUtils.fastSplit(dimension, ':');
 
final Point start = resolve(parts.get(0));
this.startX = start.x;
this.startY = start.y;
 
final Point end = resolve(parts.get(1));
this.endX = end.x;
this.endY = end.y;
this.rows = new ArrayList<>(end.y - start.y);
this.columnCount = this.endX - this.startX + 1;
 
for (int i = start.y; i <= end.y; i++) {
List<Object> row = new ArrayList<>();
for (int j = 0; j < this.columnCount; j++) {
row.add(null);
}
this.rows.add(row);
}
Calendar calendar = Calendar.getInstance();
NodeList nListRows = doc.getElementsByTagName("row");
int l1 = nListRows.getLength();
for (int i = 0; i < l1; i++) {
Node r = nListRows.item(i);
NodeList nListCells = r.getChildNodes();
int l2 = nListCells.getLength();
for (int j = 0; j < l2; j++) {
Node c = nListCells.item(j);
final String location = c.getAttributes().getNamedItem("r").getNodeValue();
final Point p = resolve(location);
if (p == null) {
throw new IllegalStateException("unable to parse location : " + location);
}
// The index of this cell's style. Style records are stored in the Styles Part.
// The possible values for this attribute are defined by the W3C XML Schema
// unsignedInt datatype.
int style = 0;
if (c.getAttributes().getNamedItem("s") != null) {
style = Integer.parseInt(c.getAttributes().getNamedItem("s").getNodeValue());
}
// An enumeration representing the cell's data type.
// The possible values for this attribute are defined by the ST_CellType simple type
// (§18.18.11):
// "b" boolean
// "d" ISO 8601 date
// "n" number
// "e" error
// "s" strin
// "str" formula
// "inlineStr" the cell value is in the is element rather than the v
// element in the cell
String type = "n";
if (c.getAttributes().getNamedItem("t") != null) {
type = c.getAttributes().getNamedItem("t").getNodeValue();
}
NodeList nListCellParts = c.getChildNodes();
int l3 = nListCellParts.getLength();
for (int k = 0; k < l3; k++) {
Node part = nListCellParts.item(k);
if (part.getNodeName().equals("v")) {
String value = part.getTextContent();
Object cellValue = null;
if (type.equals("n")) {
final XLSXFormat format = document.getFormatFromStyle(style);
if (format != null) {
if (format.isDateFormat()) {
cellValue = stringToDate(calendar, value);
} else {
cellValue = new BigDecimal(value);
}
} else {
cellValue = new BigDecimal(value);
}
} else if (type.equals("s")) {
cellValue = document.getSharedString(Integer.parseInt(value));
}
this.rows.get(p.y - this.startY).set(p.x - this.startX, cellValue);
}
}
 
}
}
}
 
public Object getValueAt(int col, int row) {
return this.rows.get(row).get(col);
}
 
public int getColumnCount() {
return this.columnCount;
}
 
public int getRowCount() {
return this.rows.size();
}
 
/**
* Convert string coordinates into numeric ones.
*
* @param ref the string address, eg "$AA$34" or "AA34".
* @return the numeric coordinates or <code>null</code> if <code>ref</code> is not valid, eg
* {26, 33}.
*/
static final Point resolve(String ref) {
final Matcher matcher = minCellPattern.matcher(ref);
if (!matcher.matches())
return null;
return resolve(matcher.group(1), matcher.group(2));
}
 
/**
* Convert string coordinates into numeric ones. ATTN this method does no checks.
*
* @param letters the column, eg "AA".
* @param digits the row, eg "34".
* @return the numeric coordinates, eg {26, 33}.
*/
static final Point resolve(final String letters, final String digits) {
return new Point(toInt(letters), Integer.parseInt(digits) - 1);
}
 
// "AA" => 26
static final int toInt(String col) {
if (col.length() < 1)
throw new IllegalArgumentException("x cannot be empty");
col = col.toUpperCase();
 
int x = 0;
for (int i = 0; i < col.length(); i++) {
x = x * 26 + (col.charAt(i) - 'A' + 1);
}
 
// zero based
return x - 1;
}
 
public static final String toStr(int col) {
if (col < 0)
throw new IllegalArgumentException("negative column : " + col);
// one based (i.e. 0 is A)
col++;
 
final int radix = 26;
final StringBuilder chars = new StringBuilder(4);
while (col > 0) {
chars.append((char) ('A' + ((col - 1) % radix)));
col = (col - 1) / radix;
}
 
return chars.reverse().toString();
}
 
/**
* Convert numeric coordinates into string ones.
*
* @param p the numeric coordinates, e.g. {26, 33}.
* @return the string address, e.g. "AA34".
*/
static final String getAddress(Point p) {
if (p.x < 0 || p.y < 0)
throw new IllegalArgumentException("negative coordinates : " + p);
return toStr(p.x) + (p.y + 1);
}
 
public String getId() {
return this.id;
}
 
public static Date stringToDate(Calendar c, String d) {
c.clear();
c.set(1900, 0, 0);
c.add(Calendar.DAY_OF_YEAR, Integer.parseInt(d) - 1);
return c.getTime();
}
 
public int getStartX() {
return this.startX;
}
 
public int getStartY() {
return this.startY;
}
 
public int getEndX() {
return this.endX;
}
 
public int getEndY() {
return this.endY;
}
 
public String getName() {
return this.name;
}
 
public String getRId() {
return this.rId;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ProductInfo.java
14,6 → 14,9
package org.openconcerto.utils;
 
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Properties;
 
157,6 → 160,12
return this.getProperty(VERSION);
}
 
public final void store(final Path p) throws IOException {
try (final OutputStream out = Files.newOutputStream(p)) {
this.getProps().store(out, this.getClass().getName());
}
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " for " + getName() + " " + getVersion();
/trunk/OpenConcerto/src/org/openconcerto/utils/NetUtils.java
22,11 → 22,17
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
 
public class NetUtils {
 
125,6 → 131,10
}
};
 
public static final String getHTTPContent(String address) {
return getHTTPContent(address, false);
}
 
public static final String getHTTPContent(String address, final boolean dontVerify) {
String content = "";
OutputStream out = null;
167,4 → 177,23
 
return content;
}
 
// Create a trust manager that does not validate certificate chains
static private final TrustManager[] TRUSTALL_MANAGERS = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
 
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
 
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
 
static public final SSLContext createTrustAllContext() throws KeyManagementException, NoSuchAlgorithmException {
final SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, TRUSTALL_MANAGERS, new java.security.SecureRandom());
return sc;
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLDecoderStAX.java
New file
0,0 → 1,99
/*
* 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.xml;
 
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
 
/**
* To decode using {@link XMLStreamReader}.
*
* @author Sylvain CUAZ
*/
public final class XMLDecoderStAX extends AbstractXMLDecoder<XMLStreamReader, XMLStreamException> {
 
@Override
protected String getAttributeValue(XMLStreamReader elem, String attrName) {
return elem.getAttributeValue(null, attrName);
}
 
@Override
protected String getLocalName(XMLStreamReader elem) {
return elem.getLocalName();
}
 
@Override
protected String getElementText(XMLStreamReader elem) throws XMLStreamException {
return elem.getElementText();
}
 
@Override
protected XMLStreamReader getFirstChild(XMLStreamReader reader) {
try {
reader.nextTag();
} catch (XMLStreamException e) {
throw new IllegalStateException("Couldn't advance to first child", e);
}
return reader;
}
 
@Override
protected void preEval(XMLStreamReader reader) throws XMLStreamException {
assert reader.isStartElement();
}
 
@Override
protected void nullDecoded(XMLStreamReader reader) throws XMLStreamException {
reader.nextTag();
}
 
@Override
protected void idRefDecoded(XMLStreamReader reader) throws XMLStreamException {
reader.nextTag();
}
 
@Override
protected void postEval(XMLStreamReader reader, final Object res) throws XMLStreamException {
assert reader.isEndElement();
reader.nextTag();
}
 
@Override
protected String toString(XMLStreamReader elem) {
return elem.getLocation().toString();
}
 
@Override
protected Children<XMLStreamReader> createChildren(final XMLStreamReader reader) throws XMLStreamException {
if (!reader.isStartElement())
throw new IllegalStateException("Not at a start of an element : " + reader.getLocation());
final String localName = reader.getLocalName();
// move from START parent to either :
// 1. END parent if no children, or
// 2. START child
reader.nextTag();
return new Children<XMLStreamReader>() {
@Override
public XMLStreamReader getNextChild() {
if (reader.isEndElement() && reader.getLocalName().equals(localName)) {
return null;
}
return reader;
}
};
}
 
protected XMLDecoderStAX() {
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/FastXMLProperties.java
New file
0,0 → 1,71
/*
* 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.xml;
 
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Properties;
 
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.input.sax.XMLReaderSAX2Factory;
 
public class FastXMLProperties {
 
public static void load(Properties props, InputStream in) throws IOException {
final SAXBuilder builder = new SAXBuilder(new XMLReaderSAX2Factory(false, "com.bluecast.xml.Piccolo"), null, null);
try {
final Document document = builder.build(new BufferedInputStream(in));
for (Element element : document.getRootElement().getChildren()) {
if (element.getName().equals("entry")) {
props.setProperty(element.getAttributeValue("key"), element.getText());
}
}
} catch (Exception e) {
throw new IOException(e);
}
 
}
 
/**
* Fast alternative (<1ms) for Properties.storeToXML (30ms)
*
*/
public static void store(Properties props, OutputStream out, String comment) throws IOException {
PrintStream prt = new PrintStream(out, false, "UTF-8");
prt.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n");
prt.append("<properties>\\r\n");
if (comment != null) {
prt.append("<comment>");
prt.append(comment);
prt.append("</comment>\\r\n");
}
synchronized (props) {
for (String k : props.stringPropertyNames()) {
prt.append("<entry key=\"");
prt.append(XMLUtils.escapeAttribute(k));
prt.append("\">");
prt.append(XMLUtils.escapeText(props.getProperty(k)));
prt.append("</entry>\\r\n");
}
}
prt.append("</properties>");
prt.close();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLDecoderJDOM.java
New file
0,0 → 1,74
/*
* 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.xml;
 
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.util.Iterator;
 
import org.jdom2.Element;
 
/**
* To encode and decode using {@link XMLEncoder} and {@link XMLDecoder}.
*
* @author Sylvain CUAZ
*/
public final class XMLDecoderJDOM extends AbstractXMLDecoder<Element, RuntimeException> {
 
@Override
protected String getAttributeValue(Element elem, String attrName) {
return elem.getAttributeValue(attrName);
}
 
@Override
protected String getLocalName(Element elem) {
return elem.getName();
}
 
@Override
protected String getElementText(Element elem) {
return elem.getText();
}
 
@Override
protected Element getFirstChild(Element elem) {
return elem.getChildren().get(0);
}
 
@Override
protected String toString(Element elem) {
return JDOM2Utils.output(elem);
}
 
@Override
protected Children<Element> createChildren(final Element elem) {
return new Children<Element>() {
 
private final Iterator<Element> iter = elem.getChildren().iterator();
 
@Override
public Element getNextChild() {
if (!this.iter.hasNext())
return null;
 
final Element res = this.iter.next();
assert res != null;
return res;
}
};
}
 
protected XMLDecoderJDOM() {
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/AbstractXMLDecoder.java
New file
0,0 → 1,381
/*
* 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.xml;
 
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICache;
import org.openconcerto.utils.cc.ExnTransformer;
 
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
 
/**
* To decode XML in {@link XMLEncoder} format.
*
* @author Sylvain CUAZ
* @param <S> type of source
* @param <E> type of exception
*/
public abstract class AbstractXMLDecoder<S, E extends Exception> {
 
protected static interface Children<C> {
C getNextChild();
}
 
private static final ICache<Object, Method, Object> cache = new ICache<Object, Method, Object>(60, -1, "methods for " + XMLCodecUtils.class);
private static final ICache<Object, Constructor<?>, Object> cacheCtor = new ICache<Object, Constructor<?>, Object>(60, -1, "constructors for " + XMLCodecUtils.class);
 
protected abstract String getLocalName(S elem);
 
protected abstract String getAttributeValue(S elem, final String attrName);
 
protected abstract String getElementText(S elem) throws E;
 
protected abstract S getFirstChild(S elem);
 
protected abstract String toString(S elem);
 
protected abstract Children<S> createChildren(S elem) throws E;
 
public final <K, V> Map<K, V> decodeFromArray(final S elem, final Class<K> keyClass, final Class<V> valueClass) {
return XMLCodecUtils.decodeFromArray((Object[]) this.decode1(elem), keyClass, valueClass);
}
 
/**
* Tries to decode an xml element parsed from a string obtained from XMLEncoder. This doesn't
* use {@link XMLDecoder} as it requires outputting it first to string which is inefficient.
* NOTE: this decoder supports only a subset of XMLDecoder.
*
* @param javaElem a "java" element.
* @return the decoded object.
*/
public final Object decode1(S javaElem) {
final S elem = getFirstChild(javaElem);
try {
return eval(elem, new Stack<Object>(), new HashMap<String, Object>());
} catch (Exception e) {
throw new IllegalStateException("error decoding " + toString(javaElem), e);
}
}
 
private final Object eval(S elem, Stack<Object> context, final Map<String, Object> ids)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, E {
preEval(elem);
final Object res = this._eval(elem, context, ids);
postEval(elem, res);
return res;
}
 
protected void preEval(S elem) throws E {
}
 
protected void nullDecoded(S elem) throws E {
}
 
protected void idRefDecoded(S elem) throws E {
}
 
protected void postEval(S elem, final Object res) throws E {
}
 
private final Object _eval(S elem, Stack<Object> context, final Map<String, Object> ids)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, E {
final String n = getLocalName(elem);
// Ordered from real world scenario
// string : 80k
// void : 53k
// int : 18k
// object : 9k
// null : 6k
switch (n) {
case "string":
return getElementText(elem);
case "void":
case "object":
final String idref = getAttributeValue(elem, "idref");
if (idref != null) {
if (!ids.containsKey(idref))
throw new IllegalStateException("id '" + idref + "' wasn't defined");
idRefDecoded(elem);
return ids.get(idref);
}
final String id = getAttributeValue(elem, "id");
final String targetClass = getAttributeValue(elem, "class");
final Object target = targetClass == null ? context.peek() : Class.forName(targetClass);
final String propAttr = getAttributeValue(elem, "property");
final String indexAttr = getAttributeValue(elem, "index");
final String methodAttr = getAttributeValue(elem, "method");
 
// statement or expression
final Object res = evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, Exception>() {
@Override
public Object transformChecked(List<Object> args) throws Exception {
// call the statement
final Object res;
 
if (propAttr != null) {
final String methodName = (args.size() == 0 ? "get" : "set") + StringUtils.firstUp(propAttr);
res = invoke(target, methodName, args);
} else if (indexAttr != null) {
final String methodName;
if (target instanceof List) {
methodName = args.size() == 0 ? "get" : "set";
// get(index) or set(index, value)
args.add(0, Integer.valueOf(indexAttr));
res = invoke(target, methodName, args);
} else if (target.getClass().isArray()) {
final Class<?> componentType = target.getClass().getComponentType();
// in Array there's set(array, int index, Object value) or
// setPrimitive(array, int index, primitive value)
methodName = (args.size() == 0 ? "get" : "set") + (componentType.isPrimitive() ? StringUtils.firstUp(componentType.getSimpleName()) : "");
args.add(0, target);
args.add(1, Integer.valueOf(indexAttr));
res = invoke(Array.class, methodName, args);
} else
throw new IllegalStateException("use index with neither List nor array: " + target);
} else if (methodAttr != null) {
res = invoke(target, methodAttr, args);
} else
res = getCtor((Class<?>) target, args).newInstance(args.toArray());
return res;
}
});
// not very functional but it works
if (id != null)
ids.put(id, res);
return res;
case "int":
return Integer.valueOf(getElementText(elem));
case "null":
nullDecoded(elem);
return null;
case "boolean":
return Boolean.valueOf(getElementText(elem));
case "byte":
return Byte.valueOf(getElementText(elem));
case "char":
return Character.valueOf(getElementText(elem).charAt(0));
case "short":
return Short.valueOf(getElementText(elem));
case "long":
return Long.valueOf(getElementText(elem));
case "float":
return Float.valueOf(getElementText(elem));
case "double":
return Double.valueOf(getElementText(elem));
case "array":
final String classAttr = getAttributeValue(elem, "class");
final String lengthAttr = getAttributeValue(elem, "length");
 
final Class<?> componentClass = parseClassName(classAttr);
if (lengthAttr != null) {
context.push(Array.newInstance(componentClass, Integer.parseInt(lengthAttr)));
final Children<S> children = createChildren(elem);
S child;
while ((child = children.getNextChild()) != null) {
eval(child, context, ids);
}
return context.pop();
} else {
final List<Object> items = new LinkedList<>();
final Children<S> children = createChildren(elem);
S child;
while ((child = children.getNextChild()) != null) {
items.add(eval(child, context, ids));
}
final Object resArray = Array.newInstance(componentClass, items.size());
int i = 0;
for (final Object item : items)
Array.set(resArray, i++, item);
return resArray;
}
case "class":
return Class.forName(getElementText(elem));
default:
throw new UnsupportedOperationException("doesn't yet support " + n);
}
}
 
private final Object evalContainer(final S parent, Stack<Object> context, final Map<String, Object> ids, final ExnTransformer<List<Object>, Object, ? extends Exception> transf)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, E {
final List<Object> args = new ArrayList<Object>();
final Children<S> children = createChildren(parent);
boolean noVoid = true;
S child = null;
while (noVoid && (child = children.getNextChild()) != null) {
if (getLocalName(child).equals("void"))
noVoid = false;
else {
args.add(eval(child, context, ids));
}
}
 
// call the statement
final Object res = transf.transformCheckedWithExn(args, false, InvocationTargetException.class, InstantiationException.class, IllegalAccessException.class);
 
context.push(res);
 
// now call the voids
if (child != null) {
do {
eval(child, context, ids);
} while ((child = children.getNextChild()) != null);
}
return context.pop();
}
 
private static final Object invoke(final Object target, String methodName, final List<Object> args) throws IllegalAccessException, InvocationTargetException {
// <object class="Cell" method="createEmpty" >
// for static methods the target is already a class
final Class clazz = target instanceof Class ? (Class) target : target.getClass();
final Method m = getMethod(clazz, methodName, args);
return m.invoke(target, args.toArray());
}
 
private static final Method getMethod(Class<?> clazz, String name, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(name);
key.add(actualClasses);
 
final CacheResult<Method> cacheRes = cache.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Method res = findMethod(clazz, name, actualClasses);
if (res == null)
throw new IllegalStateException("No matching method " + name + " found in " + clazz);
cache.put(key, res);
return res;
}
 
private static final Constructor getCtor(Class<?> clazz, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(actualClasses);
 
final CacheResult<Constructor<?>> cacheRes = cacheCtor.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Constructor res = findCtor(clazz, actualClasses);
cacheCtor.put(key, res);
return res;
}
 
private static final List<Class<?>> objectsToClasses(List<Object> actualArgs) {
final List<Class<?>> actualClasses = new ArrayList<Class<?>>(actualArgs.size());
for (final Object actualArg : actualArgs)
actualClasses.add(actualArg == null ? null : actualArg.getClass());
return actualClasses;
}
 
// TODO return the most specific matching method instead of the first one
// (handle both Sub/Superclass and primitive/object type)
private static final Method findMethod(Class<?> clazz, String name, List<Class<?>> actualArgs) {
for (final Method m : clazz.getMethods()) {
if (m.getName().equals(name) && callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
// TODO see findMethod()
private static final Constructor findCtor(Class<?> clazz, List<Class<?>> actualArgs) {
for (final Constructor m : clazz.getConstructors()) {
if (callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
private static final boolean callableWith(Class<?>[] formalArgs, List<Class<?>> actualArgs) {
if (formalArgs.length != actualArgs.size())
return false;
int i = 0;
for (final Class<?> argClass : formalArgs) {
final Class<?> actualArg = actualArgs.get(i);
// null match everything
if (actualArg != null && !argClass.isAssignableFrom(actualArg) && argClass != getPrimitive(actualArg))
return false;
i++;
}
 
return true;
}
 
private static Class<?> getPrimitive(Class<?> argClass) {
if (argClass == Boolean.class)
return Boolean.TYPE;
else if (argClass == Character.class)
return Character.TYPE;
else if (argClass == Byte.class)
return Byte.TYPE;
else if (argClass == Short.class)
return Short.TYPE;
else if (argClass == Integer.class)
return Integer.TYPE;
else if (argClass == Long.class)
return Long.TYPE;
else if (argClass == Float.class)
return Float.TYPE;
else if (argClass == Double.class)
return Double.TYPE;
else
return null;
}
 
private static final Map<String, Class> primitiveNames = new HashMap<String, Class>();
 
static {
primitiveNames.put("boolean", boolean.class);
primitiveNames.put("byte", byte.class);
primitiveNames.put("char", char.class);
primitiveNames.put("short", short.class);
primitiveNames.put("int", int.class);
primitiveNames.put("long", long.class);
primitiveNames.put("float", float.class);
primitiveNames.put("double", double.class);
}
 
/**
* Parse class names (including primitive).
*
* @param className a class name, eg "java.lang.String" or "int".
* @return the matching class, eg java.lang.String.class or Integer.TYPE.
* @throws ClassNotFoundException if the passed name doesn't exist.
*/
private static Class<?> parseClassName(String className) throws ClassNotFoundException {
final Class<?> primitive = primitiveNames.get(className);
if (primitive != null)
return primitive;
else
return Class.forName(className);
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLCodecUtils.java
13,11 → 13,6
package org.openconcerto.xml;
 
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICache;
import org.openconcerto.utils.cc.ExnTransformer;
 
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
35,11 → 30,8
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
47,7 → 39,6
import java.util.Map.Entry;
import java.util.RandomAccess;
import java.util.Set;
import java.util.Stack;
 
import org.jdom2.Element;
import org.jdom2.JDOMException;
62,9 → 53,6
 
private static final String END_DECL = "?>";
 
private static final ICache<Object, Method, Object> cache = new ICache<Object, Method, Object>(60, -1, "methods for " + XMLCodecUtils.class);
private static final ICache<Object, Constructor<?>, Object> cacheCtor = new ICache<Object, Constructor<?>, Object>(60, -1, "constructors for " + XMLCodecUtils.class);
 
// the same as XMLEncoder
private static final Charset CS = Charset.forName("UTF-8");
 
85,6 → 73,9
}
};
 
public static final XMLDecoderJDOM XML_DECODER_JDOM = new XMLDecoderJDOM();
public static final XMLDecoderStAX XML_DECODER_STAX = new XMLDecoderStAX();
 
/**
* Register a {@link PersistenceDelegate} for the passed class. This method tries to set
* <code>del</code> as the default for any subsequent {@link Encoder}, but with the current JRE
130,7 → 121,46
return res;
}
 
public static final String encodeAsArray(final Map<?, ?> m) {
return encodeAsArray(m, new StringBuilder(1024)).toString();
}
 
/**
* Encode a map as an array. Useful since parsing an array is faster than parsing a map.
*
* @param m the map to encode.
* @param sb where to encode.
* @return <code>sb</code>.
* @see AbstractXMLDecoder#decodeFromArray(Object, Class, Class)
*/
public static final StringBuilder encodeAsArray(final Map<?, ?> m, final StringBuilder sb) {
final Object[] array = new Object[m.size() * 2];
int i = 0;
for (final Entry<?, ?> e : m.entrySet()) {
array[i++] = e.getKey();
array[i++] = e.getValue();
}
assert i == array.length;
return encodeSimple(array, sb);
}
 
public static final <K, V> Map<K, V> decodeFromArray(final Object[] array, final Class<K> keyClass, final Class<V> valueClass) {
return decodeFromArray(array, keyClass, valueClass, null);
}
 
public static final <K, V> Map<K, V> decodeFromArray(final Object[] array, final Class<K> keyClass, final Class<V> valueClass, Map<K, V> m) {
final int l = array.length;
if (m == null)
m = new HashMap<K, V>((int) (l / 2 / 0.8f) + 1, 0.8f);
for (int i = 0; i < l; i += 2) {
final K key = keyClass.cast(array[i]);
final V value = valueClass.cast(array[i + 1]);
m.put(key, value);
}
return m;
}
 
/**
* Encodes an object using {@link XMLEncoder}, stripping the XML declaration.
*
* @param o the object to encode.
153,10 → 183,14
*/
public static final String encodeSimple(Object o) {
final StringBuilder sb = new StringBuilder(256);
return encodeSimple(o, sb).toString();
}
 
public static final StringBuilder encodeSimple(final Object o, final StringBuilder sb) {
sb.append("<java version=\"1.6.0\" class=\"java.beans.XMLDecoder\">");
encodeSimpleRec(o, sb);
sb.append("</java>");
return sb.toString();
return sb;
}
 
private static final void createElemEscaped(final String elemName, final Object o, final StringBuilder sb) {
361,287 → 395,9
* @return the decoded object.
*/
public static final Object decode1(Element javaElem) {
final Element elem = (Element) javaElem.getChildren().get(0);
try {
return eval(elem, new Stack<Object>(), new HashMap<String, Object>());
} catch (Exception e) {
throw new IllegalStateException("error decoding " + JDOM2Utils.output(javaElem), e);
return XML_DECODER_JDOM.decode1(javaElem);
}
}
 
private static final Object eval(Element elem, Stack<Object> context, final Map<String, Object> ids)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
final String n = elem.getName();
// Ordered from real world scenario
// string : 80k
// void : 53k
// int : 18k
// object : 9k
// null : 6k
if (n.equals("string")) {
return elem.getText();
} else if (n.equals("void") || n.equals("object")) {
final String idref = elem.getAttributeValue("idref");
if (idref != null) {
if (!ids.containsKey(idref))
throw new IllegalStateException("id '" + idref + "' wasn't defined");
return ids.get(idref);
}
final String id = elem.getAttributeValue("id");
final String targetClass = elem.getAttributeValue("class");
final Object target = targetClass == null ? context.peek() : Class.forName(targetClass);
final String propAttr = elem.getAttributeValue("property");
final String indexAttr = elem.getAttributeValue("index");
final String methodAttr = elem.getAttributeValue("method");
 
// statement or expression
final Object res = evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, Exception>() {
@Override
public Object transformChecked(List<Object> args) throws Exception {
// call the statement
final Object res;
 
if (propAttr != null) {
final String methodName = (args.size() == 0 ? "get" : "set") + StringUtils.firstUp(propAttr);
res = invoke(target, methodName, args);
} else if (indexAttr != null) {
final String methodName;
if (target instanceof List) {
methodName = args.size() == 0 ? "get" : "set";
// get(index) or set(index, value)
args.add(0, Integer.valueOf(indexAttr));
res = invoke(target, methodName, args);
} else if (target.getClass().isArray()) {
final Class<?> componentType = target.getClass().getComponentType();
// in Array there's set(array, int index, Object value) or
// setPrimitive(array, int index, primitive value)
methodName = (args.size() == 0 ? "get" : "set") + (componentType.isPrimitive() ? StringUtils.firstUp(componentType.getSimpleName()) : "");
args.add(0, target);
args.add(1, Integer.valueOf(indexAttr));
res = invoke(Array.class, methodName, args);
} else
throw new IllegalStateException("use index with neither List nor array: " + target);
} else if (methodAttr != null) {
res = invoke(target, methodAttr, args);
} else
res = getCtor((Class<?>) target, args).newInstance(args.toArray());
return res;
}
});
// not very functional but it works
if (id != null)
ids.put(id, res);
return res;
} else if (n.equals("int")) {
return Integer.valueOf(elem.getText());
} else if (n.equals("null")) {
return null;
} else if (n.equals("boolean")) {
return Boolean.valueOf(elem.getText());
} else if (n.equals("byte")) {
return Byte.valueOf(elem.getText());
} else if (n.equals("char")) {
return Character.valueOf(elem.getText().charAt(0));
} else if (n.equals("short")) {
return Short.valueOf(elem.getText());
} else if (n.equals("long")) {
return Long.valueOf(elem.getText());
} else if (n.equals("float")) {
return Float.valueOf(elem.getText());
} else if (n.equals("double")) {
return Double.valueOf(elem.getText());
} else if (n.equals("array")) {
final String classAttr = elem.getAttributeValue("class");
final String lengthAttr = elem.getAttributeValue("length");
 
final Class<?> componentClass = parseClassName(classAttr);
if (lengthAttr != null) {
context.push(Array.newInstance(componentClass, Integer.parseInt(lengthAttr)));
for (final Object child : elem.getChildren()) {
eval((Element) child, context, ids);
}
return context.pop();
} else {
return evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, RuntimeException>() {
@Override
public Object transformChecked(List<Object> args) {
final Object res = Array.newInstance(componentClass, args.size());
for (int j = 0; j < args.size(); j++) {
Array.set(res, j, args.get(j));
}
return res;
}
});
}
} else if (n.equals("class")) {
return Class.forName(elem.getText());
} else
throw new UnsupportedOperationException("doesn't yet support " + n);
}
 
private static final Object evalContainer(final Element parent, Stack<Object> context, final Map<String, Object> ids, final ExnTransformer<List<Object>, Object, ? extends Exception> transf)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
final List<Object> args = new ArrayList<Object>();
final List<?> children = parent.getChildren();
int i = 0;
boolean noVoid = true;
final int size = children.size();
while (i < size && noVoid) {
final Element child = (Element) children.get(i);
if (child.getName().equals("void"))
noVoid = false;
else {
args.add(eval(child, context, ids));
i++;
}
}
 
// call the statement
final Object res = transf.transformCheckedWithExn(args, false, InvocationTargetException.class, InstantiationException.class, IllegalAccessException.class);
 
context.push(res);
 
// now call the voids
while (i < children.size()) {
final Element child = (Element) children.get(i);
eval(child, context, ids);
i++;
}
return context.pop();
}
 
private static final Object invoke(final Object target, String methodName, final List<Object> args) throws IllegalAccessException, InvocationTargetException {
// <object class="Cell" method="createEmpty" >
// for static methods the target is already a class
final Class clazz = target instanceof Class ? (Class) target : target.getClass();
final Method m = getMethod(clazz, methodName, args);
return m.invoke(target, args.toArray());
}
 
private static final Method getMethod(Class<?> clazz, String name, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(name);
key.add(actualClasses);
 
final CacheResult<Method> cacheRes = cache.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Method res = findMethod(clazz, name, actualClasses);
cache.put(key, res);
return res;
}
 
private static final Constructor getCtor(Class<?> clazz, List<Object> actualArgs) {
final List<Class<?>> actualClasses = objectsToClasses(actualArgs);
final List<Object> key = new ArrayList<Object>(3);
key.add(clazz);
key.add(actualClasses);
 
final CacheResult<Constructor<?>> cacheRes = cacheCtor.check(key);
if (cacheRes.getState() == CacheResult.State.VALID)
return cacheRes.getRes();
 
final Constructor res = findCtor(clazz, actualClasses);
cacheCtor.put(key, res);
return res;
}
 
private static final List<Class<?>> objectsToClasses(List<Object> actualArgs) {
final List<Class<?>> actualClasses = new ArrayList<Class<?>>(actualArgs.size());
for (final Object actualArg : actualArgs)
actualClasses.add(actualArg == null ? null : actualArg.getClass());
return actualClasses;
}
 
// TODO return the most specific matching method instead of the first one
// (handle both Sub/Superclass and primitive/object type)
private static final Method findMethod(Class<?> clazz, String name, List<Class<?>> actualArgs) {
for (final Method m : clazz.getMethods()) {
if (m.getName().equals(name) && callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
// TODO see findMethod()
private static final Constructor findCtor(Class<?> clazz, List<Class<?>> actualArgs) {
for (final Constructor m : clazz.getConstructors()) {
if (callableWith(m.getParameterTypes(), actualArgs)) {
return m;
}
}
return null;
}
 
private static final boolean callableWith(Class<?>[] formalArgs, List<Class<?>> actualArgs) {
if (formalArgs.length != actualArgs.size())
return false;
int i = 0;
for (final Class<?> argClass : formalArgs) {
final Class<?> actualArg = actualArgs.get(i);
// null match everything
if (actualArg != null && !argClass.isAssignableFrom(actualArg) && argClass != getPrimitive(actualArg))
return false;
i++;
}
 
return true;
}
 
private static Class<?> getPrimitive(Class<?> argClass) {
if (argClass == Boolean.class)
return Boolean.TYPE;
else if (argClass == Character.class)
return Character.TYPE;
else if (argClass == Byte.class)
return Byte.TYPE;
else if (argClass == Short.class)
return Short.TYPE;
else if (argClass == Integer.class)
return Integer.TYPE;
else if (argClass == Long.class)
return Long.TYPE;
else if (argClass == Float.class)
return Float.TYPE;
else if (argClass == Double.class)
return Double.TYPE;
else
return null;
}
 
private static final Map<String, Class> primitiveNames = new HashMap<String, Class>();
 
static {
primitiveNames.put("boolean", boolean.class);
primitiveNames.put("byte", byte.class);
primitiveNames.put("char", char.class);
primitiveNames.put("short", short.class);
primitiveNames.put("int", int.class);
primitiveNames.put("long", long.class);
primitiveNames.put("float", float.class);
primitiveNames.put("double", double.class);
}
 
/**
* Parse class names (including primitive).
*
* @param className a class name, eg "java.lang.String" or "int".
* @return the matching class, eg java.lang.String.class or Integer.TYPE.
* @throws ClassNotFoundException if the passed name doesn't exist.
*/
private static Class<?> parseClassName(String className) throws ClassNotFoundException {
final Class<?> primitive = primitiveNames.get(className);
if (primitive != null)
return primitive;
else
return Class.forName(className);
}
 
private XMLCodecUtils() {
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLUtils.java
New file
0,0 → 1,133
/*
* 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.xml;
 
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
 
public class XMLUtils {
 
public static final String escapeAttribute(final String value) {
final int len = value.length();
int idx = 0;
 
checkloop: while (idx < len) {
final char ch = value.charAt(idx);
if (ch == '<' || ch == '>' || ch == '&' || ch == '\r' || ch == '\n' || ch == '"' || ch == '\t') {
break checkloop;
}
idx++;
}
 
if (idx == len) {
return value;
}
 
final StringBuilder sb = new StringBuilder(len + 5);
sb.append(value, 0, idx);
while (idx < len) {
final char ch = value.charAt(idx++);
switch (ch) {
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '&':
sb.append("&amp;");
break;
case '\r':
sb.append("&#xD;");
break;
case '"':
sb.append("&quot;");
break;
case '\t':
sb.append("&#x9;");
break;
case '\n':
sb.append("&#xA;");
break;
default:
sb.append(ch);
break;
}
}
 
return sb.toString();
}
 
public static final String escapeText(final String value) {
final int right = value.length();
int idx = 0;
checkloop: while (idx < right) {
final char ch = value.charAt(idx);
if (ch == '<' || ch == '>' || ch == '&' || ch == '\r' || ch == '\n') {
break checkloop;
}
idx++;
}
 
if (idx == right) {
// no escape needed.
return value;
}
 
final StringBuilder sb = new StringBuilder();
if (idx > 0) {
sb.append(value, 0, idx);
}
 
while (idx < right) {
final char ch = value.charAt(idx++);
switch (ch) {
case '<':
sb.append("&lt;");
break;
case '>':
sb.append("&gt;");
break;
case '&':
sb.append("&amp;");
break;
case '\r':
sb.append("&#xD;");
break;
case '\n':
sb.append('\n');
break;
default:
sb.append(ch);
break;
}
}
return sb.toString();
}
 
public static final void skipToEndElement(final XMLStreamReader reader) throws XMLStreamException {
if (!reader.isStartElement())
throw new IllegalStateException("Not at a start of an element : " + reader.getEventType() + ", " + reader.getLocation());
final String name = reader.getLocalName();
int depth = 1;
while (!(depth == 0 && reader.isEndElement() && reader.getLocalName().equals(name))) {
final int eventType = reader.next();
if (eventType == XMLStreamConstants.START_ELEMENT)
depth++;
else if (eventType == XMLStreamConstants.END_ELEMENT)
depth--;
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/ui/BonDeLivraisonItemTable.java
617,6 → 617,7
if (e.getTable().getFieldsName().contains("ID_ECO_CONTRIBUTION")) {
completionField.add("ID_ECO_CONTRIBUTION");
}
completionField.add("POURCENT_REMISE");
completionField.add("ID_UNITE_VENTE");
completionField.add("QTE_UNITAIRE");
completionField.add("PA_HT");
653,11 → 654,13
protected Object getValueFrom(SQLRow row, String field, SQLRowAccessor rowDest) {
Object res = tarifCompletion(row, field, rowDest, true);
if (res == null) {
return super.getValueFrom(row, field, rowDest);
} else {
res = super.getValueFrom(row, field, rowDest);
}
if (field.equals("POURCENT_REMISE")) {
return getRemiseClient(row);
}
return res;
}
}
};
m.fill("NOM", "NOM");
m.fill("ID", "ID_ARTICLE");
743,11 → 746,13
protected Object getValueFrom(SQLRow row, String field, SQLRowAccessor rowDest) {
Object res = tarifCompletion(row, field, rowDest, true);
if (res == null) {
return super.getValueFrom(row, field, rowDest);
} else {
res = super.getValueFrom(row, field, rowDest);
}
if (field.equals("POURCENT_REMISE")) {
return getRemiseClient(row);
}
return res;
}
}
};
m2.fill("CODE", "CODE");
m2.fill("ID", "ID_ARTICLE");
764,11 → 769,13
protected Object getValueFrom(SQLRow row, String field, SQLRowAccessor rowDest) {
Object res = tarifCompletion(row, field, rowDest, true);
if (res == null) {
return super.getValueFrom(row, field, rowDest);
} else {
res = super.getValueFrom(row, field, rowDest);
}
if (field.equals("POURCENT_REMISE")) {
return getRemiseClient(row);
}
return res;
}
}
};
m3.fill("CODE", "CODE");
m3.fill("NOM", "NOM");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/component/BonDeLivraisonSQLComponent.java
22,6 → 22,7
import org.openconcerto.erp.core.common.ui.TotalPanel;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AddressChoiceUI;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseType;
import org.openconcerto.erp.core.customerrelationship.customer.ui.CategorieComptableChoiceUI;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.sales.invoice.element.SaisieVenteFactureItemSQLElement;
import org.openconcerto.erp.core.sales.product.model.ProductComponent;
40,6 → 41,7
import org.openconcerto.erp.utils.TM;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
50,6 → 52,8
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.sqlobject.JUniqueTextField;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableModel;
105,6 → 109,7
private final JDate date = new JDate(true);
private final boolean displayDpt;
private final ElementComboBox comboDpt = new ElementComboBox();
private ElementComboBox comboCommercial;
 
public BonDeLivraisonSQLComponent() {
super(Configuration.getInstance().getDirectory().getElement("BON_DE_LIVRAISON"));
125,6 → 130,13
if (rowVals == null) {
rowVals = new SQLRowValues(getTable());
}
SQLElement eltComm = getElement().getForeignElement("ID_COMMERCIAL");
int idUser = UserManager.getInstance().getCurrentUser().getId();
SQLRow rowsComm = SQLBackgroundTableCache.getInstance().getCacheForTable(eltComm.getTable()).getFirstRowContains(idUser, eltComm.getTable().getField("ID_USER_COMMON"));
 
if (rowsComm != null) {
rowVals.put("ID_COMMERCIAL", rowsComm.getID());
}
if (getTable().contains("CREATE_VIRTUAL_STOCK")) {
rowVals.put("CREATE_VIRTUAL_STOCK", Boolean.TRUE);
}
307,6 → 319,23
}
});
}
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CATEGORIE_COMPTABLE_SPEC, false)) {
// cat spe
final CategorieComptableChoiceUI catUI = new CategorieComptableChoiceUI();
catUI.addToUI(this, c);
catUI.getCombo().addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
int wantedID = catUI.getCombo().getWantedID();
if (wantedID != SQLRow.NONEXISTANT_ID && wantedID >= SQLRow.MIN_VALID_ID) {
tableBonItem.setRowCatComptable(catUI.getCombo().getElement().getTable().getRow(wantedID));
} else {
tableBonItem.setRowCatComptable(null);
}
}
});
}
if (getTable().contains("SPEC_LIVRAISON")) {
// Date livraison
c.gridx++;
362,14 → 391,37
} else {
tableBonItem.setRowCatComptable(null);
}
if (!isFilling()) {
tableBonItem.setClient(rowClient, true);
}
 
} else {
comboContact.getRequest().setWhere(Where.FALSE);
tableBonItem.setRowCatComptable(null);
if (!isFilling()) {
tableBonItem.setClient(null, true);
}
// DevisSQLComponent.this.table.setTarif(null, false);
}
}
});
 
// Commercial
JLabel labelCommercial = new JLabel(getLabelFor("ID_COMMERCIAL"));
labelCommercial.setHorizontalAlignment(SwingConstants.RIGHT);
 
c.gridx++;
c.weightx = 0;
this.add(labelCommercial, c);
 
this.comboCommercial = new ElementComboBox(false, 25);
this.comboCommercial.setListIconVisible(false);
c.gridx++;
c.fill = GridBagConstraints.NONE;
c.weightx = 1;
this.add(this.comboCommercial, c);
addRequiredSQLObject(this.comboCommercial, "ID_COMMERCIAL");
 
}
 
final ElementComboBox boxTarif = new ElementComboBox();
445,7 → 497,23
tableBonItem.setTarif(selectedRow, !isFilling());
}
});
 
if (getTable().contains("SERVI_PAR")) {
// Commercial
JLabel labelServi = new JLabel("Servi par");
labelServi.setHorizontalAlignment(SwingConstants.RIGHT);
c.gridx++;
c.weightx = 0;
this.add(labelServi, c);
 
SQLTextCombo comboServiPar = new SQLTextCombo();
c.gridx++;
c.fill = GridBagConstraints.NONE;
c.weightx = 1;
this.add(comboServiPar, c);
addRequiredSQLObject(comboServiPar, "SERVI_PAR");
}
}
 
if (getTable().contains("A_ATTENTION")) {
// Date livraison
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/element/BonDeLivraisonItemSQLElement.java
37,6 → 37,7
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_BON_DE_LIVRAISON");
l.add("CODE");
l.add("NOM");
l.add("PA_HT");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/element/BonDeLivraisonSQLElement.java
77,6 → 77,10
final List<String> l = new ArrayList<>();
l.add("NUMERO");
l.add("DATE");
if(getTable().contains("ID_COMMERCIAL")) {
l.add("ID_COMMERCIAL");
}
l.add("ID_CLIENT");
DefaultProps props = DefaultNXProps.getInstance();
Boolean b = props.getBooleanValue("ArticleShowPoids");
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/credit/component/AvoirClientSQLComponent.java
27,6 → 27,7
import org.openconcerto.erp.core.common.ui.TotalPanel;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AddressChoiceUI;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseType;
import org.openconcerto.erp.core.customerrelationship.customer.ui.CategorieComptableChoiceUI;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.EcritureSQLElement;
import org.openconcerto.erp.core.finance.payment.component.ModeDeReglementSQLComponent;
193,6 → 194,9
boxTarif.setValue(foreignRow.getID());
}
}
if (!isFilling()) {
AvoirClientSQLComponent.this.table.setClient(row, true);
}
 
} else {
table.setRowCatComptable(null);
423,7 → 427,25
}
});
}
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CATEGORIE_COMPTABLE_SPEC, false)) {
// cat spe
final CategorieComptableChoiceUI catUI = new CategorieComptableChoiceUI();
catUI.addToUI(this, c);
catUI.getCombo().addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
int wantedID = catUI.getCombo().getWantedID();
if (wantedID != SQLRow.NONEXISTANT_ID && wantedID >= SQLRow.MIN_VALID_ID) {
table.setRowCatComptable(catUI.getCombo().getElement().getTable().getRow(wantedID));
} else {
table.setRowCatComptable(null);
}
}
});
 
}
 
final ComptaPropsConfiguration comptaPropsConfiguration = ((ComptaPropsConfiguration) Configuration.getInstance());
 
// Contact
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/action/ListeDesElementsACommanderClientAction.java
18,6 → 18,7
import org.openconcerto.erp.core.common.ui.IListFilterDatePanel;
import org.openconcerto.erp.core.common.ui.ListeViewPanel;
import org.openconcerto.erp.core.sales.order.element.CommandeClientElementSQLElement;
import org.openconcerto.erp.core.sales.product.ui.QteAcommanderRenderer;
import org.openconcerto.erp.core.supplychain.stock.element.StockSQLElement;
import org.openconcerto.erp.preferences.GestionArticleGlobalPreferencePanel;
import org.openconcerto.sql.element.SQLElement;
124,14 → 125,17
protected Object show_(SQLRowAccessor r) {
 
final SQLRowAccessor foreign = r.getForeign("ID_ARTICLE");
 
if (foreign != null && !foreign.isUndefined()) {
if (foreign.getBoolean("GESTION_STOCK")) {
SQLRowAccessor foreign2 = StockSQLElement.getStockFetched(r);
if (foreign2 != null && !foreign2.isUndefined()) {
return foreign2.getFloat("QTE_REEL");
}
}
return 0F;
}
return null;
}
 
@Override
public Set<FieldPath> getPaths() {
150,13 → 154,16
 
final SQLRowAccessor foreign = r.getForeign("ID_ARTICLE");
if (foreign != null && !foreign.isUndefined()) {
if (foreign.getBoolean("GESTION_STOCK")) {
 
SQLRowAccessor foreign2 = StockSQLElement.getStockFetched(r);
if (foreign2 != null && !foreign2.isUndefined()) {
return foreign2.getFloat("QTE_TH");
}
}
return 0F;
}
return null;
}
 
@Override
public Set<FieldPath> getPaths() {
175,13 → 182,16
 
final SQLRowAccessor foreign = r.getForeign("ID_ARTICLE");
if (foreign != null && !foreign.isUndefined()) {
if (foreign.getBoolean("GESTION_STOCK")) {
 
SQLRowAccessor foreign2 = StockSQLElement.getStockFetched(r);
if (foreign2 != null && !foreign2.isUndefined()) {
return foreign2.getFloat("QTE_MIN");
}
}
return 0F;
}
return null;
}
 
@Override
public Set<FieldPath> getPaths() {
200,6 → 210,8
 
final SQLRowAccessor foreign = r.getForeign("ID_ARTICLE");
if (foreign != null && !foreign.isUndefined()) {
if (foreign.getBoolean("GESTION_STOCK")) {
 
SQLRowAccessor foreign2 = StockSQLElement.getStockFetched(r);
if (foreign2 != null && !foreign2.isUndefined()) {
float qteMin = foreign2.getFloat("QTE_MIN");
206,10 → 218,13
float manque = foreign2.getFloat("QTE_TH") - qteMin;
if (manque < 0) {
return -manque;
} else {
return 0f;
}
}
}
return 0F;
}
return r.getBigDecimal("QTE_UNITAIRE").multiply(new BigDecimal(r.getInt("QTE"))).floatValue();
 
}
 
222,7 → 237,7
}
};
tableSource.getColumns().add(colSug);
// colLiv2.setRenderer(new PercentTableCellRenderer());
colSug.setRenderer(new QteAcommanderRenderer());
 
return tableSource;
}
314,7 → 329,7
@Override
public void actionPerformed(ActionEvent e) {
List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
eltCmd.createCommandeF(selectedRows);
eltCmd.transfertCommande(selectedRows);
}
}, true);
predicateACtion.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/component/CommandeClientSQLComponent.java
23,6 → 23,7
import org.openconcerto.erp.core.common.ui.TotalPanel;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AddressChoiceUI;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseType;
import org.openconcerto.erp.core.customerrelationship.customer.ui.CategorieComptableChoiceUI;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.sales.order.report.CommandeClientXmlSheet;
import org.openconcerto.erp.core.sales.order.ui.CommandeClientItemTable;
255,8 → 256,16
// }
// table.setTarif(foreignRow, true);
}
if (!isFilling()) {
table.setClient(row, true);
}
 
} else {
if (!isFilling()) {
table.setClient(null, true);
}
}
}
 
}
});
393,6 → 402,24
});
}
 
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CATEGORIE_COMPTABLE_SPEC, false)) {
// cat spe
final CategorieComptableChoiceUI catUI = new CategorieComptableChoiceUI();
catUI.addToUI(this, c);
catUI.getCombo().addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
int wantedID = catUI.getCombo().getWantedID();
if (wantedID != SQLRow.NONEXISTANT_ID && wantedID >= SQLRow.MIN_VALID_ID) {
table.setRowCatComptable(catUI.getCombo().getElement().getTable().getRow(wantedID));
} else {
table.setRowCatComptable(null);
}
}
});
}
 
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.ORDER_PACKAGING_MANAGEMENT, true)) {
// Emballage
c.gridy++;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/CommandeClientElementSQLElement.java
16,11 → 16,11
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.erp.core.sales.product.element.UniteVenteArticleSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.MouvementStockSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.StockItemsUpdater;
import org.openconcerto.erp.core.supplychain.stock.element.StockItemsUpdater.TypeStockUpdate;
import org.openconcerto.erp.core.supplychain.stock.element.StockLabel;
import org.openconcerto.erp.core.supplychain.stock.element.StockSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.UISQLComponent;
66,16 → 66,9
 
@Override
public void actionPerformed(ActionEvent e) {
final List<SQLRowValues> selectedRows = IListe.get(e).getSelectedRows();
ComptaPropsConfiguration.getInstanceCompta().getNonInteractiveSQLExecutor().execute(new Runnable() {
 
@Override
public void run() {
 
createCommandeF(selectedRows);
final List<SQLRow> rows = SQLRowListRSH.fetch(IListe.get(e).getRequest().getPrimaryTable(), IListe.get(e).getSelection().getSelectedIDs());
((CommandeClientSQLElement) getForeignElement("ID_COMMANDE_CLIENT")).transfertEltToCommandeF(rows);
}
});
}
 
}, true);
rowAction.setPredicate(IListeEvent.getNonEmptySelectionPredicate());
214,6 → 207,7
l.add("NOM");
l.add("ID_COMMANDE_CLIENT");
l.add("ID_ARTICLE");
l.add("ID_DEPOT_STOCK");
l.add("PA_HT");
l.add("PV_HT");
l.add("T_PA_HT");
234,6 → 228,11
*/
public void transfertCommande(List<SQLRowValues> commandeClientEltsRows) {
 
ComptaPropsConfiguration.getInstanceCompta().getNonInteractiveSQLExecutor().execute(new Runnable() {
 
@Override
public void run() {
 
SQLTable tableCmdElt = getDirectory().getElement("COMMANDE_ELEMENT").getTable();
SQLElement eltArticle = getDirectory().getElement("ARTICLE");
 
240,10 → 239,26
final ListMap<SQLRow, SQLRowValues> map = new ListMap<SQLRow, SQLRowValues>();
List<String> fields2copy = Arrays.asList("CODE", "NOM", "VALEUR_METRIQUE_1", "VALEUR_METRIQUE_2", "VALEUR_METRIQUE_3");
 
// Set<Integer> art = new HashSet<Integer>();
Set<Integer> artAdded = new HashSet<Integer>();
for (SQLRowValues sqlRow : commandeClientEltsRows) {
boolean article = false;
if (sqlRow.getTable().getName().equalsIgnoreCase("ARTICLE")) {
article = true;
}
 
// renderer sur liste des ar
 
// if()
 
/// rowValsElt.put("QTE", sqlRow.getObject("QTE"));
SQLRowAccessor rowArticleFind;
SQLRowValues rowArticle;
int qte = 1;
BigDecimal qteUV = BigDecimal.ONE;
boolean gestionStock = true;
if (!article) {
// on récupére l'article qui lui correspond
SQLRowValues rowArticle = new SQLRowValues(eltArticle.getTable());
rowArticle = new SQLRowValues(eltArticle.getTable());
for (String field : fields2copy) {
// if (sqlRow.getTable().getFieldsName().contains(field.getName())) {
rowArticle.put(field, sqlRow.asRow().getObject(field));
251,54 → 266,43
}
 
int idArticle = ReferenceArticleSQLElement.getIdForCNM(rowArticle, true);
SQLRow rowArticleFind = eltArticle.getTable().getRow(idArticle);
if (rowArticleFind != null && !rowArticleFind.isUndefined()) {
SQLInjector inj = SQLInjector.getInjector(rowArticle.getTable(), tableCmdElt);
SQLRowValues rowValsElt = new SQLRowValues(inj.createRowValuesFrom(rowArticleFind));
rowValsElt.put("ID_STYLE", sqlRow.getObject("ID_STYLE"));
rowArticleFind = eltArticle.getTable().getRow(idArticle);
 
// if()
gestionStock = rowArticleFind.getBoolean("GESTION_STOCK");
if (!gestionStock) {
qte = sqlRow.getInt("QTE");
qteUV = sqlRow.getBigDecimal("QTE_UNITAIRE");
 
rowValsElt.put("QTE", sqlRow.getObject("QTE"));
rowValsElt.put("T_POIDS", rowValsElt.getLong("POIDS") * rowValsElt.getInt("QTE"));
rowValsElt.put("T_PA_HT", ((BigDecimal) rowValsElt.getObject("PA_HT")).multiply(new BigDecimal(rowValsElt.getInt("QTE")), DecimalUtils.HIGH_PRECISION));
rowValsElt.put("T_PA_TTC",
((BigDecimal) rowValsElt.getObject("T_PA_HT")).multiply(new BigDecimal((rowValsElt.getForeign("ID_TAXE").getFloat("TAUX") / 100.0 + 1.0)), DecimalUtils.HIGH_PRECISION));
// rowValsElt.put("ID_DEVISE",
// rowCmd.getForeignRow("ID_TARIF").getForeignID("ID_DEVISE"));
map.add(rowArticleFind.getForeignRow("ID_FOURNISSEUR"), rowValsElt);
if (sqlRow.getObject("ID_UNITE_VENTE") != null && sqlRow.getForeignID("ID_UNITE_VENTE") != UniteVenteArticleSQLElement.A_LA_PIECE) {
qteUV = qteUV.multiply(new BigDecimal(qte));
qte = 1;
}
 
} else {
if (rowArticle.getForeign("ID_STOCK") != null && !rowArticle.isForeignEmpty("ID_STOCK")) {
SQLRowAccessor rowStock = rowArticle.getForeign("ID_STOCK");
qte = -Math.round(rowStock.getFloat("QTE_TH") - rowStock.getFloat("QTE_MIN"));
}
// TODO
MouvementStockSQLElement.createCommandeF(map, null, "", false);
}
} else {
rowArticleFind = sqlRow;
rowArticle = sqlRow;
if (rowArticle.getForeign("ID_STOCK") != null && !rowArticle.isForeignEmpty("ID_STOCK")) {
SQLRowAccessor rowStock = rowArticle.getForeign("ID_STOCK");
qte = -Math.round(rowStock.getFloat("QTE_TH") - rowStock.getFloat("QTE_MIN"));
}
}
if (rowArticleFind != null && !rowArticleFind.isUndefined() && (!gestionStock || !artAdded.contains(rowArticleFind.getID()))) {
 
public void createCommandeF(final List<? extends SQLRowAccessor> rowsItems) {
artAdded.add(rowArticleFind.getID());
 
ComptaPropsConfiguration.getInstanceCompta().getNonInteractiveSQLExecutor().execute(new Runnable() {
SQLInjector inj = SQLInjector.getInjector(rowArticle.getTable(), tableCmdElt);
SQLRowValues rowValsElt = new SQLRowValues(inj.createRowValuesFrom(rowArticleFind.asRow()));
 
@Override
public void run() {
final ListMap<SQLRow, SQLRowValues> map = new ListMap<SQLRow, SQLRowValues>();
final Set<Integer> stockChecked = new HashSet<Integer>();
for (SQLRowAccessor rowItem : rowsItems) {
if (rowItem.getObject("ID_ARTICLE") != null && !rowItem.isForeignEmpty("ID_ARTICLE")) {
SQLRowAccessor rowArticleFind = rowItem.getForeign("ID_ARTICLE");
rowValsElt.put("ID_STYLE", sqlRow.getObject("ID_STYLE"));
 
SQLRow row = rowArticleFind.asRow();
SQLRowAccessor rowStock = StockSQLElement.getStock(rowItem);
if (!stockChecked.contains(rowStock.getID())) {
stockChecked.add(rowStock.getID());
rowValsElt.put("QTE", qte);
rowValsElt.put("QTE_UNITAIRE", qteUV);
 
int value = -Math.round(rowStock.getFloat("QTE_TH") - rowStock.getFloat("QTE_MIN"));
 
if (value > 0) {
 
SQLInjector inj = SQLInjector.getInjector(row.getTable(), row.getTable().getTable("COMMANDE_ELEMENT"));
SQLRowValues rowValsElt = new SQLRowValues(inj.createRowValuesFrom(row));
 
rowValsElt.put("QTE", value);
rowValsElt.put("T_POIDS", rowValsElt.getLong("POIDS") * rowValsElt.getInt("QTE"));
rowValsElt.put("T_PA_HT", ((BigDecimal) rowValsElt.getObject("PA_HT")).multiply(new BigDecimal(rowValsElt.getInt("QTE")), DecimalUtils.HIGH_PRECISION));
rowValsElt.put("T_PA_TTC", ((BigDecimal) rowValsElt.getObject("T_PA_HT")).multiply(new BigDecimal((rowValsElt.getForeign("ID_TAXE").getFloat("TAUX") / 100.0 + 1.0)),
305,15 → 309,13
DecimalUtils.HIGH_PRECISION));
// rowValsElt.put("ID_DEVISE",
// rowCmd.getForeignRow("ID_TARIF").getForeignID("ID_DEVISE"));
map.add(rowArticleFind.getForeign("ID_FOURNISSEUR").asRow(), rowValsElt);
map.add(rowArticleFind.asRow().getForeignRow("ID_FOURNISSEUR"), rowValsElt);
}
}
 
MouvementStockSQLElement.createCommandeF(map, null, "");
}
}
MouvementStockSQLElement.createCommandeF(map, null, "", false);
}
});
 
}
 
protected List<String> getComboFields() {
338,7 → 340,7
res.putCollection("ID_COMMANDE_CLIENT", "NUMERO", "DATE", "DATE_LIVRAISON_PREV", "ID_CLIENT");
 
if (getTable().contains("ID_ARTICLE")) {
res.putCollection("ID_ARTICLE", "ID_FAMILLE_ARTICLE", "ID_FOURNISSEUR");
res.putCollection("ID_ARTICLE", "GESTION_STOCK", "ID_FAMILLE_ARTICLE", "ID_FOURNISSEUR");
}
res.putCollection(null, "NOM");
return res;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/CommandeClientSQLElement.java
22,7 → 22,9
import org.openconcerto.erp.core.sales.order.component.CommandeClientSQLComponent;
import org.openconcerto.erp.core.sales.order.report.CommandeClientXmlSheet;
import org.openconcerto.erp.core.sales.order.ui.EtatCommandeClient;
import org.openconcerto.erp.core.sales.product.element.ReferenceArticleSQLElement;
import org.openconcerto.erp.core.sales.product.element.UniteVenteArticleSQLElement;
import org.openconcerto.erp.core.sales.product.model.ProductComponent;
import org.openconcerto.erp.core.sales.product.model.ProductHelper;
import org.openconcerto.erp.core.sales.shipment.component.BonDeLivraisonSQLComponent;
import org.openconcerto.erp.core.supplychain.stock.element.MouvementStockSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.StockSQLElement;
36,7 → 38,6
import org.openconcerto.sql.element.TreesOfSQLRows;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLInjector;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
579,43 → 580,68
public void transfertCommande(int commandeID, boolean useCommandeEnCours) {
 
SQLElement elt = Configuration.getInstance().getDirectory().getElement("COMMANDE_CLIENT_ELEMENT");
SQLTable tableCmdElt = Configuration.getInstance().getDirectory().getElement("COMMANDE_ELEMENT").getTable();
SQLElement eltArticle = Configuration.getInstance().getDirectory().getElement("ARTICLE");
SQLRow rowCmd = getTable().getRow(commandeID);
List<SQLRow> rows = rowCmd.getReferentRows(elt.getTable());
transfertEltToCommandeF(rows);
}
 
public void transfertEltToCommandeF(List<? extends SQLRowAccessor> rowsItems) {
ComptaPropsConfiguration.getInstanceCompta().getNonInteractiveSQLExecutor().execute(new Runnable() {
 
@Override
public void run() {
ProductHelper helper = new ProductHelper(getTable().getDBRoot());
List<ProductComponent> productComp = new ArrayList<>();
helper.fillProductComponent(rowsItems, productComp, 1, 0, 1);
 
List<ProductComponent> leafItems = helper.getChildWithQtyFrom(productComp);
 
final ListMap<SQLRow, SQLRowValues> map = new ListMap<SQLRow, SQLRowValues>();
for (SQLRow sqlRow : rows) {
// on récupére l'article qui lui correspond
SQLRowValues rowArticle = new SQLRowValues(eltArticle.getTable());
for (SQLField field : eltArticle.getTable().getFields()) {
if (sqlRow.getTable().getFieldsName().contains(field.getName())) {
rowArticle.put(field.getName(), sqlRow.getObject(field.getName()));
final Set<Integer> stockChecked = new HashSet<Integer>();
for (ProductComponent comp : leafItems) {
SQLRowAccessor rowArticleFind = comp.getProduct();
 
SQLRow row = rowArticleFind.asRow();
SQLRowAccessor rowStock = comp.getStock();
int value = 0;
if (row.getBoolean("GESTION_STOCK") && !stockChecked.contains(rowStock.getID())) {
stockChecked.add(rowStock.getID());
 
value = -Math.round(rowStock.getFloat("QTE_TH") - rowStock.getFloat("QTE_MIN"));
} else if (!row.getBoolean("GESTION_STOCK")) {
value = comp.getQty().intValue();
}
if (value > 0) {
 
SQLInjector inj = SQLInjector.getInjector(row.getTable(), row.getTable().getTable("COMMANDE_ELEMENT"));
SQLRowValues rowValsElt = new SQLRowValues(inj.createRowValuesFrom(row));
 
int qte = 1;
BigDecimal qteUV = BigDecimal.ONE;
 
if (row.getObject("ID_UNITE_VENTE") != null && row.getForeignID("ID_UNITE_VENTE") != UniteVenteArticleSQLElement.A_LA_PIECE) {
qteUV = comp.getQty();
} else {
qte = comp.getQty().setScale(0, RoundingMode.HALF_UP).intValue();
}
 
int idArticle = ReferenceArticleSQLElement.getIdForCNM(rowArticle, true);
SQLRow rowArticleFind = eltArticle.getTable().getRow(idArticle);
if (rowArticleFind != null && !rowArticleFind.isUndefined()) {
SQLInjector inj = SQLInjector.getInjector(rowArticle.getTable(), tableCmdElt);
SQLRowValues rowValsElt = new SQLRowValues(inj.createRowValuesFrom(rowArticleFind));
rowValsElt.put("ID_STYLE", sqlRow.getObject("ID_STYLE"));
rowValsElt.put("QTE", sqlRow.getObject("QTE"));
rowValsElt.put("QTE", qte);
rowValsElt.put("QTE_UNITAIRE", qteUV);
 
rowValsElt.put("T_POIDS", rowValsElt.getLong("POIDS") * rowValsElt.getInt("QTE"));
rowValsElt.put("T_PA_HT", ((BigDecimal) rowValsElt.getObject("PA_HT")).multiply(new BigDecimal(rowValsElt.getInt("QTE")), DecimalUtils.HIGH_PRECISION));
rowValsElt.put("T_PA_TTC",
((BigDecimal) rowValsElt.getObject("T_PA_HT")).multiply(new BigDecimal((rowValsElt.getForeign("ID_TAXE").getFloat("TAUX") / 100.0 + 1.0)), DecimalUtils.HIGH_PRECISION));
final SQLRow foreignRow = rowArticleFind.getForeignRow("ID_FOURNISSEUR");
if (foreignRow != null && !foreignRow.isUndefined()) {
rowValsElt.put("ID_DEVISE", foreignRow.getForeignID("ID_DEVISE"));
} else {
rowValsElt.put("ID_DEVISE", rowCmd.getForeignRow("ID_TARIF").getForeignID("ID_DEVISE"));
rowValsElt.put("T_PA_TTC", ((BigDecimal) rowValsElt.getObject("T_PA_HT")).multiply(new BigDecimal((rowValsElt.getForeign("ID_TAXE").getFloat("TAUX") / 100.0 + 1.0)),
DecimalUtils.HIGH_PRECISION));
// rowValsElt.put("ID_DEVISE",
// rowCmd.getForeignRow("ID_TARIF").getForeignID("ID_DEVISE"));
map.add(rowArticleFind.getForeign("ID_FOURNISSEUR").asRow(), rowValsElt);
}
map.add(rowArticleFind.getForeignRow("ID_FOURNISSEUR"), rowValsElt);
}
 
}
MouvementStockSQLElement.createCommandeF(map, rowCmd.getForeignRow("ID_TARIF").getForeignRow("ID_DEVISE"), rowCmd.getString("NUMERO") + " - " + rowCmd.getString("NOM"), useCommandeEnCours);
MouvementStockSQLElement.createCommandeF(map, null, "");
}
});
}
 
/**
* Transfert en BL
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/element/EcheanceClientSQLElement.java
18,7 → 18,11
import org.openconcerto.erp.core.common.element.NumerotationAutoSQLElement;
import org.openconcerto.erp.core.common.ui.DeviseField;
import org.openconcerto.erp.core.customerrelationship.customer.element.RelanceSQLElement;
import org.openconcerto.erp.core.customerrelationship.mail.EmailTemplate;
import org.openconcerto.erp.core.customerrelationship.mail.ValueListener;
import org.openconcerto.erp.core.finance.accounting.element.MouvementSQLElement;
import org.openconcerto.erp.core.finance.payment.element.EncaisserMontantSQLElement;
import org.openconcerto.erp.core.sales.invoice.action.ImportReglementSage;
import org.openconcerto.erp.core.sales.invoice.report.MailRelanceCreator;
import org.openconcerto.erp.core.sales.invoice.report.VenteFactureXmlSheet;
import org.openconcerto.erp.rights.ComptaUserRight;
26,18 → 30,25
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.FieldPath;
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.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
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.sql.model.graph.Link;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.model.graph.PathBuilder;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel.EditMode;
import org.openconcerto.sql.view.list.BaseSQLTableModelColumn;
49,11 → 60,15
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.EmailComposer;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.GestionDevise;
import org.openconcerto.utils.ListMap;
 
import java.awt.Component;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
62,6 → 77,7
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
71,7 → 87,6
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
 
public class EcheanceClientSQLElement extends ComptaSQLConfElement {
 
111,16 → 126,90
}
 
{
PredicateRowAction action = new PredicateRowAction(new AbstractAction("Envoyer un mail") {
PredicateRowAction action = new PredicateRowAction(new AbstractAction("Envoyer un mail de relance") {
 
@Override
public void actionPerformed(ActionEvent arg0) {
public void actionPerformed(ActionEvent e) {
final IListe iListe = IListe.get(e);
if (iListe.getSelectedRows().isEmpty()) {
int result = JOptionPane.showConfirmDialog(iListe,
"Souhaitez vous envoyer un email de relance pour toutes les factures\ndont l'échéance est dépassée?\nLes relances ne seront pas envoyées si les factures ont déjà  une relance de moins d'un mois. ",
"Relance automatique", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
EmailTemplate.askTemplate(iListe, getTable().getDBRoot(), new ValueListener() {
 
SQLRow row = IListe.get(arg0).fetchSelectedRow();
sendMail(row);
@Override
public void valueSelected(Object value) {
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
EmailTemplate template = (EmailTemplate) value;
final SQLTable table = getTable();
final SQLRowValues v = new SQLRowValues(table);
v.putNulls(table.getFieldsName());
Where w = new Where(table.getField("REGLE"), "=", false);
w = w.and(new Where(table.getField("REG_COMPTA"), "=", false));
final Calendar c = Calendar.getInstance();
c.add(Calendar.MONTH, -1);
w = w.and(new Where(table.getField("DATE_LAST_RELANCE"), ">", c.getTime()));
w = w.and(new Where(table.getField("DATE"), "<=", Calendar.getInstance().getTime()));
List<SQLRowValues> rowValues = SQLRowValuesListFetcher.create(v).fetch(w);
if (rowValues.isEmpty()) {
JOptionPane.showMessageDialog(iListe, "Aucune relance à  envoyer.");
} else {
for (SQLRowValues row : rowValues) {
sendMail(row.asRow(), template);
}
}, false);
action.setPredicate(IListeEvent.getSingleSelectionPredicate());
}
} catch (Exception e) {
ExceptionHandler.handle("erreur lors de l'envoi", e);
}
 
}
});
t.setDaemon(true);
t.setName("email relance");
t.start();
 
}
});
 
}
 
} else {
final SQLTable primaryTable = iListe.getRequest().getPrimaryTable();
final List<Integer> selectedIDs = iListe.getSelection().getSelectedIDs();
EmailTemplate.askTemplate(iListe, getTable().getDBRoot(), new ValueListener() {
 
@Override
public void valueSelected(Object value) {
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
EmailTemplate template = (EmailTemplate) value;
final List<SQLRow> rows = SQLRowListRSH.fetch(primaryTable, selectedIDs);
for (SQLRow row : rows) {
sendMail(row, template);
}
} catch (Exception e) {
ExceptionHandler.handle("erreur lors de l'envoi", e);
}
 
}
});
t.setDaemon(true);
t.setName("email relance selection");
t.start();
 
}
});
 
}
}
}, true);
action.setPredicate(IListeEvent.createTotalRowCountPredicate(0, Integer.MAX_VALUE));
getRowActions().add(action);
}
 
143,6 → 232,7
}
}
}, false) {
 
@Override
public boolean enabledFor(List<SQLRowValues> selection) {
if (selection != null && selection.size() == 1) {
184,6 → 274,7
}
}
}, false) {
 
@Override
public boolean enabledFor(List<SQLRowValues> selection) {
if (selection != null && selection.size() == 1) {
193,24 → 284,63
return true;
}
}
 
};
getRowActions().add(actionRegul);
}
 
RowAction actionImport = new RowAction(new AbstractAction("Importer") {
 
public void actionPerformed(ActionEvent e) {
 
final Frame frame = SwingThreadUtils.getAncestorOrSelf(Frame.class, (Component) e.getSource());
final FileDialog fd = new FileDialog(frame, "Import XML des réglements Sage", FileDialog.LOAD);
if (fd.getFile() != null) {
try {
SQLUtils.executeAtomic(getTable().getDBSystemRoot().getDataSource(), new ConnectionHandlerNoSetup<Object, IOException>() {
@Override
public Object handle(final SQLDataSource ds) throws SQLException, IOException {
 
ImportReglementSage sageImporter = new ImportReglementSage(getDirectory().getElement(EncaisserMontantSQLElement.class));
try {
sageImporter.importFromFile(new File(fd.getDirectory(), fd.getFile()));
} catch (Exception e) {
e.printStackTrace();
new SQLException(e);
}
return null;
}
 
});
JOptionPane.showMessageDialog(null, "Import des paiements terminés!");
} catch (IOException exn) {
ExceptionHandler.handle(frame, "Erreur lors de la lecture du fichier", exn);
} catch (SQLException exn) {
ExceptionHandler.handle(frame, "Erreur lors de l'insertion des paiements dans la base", exn);
}
 
private void sendMail(final SQLRow row) {
}
fd.setVisible(true);
}
}, true) {
@Override
public boolean enabledFor(List<SQLRowValues> selection) {
return true;
}
};
getRowActions().add(actionImport);
 
}
 
 
private void sendMail(final SQLRow row, EmailTemplate template) throws Exception {
 
SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete();
 
if (row != null) {
 
int idMvtSource = MouvementSQLElement.getSourceId(row.getInt("ID_MOUVEMENT"));
SQLRow rowMvtSource = base.getTable("MOUVEMENT").getRow(idMvtSource);
 
if (!rowMvtSource.getString("SOURCE").equalsIgnoreCase("SAISIE_VENTE_FACTURE")) {
// this.relancer.setEnabled(false);
return;
}
int idFact = rowMvtSource.getInt("IDSOURCE");
242,16 → 372,12
}
final String adresseMail = mail;
 
MailRelanceCreator creator = new MailRelanceCreator();
final String references = creator.getObject(row);
final String text = creator.getValue(row);
MailRelanceCreator creator = new MailRelanceCreator(template, row);
final String references = creator.getObject();
final String text = creator.getValue();
 
final Thread t = new Thread() {
@Override
public void run() {
final File f;
 
final File f;
try {
f = sheet.getOrCreatePDFDocumentFile(true);
 
EmailComposer.getInstance().compose(adresseMail, references, text, f.getAbsoluteFile());
266,7 → 392,7
rowValsR.put("MONTANT", row.getObject("MONTANT"));
rowValsR.put("INFOS", "Email");
rowValsR.put("ID_ECHEANCE_CLIENT", row.getID());
try {
 
rowValsR.insert();
 
SQLTable tableNum = getTable().getBase().getTable("NUMEROTATION_AUTO");
287,26 → 413,8
 
rowValsEch.update(row.getID());
 
} catch (SQLException e) {
 
e.printStackTrace();
}
} catch (IOException exn) {
exn.printStackTrace();
} catch (InterruptedException exn) {
exn.printStackTrace();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
 
}
};
 
t.start();
}
}
 
@Override
public ListMap<String, String> getShowAs() {
ListMap<String, String> map = new ListMap<String, String>();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/report/ReportingStockXmlSheet.java
13,7 → 13,6
package org.openconcerto.erp.core.sales.invoice.report;
 
import org.openconcerto.erp.core.sales.invoice.report.ReportingVenteXmlSheet.Line;
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml;
import org.openconcerto.erp.preferences.PrinterNXProps;
import org.openconcerto.sql.Configuration;
37,8 → 36,6
import java.util.Map;
import java.util.TreeMap;
 
import javax.swing.JProgressBar;
 
public class ReportingStockXmlSheet extends AbstractListeSheetXml {
 
private final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
125,11 → 122,12
Float qte = vals.getForeign("ID_STOCK").getFloat("QTE_REEL");
BigDecimal ha = BigDecimal.ZERO;
if (qte > 0) {
ha = vals.getBigDecimal("PA_HT").multiply(new BigDecimal(qte));
final BigDecimal puHA = vals.getBigDecimal("PA_HT");
ha = puHA.multiply(new BigDecimal(qte));
 
int idFamille = vals.getForeignID("ID_FAMILLE_ARTICLE");
SQLRow rowF = mapF.get(idFamille);
Line lineArt = new Line(vals.getString("NOM"), vals.getString("CODE"), ha, qte);
Line lineArt = new Line(vals.getString("NOM"), vals.getString("CODE"), puHA, ha, qte);
 
// Init des lines familles
 
225,13 → 223,18
 
class Line {
final private String nomArt, codeArt;
private BigDecimal totalHA;
private BigDecimal totalHA, puHA;
private Float qte;
 
public Line(String nomArt, String codeArt, BigDecimal totalHA, Float qte) {
this(nomArt, codeArt, BigDecimal.ZERO, totalHA, qte);
}
 
public Line(String nomArt, String codeArt, BigDecimal puHA, BigDecimal totalHA, Float qte) {
this.nomArt = nomArt;
this.codeArt = codeArt;
this.totalHA = totalHA;
this.puHA = puHA;
this.qte = qte;
}
 
243,6 → 246,10
return codeArt;
}
 
public BigDecimal getPuHA() {
return puHA;
}
 
public String getNomArt() {
return nomArt;
}
263,6 → 270,7
m.put("CODE", getCodeArt());
m.put("NOM", getNomArt());
m.put("QTE", getQte());
m.put("PU_HA", getPuHA());
m.put("TOTAL_HA", getTotalHA());
return m;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/report/MailRelanceCreator.java
14,11 → 14,10
package org.openconcerto.erp.core.sales.invoice.report;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.customerrelationship.mail.EmailTemplate;
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement;
import org.openconcerto.erp.preferences.MailRelancePreferencePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.utils.GestionDevise;
 
30,10 → 29,18
 
public class MailRelanceCreator {
 
SQLRow rowEcheance;
private final EmailTemplate template;
private final SQLRow rowEcheance;
private final Map<String, String> map;
 
public MailRelanceCreator() {
public MailRelanceCreator(EmailTemplate template, SQLRow row) {
if (template == null) {
template = new EmailTemplate("defautl", getDefaultObject(), getDefaultValue(), true, "dd/MM/yyyy");
}
this.template = template;
this.rowEcheance = row;
 
this.map = getMapValues();
}
 
public String getDefaultObject() {
50,9 → 57,14
return value;
}
 
public Map<String, String> getMapValues(SQLRow rowEch, String datePattern) {
final Map<String, String> map = new HashMap<String, String>();
private Map<String, String> getMapValues() {
String datePattern = this.template.getDateFormat();
if (datePattern == null || datePattern.trim().isEmpty()) {
datePattern = "dd/MM/yyyy";
}
 
final Map<String, String> map = new HashMap<>();
 
final SQLRow rowSoc = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
final SQLRow rowSocAdresse = rowSoc.getForeignRow("ID_ADRESSE_COMMON");
SQLRow rowUser = rowSoc.getTable().getDBRoot().findTable("USER_COMMON").getRow(UserManager.getUser().getId());
84,7 → 96,7
map.put("SocieteVille", ville);
 
SQLRow rowClient;
final SQLRow clientRowNX = rowEch.getForeignRow("ID_CLIENT");
final SQLRow clientRowNX = this.rowEcheance.getForeignRow("ID_CLIENT");
rowClient = clientRowNX;
SQLRow rowAdresse = rowClient.getForeignRow("ID_ADRESSE");
if (!clientRowNX.isForeignEmpty("ID_ADRESSE_F")) {
118,13 → 130,13
DateFormat dateFormat = new SimpleDateFormat(datePattern);
map.put("RelanceDate", dateFormat.format(d));
 
SQLRow rowFacture = rowEch.getForeignRow("ID_SAISIE_VENTE_FACTURE");
SQLRow rowFacture = this.rowEcheance.getForeignRow("ID_SAISIE_VENTE_FACTURE");
 
 
// Infos facture
Long lTotal = (Long) rowFacture.getObject("T_TTC");
Long lRestant = (Long) rowEch.getObject("MONTANT");
Long lVerse = new Long(lTotal.longValue() - lRestant.longValue());
Long lRestant = (Long) this.rowEcheance.getObject("MONTANT");
Long lVerse = Long.valueOf(lTotal.longValue() - lRestant.longValue());
map.put("FactureNumero", rowFacture.getString("NUMERO"));
map.put("FactureReference", rowFacture.getString("NOM"));
map.put("FactureTotal", GestionDevise.currencyToString(lTotal.longValue(), true));
136,30 → 148,22
SQLRow modeRegRow = rowFacture.getForeignRow("ID_MODE_REGLEMENT");
Date dateEch = ModeDeReglementSQLElement.calculDate(modeRegRow.getInt("AJOURS"), modeRegRow.getInt("LENJOUR"), dFacture);
map.put("FactureDateEcheance", dateFormat.format(dateEch));
 
map.put("message", "");
return map;
}
 
public String getObject(SQLRow rowEch) {
SQLPreferences prefs = new SQLPreferences(rowEch.getTable().getDBRoot());
String object = prefs.get(MailRelancePreferencePanel.MAIL_RELANCE_OBJET, getDefaultObject());
String date = prefs.get(MailRelancePreferencePanel.MAIL_RELANCE_DATE_PATTERN, "dd/MM/yyyy");
return fill(rowEch, date, object);
public String getObject() {
return fill(this.template.getTitle());
}
 
public String getValue(SQLRow rowEch) {
SQLPreferences prefs = new SQLPreferences(rowEch.getTable().getDBRoot());
String value = prefs.get(MailRelancePreferencePanel.MAIL_RELANCE, getDefaultValue());
String date = prefs.get(MailRelancePreferencePanel.MAIL_RELANCE_DATE_PATTERN, "dd/MM/yyyy");
return fill(rowEch, date, value);
public String getValue() {
return fill(this.template.getText());
}
 
private String fill(SQLRow rowEch, String datePattern, String string) {
 
Map<String, String> map = getMapValues(rowEch, datePattern);
private String fill(String string) {
String result = string;
for (String key : map.keySet()) {
result = result.replace("{" + key + "}", map.get(key));
for (String key : this.map.keySet()) {
result = result.replace("{" + key + "}", this.map.get(key));
}
return result;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/ImportReglementSageAction.java
New file
0,0 → 1,76
/*
* 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.invoice.action;
 
import org.openconcerto.erp.core.finance.payment.element.EncaisserMontantSQLElement;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.utils.ExceptionHandler;
 
import java.awt.Component;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
 
public class ImportReglementSageAction extends AbstractAction {
private final EncaisserMontantSQLElement elt;
 
public ImportReglementSageAction(EncaisserMontantSQLElement elt) {
super();
this.elt = elt;
this.putValue(Action.NAME, "Import XML des réglements depuis Sage");
}
 
@Override
public void actionPerformed(ActionEvent e) {
final Frame frame = SwingThreadUtils.getAncestorOrSelf(Frame.class, (Component) e.getSource());
final FileDialog fd = new FileDialog(frame, "Import XML des réglements Sage", FileDialog.LOAD);
if (fd.getFile() != null) {
try {
SQLUtils.executeAtomic(this.elt.getTable().getDBSystemRoot().getDataSource(), new ConnectionHandlerNoSetup<Object, IOException>() {
@Override
public Object handle(final SQLDataSource ds) throws SQLException, IOException {
 
ImportReglementSage sageImporter = new ImportReglementSage(ImportReglementSageAction.this.elt);
try {
sageImporter.importFromFile(new File(fd.getDirectory(), fd.getFile()));
} catch (Exception e) {
e.printStackTrace();
new SQLException(e);
}
return null;
}
 
});
JOptionPane.showMessageDialog(null, "Import des paiements terminés!");
} catch (IOException exn) {
ExceptionHandler.handle(frame, "Erreur lors de la lecture du fichier", exn);
} catch (SQLException exn) {
ExceptionHandler.handle(frame, "Erreur lors de l'insertion des paiements dans la base", exn);
}
 
}
fd.setVisible(true);
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/ImportReglementSage.java
New file
0,0 → 1,190
/*
* 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.invoice.action;
 
import org.openconcerto.erp.core.finance.payment.element.EncaisserMontantSQLElement;
import org.openconcerto.erp.core.finance.payment.element.TypeReglementSQLElement;
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.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
 
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
 
public class ImportReglementSage {
 
private final DBRoot root;
private EncaisserMontantSQLElement encaisserSQLElement;
Map<String, SQLRowValues> mapVf;
// <Reglements>
// <Reglement>
// <Code_Client>0010CHDMVA</Code_Client>
// <Date_Reglement>28/01/2019</Date_Reglement>
// <Numero_Facture>FA005088</Numero_Facture>
// <Montant_Reglement>294.00</Montant_Reglement>
// <Libelle_Reglement>Aucun</Libelle_Reglement>
// </Reglement>
// ...
// </Reglements>
 
public ImportReglementSage(EncaisserMontantSQLElement encaisserSQLElement) {
this.root = encaisserSQLElement.getTable().getDBRoot();
this.encaisserSQLElement = encaisserSQLElement;
}
 
public void importFromFile(File f) throws Exception {
final BufferedReader xmlReader = new BufferedReader(new InputStreamReader(new FileInputStream(f), Charset.forName("UTF8")));
SAXBuilder builder = new SAXBuilder();
final Document doc = builder.build(xmlReader);
 
Element root = doc.getRootElement();
List<Element> reglements = root.getChildren("Reglement");
List<String> numeroFacts = new ArrayList<>(reglements.size());
for (Element r : reglements) {
Element n = r.getChild("Numero_Facture");
numeroFacts.add(n.getValue());
}
 
this.mapVf = fetchFactures(numeroFacts);
for (Element r : reglements) {
Element n = r.getChild("Numero_Facture");
Element d = r.getChild("Date_Reglement");
Element m = r.getChild("Montant_Reglement");
Element c = r.getChild("Code_Client");
createEncaissement(n.getValue(), m.getValue(), d.getValue(), c.getValue());
}
 
}
 
private Map<String, SQLRowValues> fetchFactures(List<String> numerosFactures) {
 
final SQLTable tableVf = this.root.getTable("SAISIE_VENTE_FACTURE");
SQLRowValues rowValsFact = new SQLRowValues(tableVf);
rowValsFact.putNulls("DATE", "NUMERO");
rowValsFact.putRowValues("ID_MODE_REGLEMENT").putNulls("ID_TYPE_REGLEMENT");
rowValsFact.putRowValues("ID_CLIENT").putRowValues("ID_MODE_REGLEMENT").putNulls("ID_TYPE_REGLEMENT");
SQLRowValues rowValsEch = new SQLRowValues(this.root.getTable("ECHEANCE_CLIENT"));
rowValsEch.put("ID_SAISIE_VENTE_FACTURE", rowValsFact);
rowValsEch.put("REGLE", null);
rowValsEch.put("MONTANT", null);
rowValsEch.put("REG_COMPTA", null);
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsFact);
List<SQLRowValues> res = fetcher.fetch(new Where(tableVf.getField("NUMERO"), numerosFactures));
Map<String, SQLRowValues> rowValsVf = new HashMap<>();
for (SQLRowValues sqlRowValues : res) {
rowValsVf.put(sqlRowValues.getString("NUMERO"), sqlRowValues);
}
 
return rowValsVf;
 
}
 
private void createEncaissement(String numeroFacture, String montant, String dateReglement, String codeClient) throws Exception {
SQLRowValues rowVals = this.mapVf.get(numeroFacture);
if (rowVals == null) {
SwingUtilities.invokeLater(new Runnable() {
 
@Override
public void run() {
JOptionPane.showMessageDialog(null, "Impossible de trouver la facture numéro " + numeroFacture);
}
});
} else {
final Collection<SQLRowValues> referentRows = rowVals.getReferentRows(rowVals.getTable().getTable("ECHEANCE_CLIENT"));
if (referentRows.size() == 1) {
SQLRowValues ech = referentRows.iterator().next();
if (!ech.getBoolean("REGLE") && !ech.getBoolean("REG_COMPTA")) {
BigDecimal b = new BigDecimal(montant);
long montantL = b.movePointRight(2).setScale(0, RoundingMode.HALF_UP).longValue();
DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
SQLRowValues rowValsEncaisser = new SQLRowValues(this.encaisserSQLElement.getTable());
rowValsEncaisser.put("ID_CLIENT", rowVals.getForeignID("ID_CLIENT"));
rowValsEncaisser.put("NOM", numeroFacture);
rowValsEncaisser.put("TIERS", codeClient);
rowValsEncaisser.put("DATE", format.parse(dateReglement));
 
rowValsEncaisser.put("MONTANT", montantL);
 
SQLRowAccessor rowValsMdrFact = rowVals.getForeign("ID_MODE_REGLEMENT");
int idType = rowValsMdrFact.getForeignID("ID_TYPE_REGLEMENT");
 
SQLRowValues rowValsMdrEnc = new SQLRowValues(rowValsMdrFact.getTable());
 
if (idType == TypeReglementSQLElement.CB || idType == TypeReglementSQLElement.ESPECE || idType == TypeReglementSQLElement.CHEQUE || idType == TypeReglementSQLElement.VIREMENT) {
rowValsMdrEnc.put("ID_TYPE_REGLEMENT", idType);
} else {
rowValsMdrFact = rowVals.getForeign("ID_CLIENT").getForeign("ID_MODE_REGLEMENT");
idType = rowValsMdrFact.getForeignID("ID_TYPE_REGLEMENT");
if (idType == TypeReglementSQLElement.CB || idType == TypeReglementSQLElement.ESPECE || idType == TypeReglementSQLElement.CHEQUE
|| idType == TypeReglementSQLElement.VIREMENT) {
rowValsMdrEnc.put("ID_TYPE_REGLEMENT", idType);
} else {
rowValsMdrEnc.put("ID_TYPE_REGLEMENT", TypeReglementSQLElement.VIREMENT);
}
}
rowValsMdrEnc.put("AJOURS", 0);
rowValsMdrEnc.put("LENJOUR", 0);
rowValsMdrEnc.put("COMPTANT", Boolean.TRUE);
rowValsEncaisser.put("ID_MODE_REGLEMENT", rowValsMdrEnc);
 
SQLRowValues rowValsEncaisserItem = new SQLRowValues(this.encaisserSQLElement.getTable().getTable("ENCAISSER_MONTANT_ELEMENT"));
rowValsEncaisserItem.put("ID_ECHEANCE_CLIENT", ech);
rowValsEncaisserItem.put("ID_ENCAISSER_MONTANT", rowValsEncaisser);
rowValsEncaisserItem.put("MONTANT_REGLE", montantL);
rowValsEncaisserItem.put("MONTANT_A_REGLER", ech.getLong("MONTANT"));
 
SQLRow rowEncaisser = rowValsEncaisser.commit();
 
this.encaisserSQLElement.regleFacture(rowEncaisser);
 
}
}
}
}
 
public static void main(String[] args) {
File f = new File("ExempleReglementSAge.xml");
ImportReglementSage i = new ImportReglementSage(null);
try {
i.importFromFile(f);
} catch (Exception e) {
e.printStackTrace();
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/ui/EtatVentesPanel.java
18,6 → 18,7
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.JLabelBold;
import org.openconcerto.utils.NoneSelectedButtonGroup;
import org.openconcerto.utils.Tuple2;
 
import java.awt.FlowLayout;
43,7 → 44,8
private JDate du, au;
private JButton buttonGen = new JButton("Créer");
private JButton buttonClose = new JButton("Fermer");
JCheckBox boxTicket = new JCheckBox("Uniquement les ventes en caisse");
private JCheckBox boxTicket = new JCheckBox("Uniquement les ventes en caisse");
private JCheckBox boxFacture = new JCheckBox("Uniquement les ventes sur facture");
 
public EtatVentesPanel() {
super(new GridBagLayout());
120,7 → 122,18
 
c.gridy++;
c.gridx = 0;
c.weightx = 1;
c.gridwidth = GridBagConstraints.REMAINDER;
 
this.add(boxFacture, c);
 
NoneSelectedButtonGroup grou = new NoneSelectedButtonGroup();
grou.add(boxFacture);
grou.add(boxTicket);
 
c.gridy++;
c.gridx = 0;
 
JPanel panelButton = new JPanel();
panelButton.add(this.buttonGen);
panelButton.add(this.buttonClose);
167,7 → 180,7
if (e.getSource() == this.buttonGen) {
final Date start = this.du.getDate();
final Date stop = this.au.getDate();
final EtatVentesXmlSheet sheet = new EtatVentesXmlSheet(start, stop, boxTicket.isSelected());
final EtatVentesXmlSheet sheet = new EtatVentesXmlSheet(start, stop, boxTicket.isSelected(), boxFacture.isSelected());
try {
// FIXME probleme de rendu avec le viewer
sheet.createDocumentAsynchronous().get();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/ui/GenListeVentePanel.java
31,6 → 31,8
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
 
import javax.swing.JButton;
109,16 → 111,40
sel.addSelectStar(tableFact);
sel.setDistinct(true);
sel.setWhere(new Where(tableFact.getField("DATE"), GenListeVentePanel.this.du.getDate(), GenListeVentePanel.this.au.getDate()));
List<SQLRow> l = (List<SQLRow>) dataSource.execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, tableFact));
List<SQLRow> l = new ArrayList((List<SQLRow>) dataSource.execute(sel.asString(), SQLRowListRSH.createFromSelect(sel, tableFact)));
Collections.sort(l, new Comparator<SQLRow>() {
@Override
public int compare(SQLRow o1, SQLRow o2) {
int dateComp = o1.getDate("DATE").compareTo(o2.getDate("DATE"));
if (dateComp == 0) {
return o1.getString("NUMERO").compareTo(o2.getString("NUMERO"));
} else {
return dateComp;
}
}
});
 
SQLSelect sel2 = new SQLSelect(Configuration.getInstance().getBase());
sel2.addSelectStar(tableAvoir);
sel2.setWhere(new Where(tableAvoir.getField("DATE"), GenListeVentePanel.this.du.getDate(), GenListeVentePanel.this.au.getDate()));
sel2.setDistinct(true);
List<SQLRow> l2 = (List<SQLRow>) dataSource.execute(sel2.asString(), SQLRowListRSH.createFromSelect(sel2, tableAvoir));
List<SQLRow> l2 = new ArrayList((List<SQLRow>) dataSource.execute(sel2.asString(), SQLRowListRSH.createFromSelect(sel2, tableAvoir)));
Collections.sort(l2, new Comparator<SQLRow>() {
@Override
public int compare(SQLRow o1, SQLRow o2) {
int dateComp = o1.getDate("DATE").compareTo(o2.getDate("DATE"));
if (dateComp == 0) {
return o1.getString("NUMERO").compareTo(o2.getString("NUMERO"));
} else {
return dateComp;
}
}
});
 
List<SQLRow> lTotal = new ArrayList<SQLRow>();
lTotal.addAll(l);
lTotal.addAll(l2);
 
ListeVenteXmlSheet sheet = new ListeVenteXmlSheet(lTotal, GenListeVentePanel.this.du.getDate(), GenListeVentePanel.this.au.getDate(), GenListeVentePanel.this.bar);
 
sheet.createDocumentAsynchronous().get();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/component/SaisieVenteFactureSQLComponent.java
24,6 → 24,7
import org.openconcerto.erp.core.common.ui.DeviseField;
import org.openconcerto.erp.core.common.ui.TotalPanel;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseType;
import org.openconcerto.erp.core.customerrelationship.customer.ui.CategorieComptableChoiceUI;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.EcritureSQLElement;
import org.openconcerto.erp.core.finance.payment.component.ModeDeReglementSQLComponent;
160,6 → 161,10
tableFacture.setRowCatComptable(null);
}
 
if (!isFilling()) {
tableFacture.setClient(rowCli, true);
}
 
if (getMode() == SQLComponent.Mode.INSERTION || !isFilling()) {
SQLElement sqleltModeRegl = Configuration.getInstance().getDirectory().getElement("MODE_REGLEMENT");
int idModeRegl = rowCli.getInt("ID_MODE_REGLEMENT");
480,6 → 485,26
}
});
// }
 
SQLPreferences prefs = SQLPreferences.getMemCached(getTable().getDBRoot());
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CATEGORIE_COMPTABLE_SPEC, false)) {
// cat spe
final CategorieComptableChoiceUI catUI = new CategorieComptableChoiceUI();
catUI.addToUI(this, c);
catUI.getCombo().addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
int wantedID = catUI.getCombo().getWantedID();
if (wantedID != SQLRow.NONEXISTANT_ID && wantedID >= SQLRow.MIN_VALID_ID) {
tableFacture.setRowCatComptable(catUI.getCombo().getElement().getTable().getRow(wantedID));
} else {
tableFacture.setRowCatComptable(null);
}
}
});
}
 
// Contact
this.contact = new ElementComboBox() {
@Override
726,7 → 751,6
final DeviseField textFraisDocHT = new DeviseField();
final SQLRequestComboBox boxTaxeFraisDoc = new SQLRequestComboBox(false, 8);
 
SQLPreferences prefs = SQLPreferences.getMemCached(getTable().getDBRoot());
final boolean showFrais = prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.FRAIS_DOCUMENT, false);
if (showFrais) {
 
1915,4 → 1939,57
this.tableFacture.setDateDevise(this.dateSaisie.getValue());
}
 
@Override
protected void initDone() {
 
super.initDone();
 
// FIXME listener pour le module project à déplacer dans le module quand l'interface passera
// en group
if (getTable().contains("ID_AFFAIRE")) {
final SQLRequestComboBox viewClient = (SQLRequestComboBox) getView("ID_CLIENT").getComp();
final SQLRequestComboBox viewAffaire = (SQLRequestComboBox) getView("ID_AFFAIRE").getComp();
final SQLRequestComboBox viewComm = (SQLRequestComboBox) getView("ID_COMMERCIAL").getComp();
final SQLRequestComboBox viewAgence;
if (getTable().contains("ID_POLE_PRODUIT")) {
viewAgence = (SQLRequestComboBox) getView("ID_POLE_PRODUIT").getComp();
} else {
viewAgence = null;
}
 
viewAffaire.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!isFilling()) {
SQLRowAccessor selAffaire = viewAffaire.getSelectedRow();
if (selAffaire != null && !selAffaire.isUndefined()) {
viewClient.setValue(selAffaire.getForeignID("ID_CLIENT"));
if (selAffaire.getTable().contains("ID_COMMERCIAL")) {
viewComm.setValue(selAffaire.getForeignID("ID_COMMERCIAL"));
}
}
}
}
});
 
if (viewAgence != null) {
 
viewComm.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!isFilling()) {
SQLRowAccessor selComm = viewComm.getSelectedRow();
if (selComm != null && !selComm.isUndefined() && selComm.getTable().contains("ID_POLE_PRODUIT")) {
viewAgence.setValue(selComm.getForeignID("ID_POLE_PRODUIT"));
}
}
}
});
}
}
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/element/DevisSQLElement.java
48,6 → 48,7
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.ui.light.CustomRowEditor;
import org.openconcerto.sql.users.UserManager;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.EditFrame;
63,7 → 64,6
import org.openconcerto.ui.light.ActivationOnSelectionControler;
import org.openconcerto.ui.light.ColumnSpec;
import org.openconcerto.ui.light.ColumnsSpec;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.LightController;
import org.openconcerto.ui.light.LightUIButtonUnmanaged;
import org.openconcerto.ui.light.LightUIComboBox;
99,7 → 99,6
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import javax.swing.AbstractAction;
767,14 → 766,12
}
 
@Override
protected Map<String, CustomEditorProvider> _getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionSecurityToken)
throws IllegalArgumentException {
final Map<String, CustomEditorProvider> map = super._getDefaultCustomEditorProvider(configuration, sqlRow, sessionSecurityToken);
map.put("sales.quote.items.list", new CustomEditorProvider() {
public List<CustomRowEditor> getCustomRowEditors(Configuration configuration, String sessionToken) {
List<CustomRowEditor> map = super.getCustomRowEditors(configuration, sessionToken);
map.add(new CustomRowEditor("sales.quote.items.list") {
 
@Override
public LightUIElement createUIElement(final String id) {
 
public LightUIElement createUIElement() {
final ColumnSpec c1 = new ColumnSpec("sales.quote.item.style", StringWithId.class, "Style", new StringWithId(2, "Normal"), true, new LightUIComboBox("sales.quote.item.style"));
final ColumnSpec c2 = new ColumnSpec("sales.quote.item.code", String.class, "Code", "", true, new LightUITextField("sales.quote.item.code"));
final ColumnSpec c3 = new ColumnSpec("sales.quote.item.label", String.class, "Nom", "", true, new LightUITextField("sales.quote.item.name"));
864,65 → 861,11
final ColumnsSpec cSpec = new ColumnsSpec(lId, columnsSpec, possibleColumnIds, null);
cSpec.setAllowMove(true);
cSpec.setAllowResize(true);
final RowSelectionSpec selectionSpec = new RowSelectionSpec(id);
final TableSpec tSpec = new TableSpec(id, selectionSpec, cSpec);
final RowSelectionSpec selectionSpec = new RowSelectionSpec(getItemId());
final TableSpec tSpec = new TableSpec(getItemId(), selectionSpec, cSpec);
tSpec.setColumns(cSpec);
 
if (sqlRow != null) {
// send: id,value
final SQLElement elem = configuration.getDirectory().getElement("DEVIS_ELEMENT");
final SQLTable table = elem.getTable();
final List<String> fieldsToFetch = new ArrayList<>();
for (ColumnSpec cs : columnsSpec) {
String colId = cs.getId();
SQLField f = configuration.getFieldMapper().getSQLFieldForItem(colId);
if (f != null) {
fieldsToFetch.add(f.getName());
} else {
throw new IllegalStateException("No field in " + table + " for column id " + colId);
}
}
 
final Where where = new Where(table.getField("ID_DEVIS"), "=", sqlRow.getID());
final ListSQLRequest req = elem.createListRequest(fieldsToFetch, where, configuration.getShowAs());
List<SQLRowValues> fetchedRows = req.getValues();
 
List<Row> rows = new ArrayList<>();
for (final SQLRowValues vals : fetchedRows) {
Row r = new Row(vals.getID(), columnsSpec.size());
List<Object> values = new ArrayList<>();
for (ColumnSpec cs : columnsSpec) {
String colId = cs.getId();
SQLField f = configuration.getFieldMapper().getSQLFieldForItem(colId);
if (f != null) {
Object object = vals.getObject(f.getName());
if (object instanceof SQLRowValues) {
SQLRowValues sqlRowValues = (SQLRowValues) object;
long rowId = sqlRowValues.getIDNumber().longValue();
List<SQLField> fieldsToExpand = configuration.getShowAs().getFieldExpand(sqlRowValues.getTable());
final StringBuilder b = new StringBuilder();
for (SQLField sqlField : fieldsToExpand) {
b.append(sqlRowValues.getObject(sqlField.getName()).toString());
b.append(' ');
}
object = new StringWithId(rowId, b.toString().trim());
}
values.add(object);
} else {
throw new IllegalStateException("No field in " + table + " for column id " + colId);
}
}
r.setValues(values);
rows.add(r);
}
 
TableContent tableContent = new TableContent();
tableContent.setRows(rows);
// tableContent.setSpec(new RowSpec());
tSpec.setContent(tableContent);
 
}
 
String id = getItemId();
final LightUITable eList = new LightUITable(id);
eList.setTableSpec(tSpec);
 
974,8 → 917,74
panel.addChild(listLine);
 
return panel;
 
}
 
@Override
public void fillFrom(LightUIElement uiElement, SQLRowAccessor sqlRow) {
LightUIPanel p = (LightUIPanel) uiElement;
LightUITable ltable = p.getFirstChild(LightUITable.class);
TableSpec tSpec = ltable.getTableSpec();
ColumnsSpec columnsSpec = tSpec.getColumns();
// send: id,value
final SQLElement elem = configuration.getDirectory().getElement("DEVIS_ELEMENT");
final SQLTable table = elem.getTable();
final List<String> fieldsToFetch = new ArrayList<>();
for (ColumnSpec cs : columnsSpec.getColumns()) {
String colId = cs.getId();
SQLField f = configuration.getFieldMapper().getSQLFieldForItem(colId);
if (f != null) {
fieldsToFetch.add(f.getName());
} else {
throw new IllegalStateException("No field in " + table + " for column id " + colId);
}
}
 
final Where where = new Where(table.getField("ID_DEVIS"), "=", sqlRow.getID());
final ListSQLRequest req = elem.createListRequest(fieldsToFetch, where, configuration.getShowAs());
List<SQLRowValues> fetchedRows = req.getValues();
 
List<Row> rows = new ArrayList<>();
for (final SQLRowValues vals : fetchedRows) {
Row r = new Row(vals.getID(), columnsSpec.getColumns().size());
List<Object> values = new ArrayList<>();
for (ColumnSpec cs : columnsSpec.getColumns()) {
String colId = cs.getId();
SQLField f = configuration.getFieldMapper().getSQLFieldForItem(colId);
if (f != null) {
Object object = vals.getObject(f.getName());
if (object instanceof SQLRowValues) {
SQLRowValues sqlRowValues = (SQLRowValues) object;
long rowId = sqlRowValues.getIDNumber().longValue();
List<SQLField> fieldsToExpand = configuration.getShowAs().getFieldExpand(sqlRowValues.getTable());
final StringBuilder b = new StringBuilder();
for (SQLField sqlField : fieldsToExpand) {
b.append(sqlRowValues.getObject(sqlField.getName()).toString());
b.append(' ');
}
object = new StringWithId(rowId, b.toString().trim());
}
values.add(object);
} else {
throw new IllegalStateException("No field in " + table + " for column id " + colId);
}
}
r.setValues(values);
rows.add(r);
}
 
TableContent tableContent = new TableContent();
tableContent.setRows(rows);
tSpec.setContent(tableContent);
 
}
 
@Override
public void store(LightUIElement uiElement, SQLRowValues row) {
// TODO Auto-generated method stub
 
}
 
});
return map;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/component/DevisSQLComponent.java
27,6 → 27,7
import org.openconcerto.erp.core.common.ui.TotalPanel;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AddressChoiceUI;
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseType;
import org.openconcerto.erp.core.customerrelationship.customer.ui.CategorieComptableChoiceUI;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.sales.quote.element.EtatDevisSQLElement;
import org.openconcerto.erp.core.sales.quote.report.DevisXmlSheet;
383,6 → 384,23
}
});
}
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CATEGORIE_COMPTABLE_SPEC, false)) {
// cat spe
final CategorieComptableChoiceUI catUI = new CategorieComptableChoiceUI();
catUI.addToUI(this, c);
catUI.getCombo().addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
int wantedID = catUI.getCombo().getWantedID();
if (wantedID != SQLRow.NONEXISTANT_ID && wantedID >= SQLRow.MIN_VALID_ID) {
table.setRowCatComptable(catUI.getCombo().getElement().getTable().getRow(wantedID));
} else {
table.setRowCatComptable(null);
}
}
});
}
if (getTable().contains("ID_CONTACT")) {
// Contact Client
c.gridx = 0;
418,8 → 436,15
final SQLRow rowClient = getTable().getForeignTable("ID_CLIENT").getRow(wantedID);
int idClient = rowClient.getID();
comboContact.getRequest().setWhere(new Where(contactElement.getTable().getField("ID_CLIENT"), "=", idClient));
if (!isFilling()) {
table.setClient(rowClient, true);
}
 
} else {
comboContact.getRequest().setWhere(Where.FALSE);
if (!isFilling()) {
table.setClient(null, true);
}
DevisSQLComponent.this.table.setTarif(null, false);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/CustomerProductQtyPriceSQLElement.java
New file
0,0 → 1,54
/*
* 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 CustomerProductQtyPriceSQLElement extends ComptaSQLConfElement {
public static final String ELEMENT_CODE = "sales.customer.product.qty.price";
 
public CustomerProductQtyPriceSQLElement() {
super("TARIF_ARTICLE_CLIENT");
}
 
@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("QUANTITE");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("QUANTITE");
return l;
}
 
@Override
protected SQLComponent createComponent() {
return null;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ReferenceArticleSQLElement.java
14,6 → 14,7
package org.openconcerto.erp.core.sales.product.element;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.config.update.Updater_1_5;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.erp.core.edm.AttachmentAction;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
20,9 → 21,7
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;
53,7 → 52,6
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;
221,6 → 219,7
l.add("SKU");
 
// if (!prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_MULTI_DEPOT, false)) {
l.add("GESTION_STOCK");
l.add("ID_STOCK");
// }
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
527,58 → 526,9
 
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);
Updater_1_5.initStock(row);
}
 
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 createCodeOfPackage() + ".ref";
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/action/TransfertStockAction.java
New file
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.erp.core.sales.product.action;
 
import org.openconcerto.erp.action.CreateFrameAbstractAction;
import org.openconcerto.erp.core.common.ui.PanelFrame;
import org.openconcerto.sql.Configuration;
 
import javax.swing.Action;
import javax.swing.JFrame;
 
public class TransfertStockAction extends CreateFrameAbstractAction {
 
private Configuration conf;
 
public TransfertStockAction(Configuration conf) {
super();
this.conf = conf;
this.putValue(Action.NAME, "Transfert de stock");
}
 
public JFrame createFrame() {
return new PanelFrame(new TransfertStockPanel(this.conf), "Transfert de stocks");
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/action/TransfertStockPanel.java
New file
0,0 → 1,337
/*
* 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.action;
 
import org.openconcerto.erp.core.common.ui.NumericTextField;
import org.openconcerto.erp.core.sales.product.model.ProductComponent;
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;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
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.sqlobject.SQLRequestComboBox;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.JDate;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
 
import org.apache.commons.dbutils.ResultSetHandler;
 
public class TransfertStockPanel extends JPanel {
 
private final String mvtStockTableQuoted;
private static String defaultLabel = "Transfert de stock";
 
public TransfertStockPanel(Configuration instance) {
super(new GridBagLayout());
 
final JButton buttonUpdate = new JButton("Mettre à jour");
 
final SQLTable mvtStockTable = instance.getRoot().findTable("MOUVEMENT_STOCK");
this.mvtStockTableQuoted = mvtStockTable.getSQLName().quote();
 
final SQLElement articleElt = instance.getDirectory().getElement("ARTICLE");
final SQLRequestComboBox comboArticle = new SQLRequestComboBox();
comboArticle.uiInit(articleElt.createComboRequest());
 
final SQLElement stockElt = instance.getDirectory().getElement("DEPOT_STOCK");
final SQLRequestComboBox comboStockDepart = new SQLRequestComboBox();
comboStockDepart.uiInit(stockElt.createComboRequest());
 
final SQLRequestComboBox comboStockArrive = new SQLRequestComboBox();
comboStockArrive.uiInit(stockElt.createComboRequest());
 
JLabel qteReel = new JLabel("Quantité", SwingConstants.RIGHT);
final NumericTextField fieldReel = new NumericTextField();
 
fieldReel.getDocument().addDocumentListener(new SimpleDocumentListener() {
 
@Override
public void update(DocumentEvent e) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
}
});
 
comboArticle.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
}
});
 
comboStockArrive.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
}
});
 
comboStockDepart.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
}
});
 
GridBagConstraints c = new DefaultGridBagConstraints();
 
this.add(new JLabel("Intitulé"), c);
final JTextField label = new JTextField();
c.gridx++;
c.gridwidth = 2;
c.weightx = 1;
this.add(label, c);
label.setText(defaultLabel);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 1;
c.weightx = 0;
this.add(new JLabel("Date", SwingConstants.RIGHT), c);
final JDate date = new JDate(true);
c.gridx++;
c.weightx = 0;
this.add(date, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(new JLabel("Article", SwingConstants.RIGHT), c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(comboArticle, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(new JLabel("Départ", SwingConstants.RIGHT), c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(comboStockDepart, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(new JLabel("Arrivée", SwingConstants.RIGHT), c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(comboStockArrive, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(qteReel, c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(fieldReel, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(qteReel, c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(fieldReel, c);
 
c.gridy++;
c.gridx = 0;
JButton buttonCancel = new JButton("Annuler");
JPanel pButton = new JPanel();
pButton.add(buttonCancel);
pButton.add(buttonUpdate);
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.EAST;
c.weightx = 0;
c.fill = GridBagConstraints.NONE;
this.add(pButton, c);
buttonCancel.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
((JFrame) SwingUtilities.getRoot(TransfertStockPanel.this)).dispose();
}
});
buttonUpdate.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
 
buttonUpdate.setEnabled(false);
defaultLabel = label.getText();
BigDecimal qteReel = fieldReel.getValue();
 
List<String> multipleRequestsHundred = new ArrayList<String>(100);
boolean usePrice = mvtStockTable.contains("PRICE");
List<StockItem> stockItems = new ArrayList<StockItem>();
final Date dateValue = date.getValue();
 
final SQLRow selectedRowArticle = comboArticle.getSelectedRow();
 
{
// DEPART
final SQLRow selectedRowDepotDepart = comboStockDepart.getSelectedRow();
final SQLRowAccessor rowStockDepart = ProductComponent.findOrCreateStock(selectedRowArticle, selectedRowDepotDepart);
StockItem item = new StockItem(selectedRowArticle, rowStockDepart);
if (!item.isStockInit()) {
SQLRowValues rowVals = new SQLRowValues(mvtStockTable.getTable("STOCK"));
rowVals.put("ID_ARTICLE", selectedRowArticle.getID());
rowVals.put("ID_DEPOT_STOCK", selectedRowDepotDepart.getID());
try {
rowVals.commit();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
selectedRowArticle.fetchValues();
item = new StockItem(selectedRowArticle, rowStockDepart);
}
stockItems.add(item);
double diff = -qteReel.doubleValue();
item.updateQty(diff, TypeStockMouvement.REEL);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, label.getText(), true, usePrice));
 
item.updateQty(diff, TypeStockMouvement.THEORIQUE);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, label.getText(), false, usePrice));
 
multipleRequestsHundred.add(item.getUpdateRequest());
}
// ARRIVEE
{
final SQLRow selectedRowDepotArrivee = comboStockArrive.getSelectedRow();
final SQLRowAccessor rowStockArrivee = ProductComponent.findOrCreateStock(selectedRowArticle, selectedRowDepotArrivee);
 
StockItem item = new StockItem(selectedRowArticle, rowStockArrivee);
if (!item.isStockInit()) {
SQLRowValues rowVals = new SQLRowValues(mvtStockTable.getTable("STOCK"));
rowVals.put("ID_ARTICLE", selectedRowArticle.getID());
rowVals.put("ID_DEPOT_STOCK", selectedRowDepotArrivee.getID());
try {
rowVals.commit();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
selectedRowArticle.fetchValues();
item = new StockItem(selectedRowArticle, rowStockArrivee);
}
stockItems.add(item);
double diff = qteReel.doubleValue();
item.updateQty(diff, TypeStockMouvement.REEL);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, label.getText(), true, usePrice));
 
item.updateQty(diff, TypeStockMouvement.THEORIQUE);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, label.getText(), false, usePrice));
 
multipleRequestsHundred.add(item.getUpdateRequest());
}
 
try {
 
final int size = multipleRequestsHundred.size();
List<? extends ResultSetHandler> handlers = new ArrayList<ResultSetHandler>(size);
for (int i = 0; i < size; i++) {
handlers.add(null);
}
SQLUtils.executeMultiple(instance.getRoot().getDBSystemRoot(), multipleRequestsHundred, handlers);
 
} catch (SQLException e1) {
ExceptionHandler.handle("Stock update error", e1);
}
 
final DBRoot root = mvtStockTable.getDBRoot();
if (root.contains("ARTICLE_ELEMENT")) {
// 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 {
comp.update();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
 
// liste.getModel().updateAll();
((JFrame) SwingUtilities.getRoot(TransfertStockPanel.this)).dispose();
}
});
}
 
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\",\"ID_STOCK\",\"NOM\",\"REEL\",\"ORDRE\"";
 
if (usePrice && prc != null) {
mvtStockQuery += ",\"PRICE\"";
}
 
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();
}
mvtStockQuery += ")";
return mvtStockQuery;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/DeliveredQtyRowValuesRenderer.java
45,8 → 45,15
public final static Color lightBlack = new Color(192, 192, 192);
public final static Color lightBlackGrey = new Color(155, 155, 155);
 
private final boolean customer;
 
public DeliveredQtyRowValuesRenderer() {
this(true);
}
 
public DeliveredQtyRowValuesRenderer(boolean customer) {
AlternateTableCellRenderer.setBGColorMap(this, CollectionUtils.createMap(lightBlack, lightBlackGrey, red, redLightGrey, orange, orangeGrey));
this.customer = customer;
}
 
@Override
60,8 → 67,15
RowValuesTableModel model = ((RowValuesTable) table).getRowValuesTableModel();
SQLRowValues rowVals = model.getRowValuesAt(row);
 
Number qte = (Number) rowVals.getObject("QTE");
Number qteL = (Number) rowVals.getObject("QTE_LIVREE");
Number qte;
Number qteL;
if (this.customer) {
qte = (Number) rowVals.getObject("QTE");
qteL = (Number) rowVals.getObject("QTE_LIVREE");
} else {
qte = (Number) rowVals.getObject("QTE_ORIGINE");
qteL = (Number) rowVals.getObject("QTE");
}
if (qte != null && qteL != null) {
if (qte.intValue() < qteL.intValue()) {
comp.setBackground(red);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/CurrencyWithSymbolRenderer.java
34,6 → 34,8
private final FieldPath fieldPath;
private final CurrencyConverter c;
 
private boolean hideZeroValue = false;
 
private String getSymbol(String currencyCode) {
// Because Java Currency return PLN as Symbol for Zl, we use our own talbe
return org.openconcerto.erp.core.finance.accounting.model.Currency.getSymbol(currencyCode);
46,6 → 48,10
this(null);
}
 
public void setHideZeroValue(boolean hideZeroValue) {
this.hideZeroValue = hideZeroValue;
}
 
/**
* Affiche une valeur monétaire en ajoutant le symbole de la devise du path
*
60,8 → 66,13
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
 
if (value != null) {
value = GestionDevise.currencyToString((BigDecimal) value);
BigDecimal amount = (BigDecimal) value;
 
if (this.hideZeroValue && amount.signum() == 0) {
value = "";
} else {
value = GestionDevise.currencyToString(amount);
 
if (fieldPath == null) {
value = value + " " + getSymbol(c.getCompanyCurrencyCode());
} else {
78,7 → 89,8
// reprend
// pas les valeurs de la SQLRow (ex : si on veut récupérer la devise du
// fournisseur
// sélectionné, getDistantRow ira chercher la valeur du fournisseur référencé en
// sélectionné, getDistantRow ira chercher la valeur du fournisseur
// référencé en
// BDD
// et non dans la SQLRow)
 
108,6 → 120,7
}
}
}
}
setHorizontalAlignment(SwingConstants.RIGHT);
 
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/QteAcommanderRenderer.java
New file
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.erp.core.sales.product.ui;
 
import org.openconcerto.erp.core.common.ui.DeviseNiceTableCellRenderer;
import org.openconcerto.ui.table.AlternateTableCellRenderer;
 
import java.awt.Color;
import java.awt.Component;
 
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
 
public class QteAcommanderRenderer extends DeviseNiceTableCellRenderer {
 
private final static Color green = new Color(225, 254, 207);
private final static Color greenDark = new Color(205, 234, 187);
 
public QteAcommanderRenderer() {
AlternateTableCellRenderer.setBGColorMap(this, green, greenDark);
}
 
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
 
Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
 
((JLabel) comp).setHorizontalAlignment(SwingConstants.RIGHT);
if (value != null) {
Float b = (Float) value;
if (b <= 0) {
comp.setBackground(green);
}
}
 
return comp;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/CustomerProductQtyPriceListTable.java
New file
0,0 → 1,120
/*
* 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.ui;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableControlPanel;
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTablePanel;
import org.openconcerto.sql.view.list.RowValuesTableRenderer;
import org.openconcerto.sql.view.list.SQLTableElement;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.table.PercentTableCellRenderer;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.math.BigDecimal;
import java.util.List;
import java.util.Vector;
 
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
 
public class CustomerProductQtyPriceListTable extends RowValuesTablePanel {
 
public CustomerProductQtyPriceListTable() {
 
init();
uiInit();
}
 
/**
*
*/
protected void init() {
 
final SQLElement e = getSQLElement();
 
final List<SQLTableElement> list = new Vector<SQLTableElement>();
 
final SQLTableElement tableElementClient = new SQLTableElement(e.getTable().getField("ID_ARTICLE"));
list.add(tableElementClient);
 
// final SQLTableElement eQuantity = new SQLTableElement(e.getTable().getField("QUANTITE"))
// {
// @Override
// protected Object getDefaultNullValue() {
// return BigDecimal.ONE;
// }
// };
// list.add(eQuantity);
 
SQLTableElement eltPourcent = new SQLTableElement(e.getTable().getField("POURCENT_REMISE"));
list.add(eltPourcent);
 
this.model = new RowValuesTableModel(e, list, e.getTable().getField("ID_ARTICLE"), false, this.defaultRowVals);
 
this.table = new RowValuesTable(this.model, null);
 
eltPourcent.setRenderer(new PercentTableCellRenderer());
 
}
 
public SQLElement getSQLElement() {
return Configuration.getInstance().getDirectory().getElement("TARIF_ARTICLE_CLIENT");
}
 
public void insertFrom(String field, SQLRowValues row) {
this.table.insertFrom(field, row);
}
 
protected void uiInit() {
// Ui init
this.setLayout(new GridBagLayout());
this.setOpaque(false);
final GridBagConstraints c = new DefaultGridBagConstraints();
c.weightx = 1;
c.gridx = 0;
final JPanel control = new RowValuesTableControlPanel(this.table);
control.setOpaque(false);
this.add(control, c);
 
c.gridy++;
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
c.weightx = 1;
JScrollPane comp = new JScrollPane(this.table);
comp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
this.add(comp, c);
this.table.setDefaultRenderer(Long.class, new RowValuesTableRenderer());
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/ProductHelper.java
74,6 → 74,44
return result;
}
 
/**
* Fill productComponents with items (SQLrowAccessor of TABLE_ELEMENT)
*
* @param items
* @param productComponents
* @param qte
* @param index
* @param level
*/
public void fillProductComponent(List<? extends SQLRowAccessor> itemsTableElement, List<ProductComponent> productComponents, int qte, int index, int level) {
if (level > 0) {
for (int i = index; i < itemsTableElement.size(); i++) {
SQLRowAccessor r = itemsTableElement.get(i);
 
if (!r.getTable().contains("NIVEAU") || r.getInt("NIVEAU") >= level) {
// On ne calcul pas les stocks pour les éléments ayant des fils (le mouvement de
// stock
// des fils impactera les stocks automatiquement)
if (r.getTable().contains("NIVEAU")) {
if (i + 1 < itemsTableElement.size()) {
SQLRowAccessor rNext = itemsTableElement.get(i + 1);
if (rNext.getInt("NIVEAU") > r.getInt("NIVEAU")) {
fillProductComponent(itemsTableElement, productComponents, qte * r.getInt("QTE"), i + 1, rNext.getInt("NIVEAU"));
continue;
}
}
}
if ((!r.getTable().contains("NIVEAU") || r.getInt("NIVEAU") == level) && r.getForeign("ID_ARTICLE") != null && !r.isForeignEmpty("ID_ARTICLE")) {
productComponents.add(ProductComponent.createFrom(r, qte, r));
}
} else if (r.getInt("NIVEAU") < level) {
// BREAK si on sort de l'article composé
break;
}
}
}
}
 
public BigDecimal getUnitCostForQuantity(SQLRowAccessor rArticle, int qty) {
 
Collection<? extends SQLRowAccessor> l = rArticle.getReferentRows(rArticle.getTable().getTable("ARTICLE_PRIX_REVIENT"));
246,7 → 284,7
 
SQLRowValues rowVals = new SQLRowValues(costTable);
 
final SQLRowValues artRowValues = rowVals.putRowValues("ID_ARTICLE").putNulls("ID", "GESTION_STOCK", "CODE", "NOM", "ID_DEPOT_STOCK", "ID_UNITE_VENTE");
final SQLRowValues artRowValues = rowVals.putRowValues("ID_ARTICLE").putNulls("ID", "GESTION_STOCK", "CODE", "NOM", "ID_DEPOT_STOCK", "ID_UNITE_VENTE", "ID_FOURNISSEUR");
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);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/ProductComponent.java
15,6 → 15,8
 
import org.openconcerto.erp.core.sales.product.model.ProductHelper.SupplierPriceField;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
167,10 → 169,39
 
private static SQLRowAccessor getStock(SQLRowAccessor rowValsProduct, SQLRowAccessor rowValsElt, SQLRowAccessor rowValsSource) {
SQLRowAccessor rowStock = null;
final int idDepot;
int idDepot = -1;
 
if (rowValsProduct.getTable().getDBRoot().contains("AFFAIRE")) {
SQLTable tableAff = rowValsProduct.getTable().getTable("AFFAIRE");
if (tableAff.contains("ID_DEPOT_STOCK")) {
if (rowValsSource.getFields().contains("ID_DEPOT_STOCK") && !rowValsSource.isForeignEmpty("ID_DEPOT_STOCK")) {
idDepot = rowValsSource.getForeignID("ID_DEPOT_STOCK");
} else if (rowValsSource.getFields().contains("ID_AFFAIRE") && !rowValsSource.isForeignEmpty("ID_AFFAIRE")) {
SQLRowAccessor rowAff = rowValsSource.getForeign("ID_AFFAIRE");
if (rowAff.getFields().contains("ID_DEPOT_STOCK") && !rowAff.isForeignEmpty("ID_DEPOT_STOCK")) {
idDepot = rowAff.getForeignID("ID_DEPOT_STOCK");
}
} else {
SQLField fieldParent = Configuration.getInstance().getDirectory().getElement(rowValsSource.getTable()).getParentForeignField();
if (fieldParent != null) {
SQLRowAccessor parent = rowValsSource.getForeign(fieldParent.getName());
 
if (parent.getFields().contains("ID_AFFAIRE") && !parent.isForeignEmpty("ID_AFFAIRE")) {
SQLRowAccessor rowAff = parent.getForeign("ID_AFFAIRE");
if (rowAff.getFields().contains("ID_DEPOT_STOCK") && !rowAff.isForeignEmpty("ID_DEPOT_STOCK")) {
idDepot = rowAff.getForeignID("ID_DEPOT_STOCK");
}
}
}
}
}
}
 
if (idDepot == -1) {
 
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 {
183,7 → 214,7
 
}
}
 
}
SQLTable stockTable = rowValsElt.getTable().getTable("STOCK");
SQLRowValues putRowValuesStock = new SQLRowValues(stockTable);
putRowValuesStock.putNulls(stockTable.getTable().getFieldsName());
215,4 → 246,37
}
return rowStock;
}
 
public static SQLRowAccessor findOrCreateStock(SQLRowAccessor article, SQLRowAccessor depot) {
 
SQLRowAccessor rowStock = null;
SQLTable stockTable = article.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"), "=", depot.getID());
Where w2 = new Where(putRowValuesStock.getTable().getField("ID_ARTICLE"), "=", article.getID());
Collection<SQLRowValues> rowValsResult = fetch.fetch(w.and(w2));
if (rowValsResult.size() == 0) {
SQLRowValues rowValsStock = new SQLRowValues(stockTable);
rowValsStock.put("ID_ARTICLE", article.getID());
rowValsStock.put("ID_DEPOT_STOCK", depot.getID());
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();
} 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 " + article.getID() + " Depot " + depot.getID());
}
return rowStock;
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/POSConfiguration.java
30,6 → 30,7
import org.openconcerto.erp.core.sales.pos.model.RegisterFiles.HashMode;
import org.openconcerto.erp.core.sales.pos.model.RegisterLogEntry.ReceiptEntry;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
import org.openconcerto.erp.core.sales.pos.model.TicketLine;
import org.openconcerto.erp.core.supplychain.stock.element.StockItemsUpdater;
import org.openconcerto.erp.core.supplychain.stock.element.StockItemsUpdater.TypeStockUpdate;
41,10 → 42,12
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLDataSource;
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.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
55,7 → 58,6
import org.openconcerto.utils.BaseDirs;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Pair;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.io.File;
69,9 → 71,11
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Logger;
 
import javax.swing.JOptionPane;
118,6 → 122,8
private String LCDLine1 = "Bienvenue";
private String LCDLine2 = "ILM Informatique";
 
private boolean askPostalCode = false;
 
public static POSConfiguration createInstance() throws JDOMException, IOException {
POSConfiguration res = new POSConfiguration(getConfigFile(new File(".")));
res.loadConfiguration();
255,8 → 261,8
System.exit(2);
}
 
NouvelleConnexionAction.initCache(conf);
 
NouvelleConnexionAction.initCache(conf, -1);
TaxeCache.getCache();
return conf;
}
 
317,14 → 323,23
throw new IllegalArgumentException("Size mismatch");
 
final int defaultIDClient = getClientCaisse().getID();
SQLElement elt = Configuration.getInstance().getDirectory().getElement("TICKET_CAISSE");
SQLElement eltFact = Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE_ELEMENT");
SQLElement eltEnc = Configuration.getInstance().getDirectory().getElement("ENCAISSER_MONTANT");
SQLElement eltMode = Configuration.getInstance().getDirectory().getElement("MODE_REGLEMENT");
SQLElement eltArticle = Configuration.getInstance().getDirectory().getElement("ARTICLE");
final SQLElementDirectory directory = Configuration.getInstance().getDirectory();
SQLElement elt = directory.getElement("TICKET_CAISSE");
SQLElement eltFact = directory.getElement("SAISIE_VENTE_FACTURE_ELEMENT");
SQLElement eltEnc = directory.getElement("ENCAISSER_MONTANT");
SQLElement eltMode = directory.getElement("MODE_REGLEMENT");
SQLElement eltArticle = directory.getElement("ARTICLE");
final SQLDataSource ds = elt.getTable().getDBSystemRoot().getDataSource();
int imported = 0;
 
//
final SQLSelect selUniteVente = new SQLSelect();
selUniteVente.addSelectStar(directory.getElement("UNITE_VENTE").getTable());
final Map<String, Integer> mapUniteVenteName = new HashMap<>();
for (SQLRow row : SQLRowListRSH.execute(selUniteVente)) {
mapUniteVenteName.put(row.getString("CODE"), row.getID());
}
 
final Iterator<ReceiptEntry> entriesIter = entries == null ? null : entries.iterator();
for (Ticket ticket : tickets) {
SQLSelect sel = new SQLSelect();
347,6 → 362,9
rowVals.put("NUMERO", ticket.getCode());
rowVals.put("DATE", ticket.getCreationDate());
rowVals.put("ID_CAISSE", getPosID());
if (elt.getTable().contains("CODE_POSTAL")) {
rowVals.put("CODE_POSTAL", ticket.getCodePostal());
}
if (entry != null) {
rowVals.put("FILE_HASH", entry.getFileHash());
rowVals.put("FILE_HASH_PREVIOUS", ticket.getPreviousHash());
364,17 → 382,24
calc.setServiceActive(bServiceActive != null && bServiceActive);
 
// Articles
for (Pair<Article, Integer> item : ticket.getArticles()) {
for (TicketItem item : ticket.getItems()) {
SQLRowValues rowValsElt = new SQLRowValues(eltFact.getTable());
final Article article = item.getFirst();
final Integer nb = item.getSecond();
rowValsElt.put("QTE", nb);
final Article article = item.getArticle();
final BigDecimal nb = item.getQty();
if (article.getSalesUnit() == null) {
rowValsElt.put("QTE", nb.intValue());
} else {
rowValsElt.put("QTE", 1);
rowValsElt.put("QTE_UNITAIRE", nb);
}
rowValsElt.put("PV_HT", article.getPriceWithoutTax());
Float tauxFromId = TaxeCache.getCache().getTauxFromId(article.getIdTaxe());
BigDecimal tauxTVA = new BigDecimal(tauxFromId).movePointLeft(2).add(BigDecimal.ONE);
BigDecimal tauxTVA = BigDecimal.valueOf(tauxFromId).movePointLeft(2).add(BigDecimal.ONE);
 
final BigDecimal valueHT = article.getPriceWithoutTax().multiply(new BigDecimal(nb), DecimalUtils.HIGH_PRECISION);
 
final BigDecimal valueHT = article.getPriceWithoutTax().multiply(nb, DecimalUtils.HIGH_PRECISION);
if (article.getSalesUnit() != null) {
rowValsElt.put("ID_UNITE_VENTE", mapUniteVenteName.get(article.getSalesUnit()));
}
rowValsElt.put("T_PV_HT", valueHT);
rowValsElt.put("T_PV_TTC", valueHT.multiply(tauxTVA, DecimalUtils.HIGH_PRECISION));
rowValsElt.put("ID_TAXE", article.getIdTaxe());
449,7 → 474,7
false);
}
if (totalEnc > longValueTotal) {
final SQLTable table = Configuration.getInstance().getDirectory().getElement("TYPE_REGLEMENT").getTable();
final SQLTable table = directory.getElement("TYPE_REGLEMENT").getTable();
int idComptePceCaisse = table.getRow(TypeReglementSQLElement.ESPECE).getInt("ID_COMPTE_PCE_CLIENT");
if (idComptePceCaisse == table.getUndefinedID()) {
idComptePceCaisse = ComptePCESQLElement.getId(ComptePCESQLElement.getComptePceDefault("VenteEspece"));
520,15 → 545,13
stockUpdater.update();
}
 
public List<Ticket> allTickets() {
public List<Ticket> allTickets() throws IOException {
final List<Ticket> l = new ArrayList<Ticket>();
for (final File f : ReceiptCode.getReceiptsToImport(getPosID())) {
// old receipts have no hash files
final Ticket ticket = Ticket.parseFile(f, HashMode.NOT_REQUIRED);
if (ticket != null) {
l.add(ticket);
}
}
return l;
}
 
565,6 → 588,8
setCompanyID(Integer.valueOf(rootElement.getAttributeValue("societeID", "42")));
setPosID(Integer.valueOf(rootElement.getAttributeValue("caisseID", "2")));
setScanDelay(Integer.valueOf(rootElement.getAttributeValue("scanDelay", "80")));
setAskPostalCode(rootElement.getAttributeValue("askPostalCode", "false").equals("true"));
 
// screen
final List<Element> children = rootElement.getChildren("screen");
if (children != null) {
607,7 → 632,7
}
// ticket printers
final List<Element> printers = rootElement.getChildren("ticketPrinter");
if (printers.size() > 0) {
if (!printers.isEmpty()) {
configureTicketPrinter(this.ticketPrinterConf1, printers.get(0));
}
if (printers.size() > 1) {
649,6 → 674,7
configElement.setAttribute("societeID", String.valueOf(this.companyID));
configElement.setAttribute("caisseID", String.valueOf(this.posID));
configElement.setAttribute("scanDelay", String.valueOf(this.scanDelay));
configElement.setAttribute("askPostalCode", this.askPostalCode ? "true" : "false");
doc.addContent(configElement);
// screen size
final Element screenElement = new Element("screen");
799,4 → 825,12
public String getLCDType() {
return this.LCDType;
}
 
public boolean askPostalCode() {
return this.askPostalCode;
}
 
public void setAskPostalCode(boolean askPostalCode) {
this.askPostalCode = askPostalCode;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/element/TicketCaisseSQLElement.java
30,6 → 30,7
static public final String UNARCHIVED_WHERE = SQLBase.quoteIdentifier("ARCHIVE") + " = " + 0;
static public final String DATE_WHERE = UNARCHIVED_WHERE + " and " + SQLBase.quoteIdentifier("FILE_HASH") + " is not null";
 
// needed until H2 databases are upgraded to use JS code
static public final class UniqueNumber_PartialUniqueTrigger extends PartialUniqueTrigger {
public UniqueNumber_PartialUniqueTrigger() {
super(Arrays.asList("NUMERO"), UNARCHIVED_WHERE);
36,6 → 37,7
}
}
 
// needed until H2 databases are upgraded to use JS code
static public final class UniqueDate_PartialUniqueTrigger extends PartialUniqueTrigger {
public UniqueDate_PartialUniqueTrigger() {
super(Arrays.asList("ID_CAISSE", "DATE"), DATE_WHERE);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CategorieSelector.java
85,6 → 85,10
 
}
super.paint(g);
 
g.setColor(Color.LIGHT_GRAY);
g.drawLine(0, 0, 0, this.getHeight());
 
}
 
private int getLeftMargin() {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/ArticleSelectorPanel.java
13,7 → 13,6
package org.openconcerto.erp.core.sales.pos.ui;
 
 
import java.awt.GridLayout;
 
import javax.swing.JPanel;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/PostalCodeEditorPanel.java
New file
0,0 → 1,106
/*
* 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.pos.ui;
 
import org.openconcerto.erp.core.common.ui.NumericTextField;
 
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
 
public class PostalCodeEditorPanel extends JPanel {
 
private final NumericTextField postalCodeTextField;
 
private final NumericKeypadPanel keyPad;
 
public PostalCodeEditorPanel(final CaisseFrame caisseFrame, final CaissePanel caissePanel) {
 
this.setBackground(Color.WHITE);
this.setOpaque(true);
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.EAST;
c.weightx = 0;
c.weighty = 1;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(20, 20, 30, 20);
// Line 1
c.gridwidth = 2;
POSLabel title = new POSLabel("Code postal");
this.add(title, c);
// Line 2
this.postalCodeTextField = new NumericTextField(8);
this.postalCodeTextField.setFont(this.postalCodeTextField.getFont().deriveFont(16f));
c.gridy++;
this.add(this.postalCodeTextField, c);
 
c.gridy++;
c.gridx = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.SOUTHEAST;
 
final JPanel buttons = new JPanel(new GridLayout(1, 2, 10, 0));
buttons.setOpaque(false);
POSButton bCancel = new POSButton("Annuler");
buttons.add(bCancel, c);
POSButton bApply = new POSButton("Valider");
buttons.add(bApply, c);
bApply.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
caissePanel.getControler().setCodePostal(PostalCodeEditorPanel.this.postalCodeTextField.getText());
caissePanel.validateTicket(caisseFrame);
caisseFrame.showCaisse();
}
});
bCancel.addActionListener(new ActionListener() {
 
@Override
public void actionPerformed(ActionEvent e) {
caisseFrame.showCaisse();
}
});
 
this.add(buttons, c);
 
c.anchor = GridBagConstraints.CENTER;
c.weightx = 0;
c.weighty = 0;
c.gridx = 3;
c.gridy = 2;
c.insets = new Insets(20, 20, 30, 20);
// Line 1
c.gridheight = 5;
keyPad = new NumericKeypadPanel(postalCodeTextField);
this.add(keyPad, c);
 
SwingUtilities.invokeLater(new Runnable() {
public void run() {
postalCodeTextField.requestFocus();
}
});
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/ArticleSearchPanel.java
17,6 → 17,7
import org.openconcerto.erp.core.sales.pos.model.Categorie;
import org.openconcerto.ui.touch.ScrollableList;
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
24,7 → 25,6
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
39,7 → 39,6
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
46,7 → 45,7
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
 
public class ArticleSearchPanel extends JPanel implements ListSelectionListener, CaisseListener {
public class ArticleSearchPanel extends JPanel implements CaisseListener {
private final ScrollableList list;
private final CaisseControler controler;
private final JTextField textField = new JTextField();
57,14 → 56,23
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
final FilteredListModel model = new FilteredListModel();
final Font f1 = new Font("Arial", Font.PLAIN, 24);
final Font f2 = new Font("Arial", Font.PLAIN, 16);
setBackground(CaissePanel.LIGHT_BLUE);
list = new ScrollableList(model) {
final Font f1;
final Font f2;
 
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
f1 = new Font("Arial", Font.PLAIN, 21);
f2 = new Font("Arial", Font.PLAIN, 14);
} else {
f1 = new Font("Arial", Font.PLAIN, 24);
f2 = new Font("Arial", Font.PLAIN, 16);
}
 
setBackground(new Color(230, 230, 230));
this.list = new ScrollableList(model) {
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(CaissePanel.LIGHT_BLUE);
g.setColor(Color.LIGHT_GRAY);
g.drawLine(0, 0, 0, this.getHeight());
}
 
88,12 → 96,12
public void mouseReleased(MouseEvent event) {
if ((event.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
final Object obj = getSelectedValue();
if (obj != null && obj instanceof Article) {
if (obj instanceof Article) {
Article product = (Article) obj;
Categorie.toggleFavoriteState(product);
controler.saveFavoriteProductsIds(Categorie.getFavoriteProducts());
model.setFilter(textField.getText());
list.scrollToOffset(0);
model.setFilter(ArticleSearchPanel.this.textField.getText());
ArticleSearchPanel.this.list.scrollToOffset(0);
}
} else {
super.mouseReleased(event);
124,7 → 132,7
bar.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
list.scrollToOffset(0);
ArticleSearchPanel.this.list.scrollToOffset(0);
}
});
 
135,29 → 143,34
// List
c.weighty = 1;
c.gridy++;
this.add(list, c);
this.list.setBackground(new Color(240, 240, 240));
this.add(this.list, c);
 
// Separator
c.weighty = 0;
c.gridy++;
this.add(new JSeparator(JSeparator.HORIZONTAL), c);
 
JPanel pBottom = new JPanel();
pBottom.setOpaque(true);
pBottom.setBackground(CaissePanel.DARK_BLUE);
pBottom.setLayout(new BorderLayout(3, 3));
 
// Icon and text
c.weighty = 0;
c.gridy++;
c.insets = new Insets(3, 3, 3, 3);
 
final JLabel label = new JLabel(new ImageIcon(this.getClass().getResource("search.png")));
c.gridwidth = 1;
c.weightx = 0;
this.add(label, c);
 
textField.setBorder(BorderFactory.createLineBorder(CaissePanel.DARK_BLUE, 1));
textField.setFont(f1);
pBottom.add(label, BorderLayout.WEST);
pBottom.setBorder(BorderFactory.createLineBorder(CaissePanel.DARK_BLUE, 3));
this.textField.setBorder(BorderFactory.createLineBorder(CaissePanel.DARK_BLUE, 1));
this.textField.setFont(f1);
 
this.textField.setFont(f1);
pBottom.add(this.textField, BorderLayout.CENTER);
c.gridy++;
c.weightx = 1;
c.gridx++;
c.gridwidth = 2;
this.add(pBottom, c);
 
textField.setFont(f1);
this.add(textField, c);
textField.getDocument().addDocumentListener(new DocumentListener() {
this.textField.getDocument().addDocumentListener(new DocumentListener() {
 
@Override
public void removeUpdate(DocumentEvent e) {
171,40 → 184,50
 
@Override
public void changedUpdate(DocumentEvent e) {
model.setFilter(textField.getText());
model.setFilter(ArticleSearchPanel.this.textField.getText());
controler.setArticleSelected(null);
}
});
list.addListSelectionListener(this);
this.list.addListSelectionListener(new ListSelectionListener() {
 
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int nb = e.getClickCount();
if (nb > 1) {
Object sel = list.getSelectedValue();
if (sel != null) {
public void valueChanged(ListSelectionEvent e) {
Object sel = ArticleSearchPanel.this.list.getSelectedValue();
if (sel != null && !e.getValueIsAdjusting()) {
if (sel instanceof Article) {
Article article = (Article) sel;
controler.incrementArticle(article);
controler.setArticleSelected(article);
 
}
}
 
}
});
}
 
this.list.addMouseListener(new MouseAdapter() {
@Override
public void valueChanged(ListSelectionEvent e) {
Object sel = list.getSelectedValue();
if (sel != null && !e.getValueIsAdjusting()) {
public void mouseClicked(MouseEvent e) {
Object sel = ArticleSearchPanel.this.list.getSelectedValue();
if (sel != null) {
int nb = e.getClickCount();
if (nb == 1) {
if (sel instanceof Article) {
Article article = (Article) sel;
controler.setArticleSelected(article);
controler.addArticle(article);
}
} else if (nb > 1) {
Article article = (Article) sel;
controler.incrementArticle(article);
controler.setArticleSelected(article);
}
}
 
}
});
 
}
 
public void paintCategorie(final Font f, Font f2, Graphics g, Categorie c, boolean isSelected, int posY, int cellWidth, int cellHeight) {
g.setFont(f);
 
248,7 → 271,7
if (c.getParent() == null) {
return null;
}
String storedString = categoryCache.get(c);
String storedString = this.categoryCache.get(c);
if (storedString != null) {
return storedString;
}
273,28 → 296,28
parent = c.getParent();
 
}
categoryCache.put(c, s);
this.categoryCache.put(c, s);
return s;
}
 
@Override
public void caisseStateChanged() {
final Article articleSelected = controler.getArticleSelected();
final Article articleSelected = this.controler.getArticleSelected();
System.err.println("ArticleSearchPanel.caisseStateChanged() article selected : " + articleSelected);
if (articleSelected == null) {
list.clearSelection();
this.list.clearSelection();
return;
}
Object selectedValue = null;
try {
selectedValue = list.getSelectedValue();
selectedValue = this.list.getSelectedValue();
} catch (Exception e) {
e.printStackTrace();
}
if (selectedValue == null || !articleSelected.equals(selectedValue)) {
boolean found = list.setSelectedValue(articleSelected, true);
boolean found = this.list.setSelectedValue(articleSelected, true);
if (!found) {
list.clearSelection();
this.list.clearSelection();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/PriceEditorPanel.java
15,6 → 15,7
 
import org.openconcerto.erp.core.common.ui.NumericTextField;
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
 
import java.awt.Color;
import java.awt.GridBagConstraints;
32,7 → 33,7
import javax.swing.event.DocumentListener;
 
public class PriceEditorPanel extends JPanel {
private final transient Article article;
private final transient TicketItem item;
private final POSLabel labelPrice;
private final POSRadioButton rHT;
private final POSRadioButton rTTC;
44,8 → 45,8
private final NumericTextField discountTextField;
private final NumericKeypadPanel keyPad;
 
public PriceEditorPanel(final CaisseFrame caisseFrame, final Article article) {
this.article = article;
public PriceEditorPanel(final CaisseFrame caisseFrame, final TicketItem item) {
this.item = item;
this.setBackground(Color.WHITE);
this.setOpaque(true);
this.setLayout(new GridBagLayout());
64,59 → 65,59
// Line 2
c.gridy++;
c.gridwidth = 1;
rTTC = new POSRadioButton("prix TTC");
rTTC.setSelected(true);
this.rTTC = new POSRadioButton("prix TTC");
this.rTTC.setSelected(true);
c.weightx = 0;
this.add(rTTC, c);
ttcTextField = new NumericTextField();
ttcTextField.setFont(title.getFont());
ttcTextField.setValue(article.getPriceWithTax());
ttcTextField.requestFocusInWindow();
this.add(this.rTTC, c);
this.ttcTextField = new NumericTextField();
this.ttcTextField.setFont(title.getFont());
this.ttcTextField.setValue(item.getArticle().getPriceWithTax());
this.ttcTextField.requestFocusInWindow();
c.gridx++;
c.weightx = 1;
this.add(ttcTextField, c);
this.add(this.ttcTextField, c);
// Line 3
c.gridy++;
rHT = new POSRadioButton("prix HT");
this.rHT = new POSRadioButton("prix HT");
c.gridx = 0;
c.weightx = 0;
this.add(rHT, c);
htTextField = new NumericTextField();
htTextField.setValue(article.getPriceWithoutTax());
htTextField.setFont(title.getFont());
this.add(this.rHT, c);
this.htTextField = new NumericTextField();
this.htTextField.setValue(item.getArticle().getPriceWithoutTax());
this.htTextField.setFont(title.getFont());
c.gridx++;
c.weightx = 1;
this.add(htTextField, c);
this.add(this.htTextField, c);
// Line 4
c.gridy++;
rDiscountPercent = new POSRadioButton("remise en %");
this.rDiscountPercent = new POSRadioButton("remise en %");
c.gridx = 0;
c.weightx = 0;
this.add(rDiscountPercent, c);
discountPercentTextField = new NumericTextField();
discountPercentTextField.setValue(BigDecimal.ZERO);
discountPercentTextField.setFont(title.getFont());
this.add(this.rDiscountPercent, c);
this.discountPercentTextField = new NumericTextField();
this.discountPercentTextField.setValue(BigDecimal.ZERO);
this.discountPercentTextField.setFont(title.getFont());
c.gridx++;
c.weightx = 1;
this.add(discountPercentTextField, c);
this.add(this.discountPercentTextField, c);
// Line 5
rDiscount = new POSRadioButton("remise HT");
this.rDiscount = new POSRadioButton("remise HT");
c.gridx = 0;
c.weightx = 0;
c.gridy++;
this.add(rDiscount, c);
discountTextField = new NumericTextField();
discountTextField.setValue(BigDecimal.ZERO);
discountTextField.setFont(title.getFont());
this.add(this.rDiscount, c);
this.discountTextField = new NumericTextField();
this.discountTextField.setValue(BigDecimal.ZERO);
this.discountTextField.setFont(title.getFont());
c.gridx++;
c.weightx = 1;
this.add(discountTextField, c);
this.add(this.discountTextField, c);
 
final ButtonGroup group = new ButtonGroup();
group.add(rHT);
group.add(rTTC);
group.add(rDiscountPercent);
group.add(rDiscount);
group.add(this.rHT);
group.add(this.rTTC);
group.add(this.rDiscountPercent);
group.add(this.rDiscount);
//
//
c.gridy++;
123,13 → 124,14
c.gridx = 0;
c.gridwidth = 2;
final POSLabel labelPriceOld = new POSLabel("Ancien Prix : ");
labelPriceOld.setText("Ancien Prix : " + TicketCellRenderer.toString(article.getPriceWithTax()) + "€ TTC, " + TicketCellRenderer.toString(article.getPriceWithoutTax()) + "€ HT");
labelPriceOld.setText(
"Ancien Prix : " + TicketCellRenderer.toString(item.getArticle().getPriceWithTax()) + "€ TTC, " + TicketCellRenderer.toString(item.getArticle().getPriceWithoutTax()) + "€ HT");
this.add(labelPriceOld, c);
 
c.gridy++;
c.gridx = 0;
labelPrice = new POSLabel("Nouveau Prix : ");
this.add(labelPrice, c);
this.labelPrice = new POSLabel("Nouveau Prix : ");
this.add(this.labelPrice, c);
 
c.gridy++;
c.gridx = 0;
146,7 → 148,7
 
@Override
public void actionPerformed(ActionEvent e) {
caisseFrame.getControler().setArticleHT(article, getHTFromUI());
caisseFrame.getControler().setArticleHT(item, getHTFromUI());
caisseFrame.showCaisse();
}
});
168,10 → 170,10
c.insets = new Insets(20, 20, 30, 20);
// Line 1
c.gridheight = 5;
keyPad = new NumericKeypadPanel(ttcTextField);
this.add(keyPad, c);
this.keyPad = new NumericKeypadPanel(this.ttcTextField);
this.add(this.keyPad, c);
 
updatePrice(article.getPriceWithoutTax());
updatePrice(item.getArticle().getPriceWithoutTax());
updateTextFields();
//
final ActionListener listenerRadio = new ActionListener() {
226,11 → 228,11
if (this.rHT.isSelected()) {
r = this.htTextField.getValue();
} else if (this.rTTC.isSelected()) {
r = Article.computePriceWithoutTax(this.ttcTextField.getValue(), this.article.getIdTaxe());
r = Article.computePriceWithoutTax(this.ttcTextField.getValue(), this.item.getArticle().getIdTaxe());
} else if (this.rDiscountPercent.isSelected()) {
r = this.article.getPriceWithoutTax().subtract(this.article.getPriceWithoutTax().multiply(this.discountPercentTextField.getValue().divide(new BigDecimal(100))));
r = this.item.getArticle().getPriceWithoutTax().subtract(this.item.getArticle().getPriceWithoutTax().multiply(this.discountPercentTextField.getValue().divide(new BigDecimal(100))));
} else if (this.rDiscount.isSelected()) {
r = this.article.getPriceWithoutTax().subtract(this.discountTextField.getValue());
r = this.item.getArticle().getPriceWithoutTax().subtract(this.discountTextField.getValue());
}
} catch (Exception e) {
e.printStackTrace();
237,30 → 239,30
}
if (r == null) {
// fallback if something wrong
r = this.article.getPriceWithoutTax();
r = this.item.getArticle().getPriceWithoutTax();
}
return r;
}
 
private void updatePrice(BigDecimal ht) {
BigDecimal ttc = Article.computePriceWithTax(ht, this.article.getIdTaxe());
labelPrice.setText("Nouveau Prix : " + TicketCellRenderer.toString(ttc) + "€ TTC, " + TicketCellRenderer.toString(ht) + "€ HT");
BigDecimal ttc = Article.computePriceWithTax(ht, this.item.getArticle().getIdTaxe());
this.labelPrice.setText("Nouveau Prix : " + TicketCellRenderer.toString(ttc) + "€ TTC, " + TicketCellRenderer.toString(ht) + "€ HT");
}
 
private void updateTextFields() {
this.invalidate();
htTextField.setVisible(false);
ttcTextField.setVisible(false);
discountPercentTextField.setVisible(false);
discountTextField.setVisible(false);
if (rHT.isSelected()) {
enableTextField(htTextField);
} else if (rTTC.isSelected()) {
enableTextField(ttcTextField);
} else if (rDiscountPercent.isSelected()) {
enableTextField(discountPercentTextField);
} else if (rDiscount.isSelected()) {
enableTextField(discountTextField);
this.htTextField.setVisible(false);
this.ttcTextField.setVisible(false);
this.discountPercentTextField.setVisible(false);
this.discountTextField.setVisible(false);
if (this.rHT.isSelected()) {
enableTextField(this.htTextField);
} else if (this.rTTC.isSelected()) {
enableTextField(this.ttcTextField);
} else if (this.rDiscountPercent.isSelected()) {
enableTextField(this.discountPercentTextField);
} else if (this.rDiscount.isSelected()) {
enableTextField(this.discountTextField);
}
this.validate();
repaint();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaisseControler.java
27,10 → 27,10
import org.openconcerto.erp.core.sales.pos.model.RegisterLogEntry.ReceiptEntry;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
import org.openconcerto.erp.preferences.TemplateNXProps;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.Pair;
import org.openconcerto.utils.StringUtils;
 
import java.awt.event.KeyEvent;
59,7 → 59,7
private Paiement paiementSelected;
private Ticket t;
private Client client = Client.NONE;
private List<CaisseListener> listeners = new ArrayList<CaisseListener>();
private List<CaisseListener> listeners = new ArrayList<>();
 
private final BarcodeReader r;
private Paiement p1 = new Paiement(Paiement.ESPECES);
67,6 → 67,7
private Paiement p3 = new Paiement(Paiement.CHEQUE);
private final CaisseFrame caisseFrame;
private final POSDisplay lcd;
private TicketItem ticketItemSelected;
 
public CaisseControler(CaisseFrame caisseFrame) throws ParseException, JDOMException, IOException {
this.caisseFrame = caisseFrame;
95,9 → 96,9
this.r.start();
this.r.addBarcodeListener(this);
if (posConf.getLCDType().equals("serial")) {
lcd = new ESCSerialDisplay(posConf.getLCDPort());
this.lcd = new ESCSerialDisplay(posConf.getLCDPort());
} else {
lcd = new PrinterPOSDisplay(posConf.getLCDPort());
this.lcd = new PrinterPOSDisplay(posConf.getLCDPort());
}
this.setLCDDefaultDisplay(0);
}
119,7 → 120,7
}
 
void setArticleSelected(Article a) {
if (a != articleSelected) {
if (a != this.articleSelected) {
this.articleSelected = a;
this.paiementSelected = null;
fire();
129,6 → 130,7
void setPaiementSelected(Paiement p) {
this.paiementSelected = p;
this.articleSelected = null;
this.ticketItemSelected = null;
fire();
}
 
159,9 → 161,13
}
 
public Client getClient() {
return client;
return this.client;
}
 
public void setCodePostal(String codePostal) {
this.t.setCodePostal(codePostal);
}
 
// Articles
public void addArticle(Article a) {
this.t.addArticle(a);
225,20 → 231,20
 
//
 
public List<Pair<Article, Integer>> getItems() {
return this.t.getArticles();
public List<TicketItem> getItems() {
return this.t.getItems();
}
 
public int getItemCount(Article article) {
public BigDecimal getItemCount(Article article) {
return this.t.getItemCount(article);
}
 
public void clearArticle(Article article) {
this.t.clearArticle(article);
this.setArticleSelected(null);
this.setTicketItemSelected(null);
}
 
public void setArticleCount(Article article, int count) {
public void setArticleCount(Article article, BigDecimal count) {
this.t.setArticleCount(article, count);
this.setArticleSelected(null);
}
258,15 → 264,10
} else if (code.equalsIgnoreCase("annuler")) {
if (this.articleSelected != null) {
this.clearArticle(this.articleSelected);
 
} else {
if (this.paiementSelected != null) {
} else if (this.paiementSelected != null) {
this.paiementSelected.setMontantInCents(0);
// setPaiementSelected(null);
fire();
}
 
}
} else if (code.equalsIgnoreCase("valider")) {
 
} else if (code.equalsIgnoreCase("facture")) {
284,7 → 285,7
Ticket t = Ticket.getTicketFromCode(code, this.caisseFrame.getFiles());
if (t != null) {
System.err.println("CaisseControler.barcodeRead() barcode : " + code + " : receipt found :" + t.getNumber());
caisseFrame.showTickets(t);
this.caisseFrame.showTickets(t);
}
}
}
325,7 → 326,7
 
@Override
public void keyReceived(KeyEvent ee) {
 
// nothing
}
 
public static String getCents(int cents) {
337,9 → 338,7
}
 
public static String getEuros(int cents) {
String s = String.valueOf(cents / 100);
 
return s;
return String.valueOf(cents / 100);
}
 
public Ticket saveAndClearTicket(final RegisterFiles files, final SQLElementDirectory dir) throws IOException, SQLException {
349,16 → 348,16
final String fileHash = this.t.save(files, dir);
final Ticket res = this.t;
final int newIndex = this.t.getNumber() + 1;
t = new Ticket(getPOSConf().getPosID(), newIndex, fileHash);
p1 = new Paiement(Paiement.ESPECES);
p2 = new Paiement(Paiement.CB);
p3 = new Paiement(Paiement.CHEQUE);
this.t = new Ticket(getPOSConf().getPosID(), newIndex, fileHash);
this.p1 = new Paiement(Paiement.ESPECES);
this.p2 = new Paiement(Paiement.CB);
this.p3 = new Paiement(Paiement.CHEQUE);
this.t.addPaiement(this.p1);
this.t.addPaiement(this.p2);
this.t.addPaiement(this.p3);
this.setPaiementSelected(null);
this.setArticleSelected(null);
client = Client.NONE;
this.client = Client.NONE;
return res;
}
 
377,7 → 376,7
}
 
public void switchListMode() {
caisseFrame.mainPanel.switchListMode();
this.caisseFrame.mainPanel.switchListMode();
 
}
 
386,7 → 385,7
@Override
public void run() {
try {
lcd.setMessage(line1, line2);
CaisseControler.this.lcd.setMessage(line1, line2);
} catch (Exception e) {
e.printStackTrace();
}
393,17 → 392,22
}
};
final Timer timer = new Timer("LCD : " + line1, true);
timer.schedule(task, delay * 1000);
timer.schedule(task, delay * 1000L);
 
}
 
public void setLCDDefaultDisplay(int delay) {
if (t.getTotalInCents() > 0) {
if (this.t.getTotalInCents() > 0) {
int count = 0;
final List<Pair<Article, Integer>> articles = t.getArticles();
for (Pair<Article, Integer> pair : articles) {
count += pair.getSecond();
final List<TicketItem> articles = this.t.getItems();
for (TicketItem pair : articles) {
Article a = pair.getArticle();
if (a.getSalesUnit() == null) {
count += pair.getQty().intValue();
} else {
count++;
}
}
String line1;
if (count == 1) {
line1 = "1 article";
410,7 → 414,7
} else {
line1 = count + " articles";
}
int cents = t.getTotalInCents();
int cents = this.t.getTotalInCents();
setLCD(line1, "Total : " + TicketCellRenderer.centsToString(cents), delay);
} else {
setLCD(getPOSConf().getLCDLine1(), getPOSConf().getLCDLine2(), delay);
421,7 → 425,7
 
final String creditCardPort = getPOSConf().getCreditCardPort();
if (creditCardPort != null && creditCardPort.trim().length() > 2) {
final Thread t = new Thread(new Runnable() {
final Thread thread = new Thread(new Runnable() {
 
@Override
public void run() {
438,33 → 442,22
}
}
});
t.setDaemon(true);
t.start();
thread.setDaemon(true);
thread.start();
 
}
 
}
 
public void setArticleHT(Article article, BigDecimal ht) {
Article existingArticle = null;
final List<Pair<Article, Integer>> articles = t.getArticles();
for (Pair<Article, Integer> pair : articles) {
final Article a = pair.getFirst();
if (a.getId() == article.getId()) {
if (article.getPriceWithoutTax().doubleValue() == a.getPriceWithoutTax().doubleValue()) {
existingArticle = a;
break;
}
}
}
if (existingArticle != null) {
existingArticle.updatePriceWithoutTax(ht);
public void setArticleHT(TicketItem item, BigDecimal ht) {
final Article newArticle = new Article(item.getArticle());
newArticle.updatePriceWithoutTax(ht);
item.setArticle(newArticle);
fire();
}
}
 
public void openPriceEditor(Article article) {
caisseFrame.showPriceEditor(article, this);
public void openPriceEditor(TicketItem item) {
this.caisseFrame.showPriceEditor(item, this);
}
 
public void enableBarcodeReader() {
476,7 → 469,7
}
 
public boolean isTicketValid() {
return (!this.t.getArticles().isEmpty()) && ((this.getTotal() >= 0 && this.getPaidTotal() >= this.getTotal()) || (this.getTotal() < 0 && this.getPaidTotal() == this.getTotal()));
return (!this.t.getItems().isEmpty()) && ((this.getTotal() >= 0 && this.getPaidTotal() >= this.getTotal()) || (this.getTotal() < 0 && this.getPaidTotal() == this.getTotal()));
}
 
public Set<Integer> loadFavoriteProductsIds() {
515,4 → 508,43
}
}
 
public void setTicketItemSelected(TicketItem item) {
this.ticketItemSelected = item;
if (item == null) {
this.articleSelected = null;
} else {
this.articleSelected = item.getArticle();
this.paiementSelected = null;
}
fire();
 
}
 
public TicketItem getTicketItemSelected() {
return this.ticketItemSelected;
}
 
public void removeTicketItem(TicketItem item) {
this.t.removeTicketItem(item);
this.setTicketItemSelected(null);
}
 
public void cancel(Ticket ticket) {
this.t.clear();
// Annulation du ticket
for (TicketItem a : ticket.getItems()) {
final Article article = a.getArticle();
TicketItem item = new TicketItem(article, a.getQty().multiply(new BigDecimal(-1)));
this.t.addItem(item);
}
for (Paiement p : ticket.getPaiements()) {
final Paiement paiement = new Paiement(p.getType());
paiement.setMontantInCents(-1 * p.getMontantInCents());
this.t.addPaiement(paiement);
}
 
this.caisseFrame.showCaisse();
fire();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/RegisterSummary.java
23,6 → 23,7
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
 
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
56,7 → 57,7
 
public abstract String getLabel();
 
protected abstract List<Ticket> getReceipts() throws ParseException;
protected abstract List<Ticket> getReceipts() throws ParseException, IOException;
 
@Override
public void print(TicketPrinter prt, int ticketWidth) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/TicketPanel.java
17,8 → 17,8
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.RegisterState;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
import org.openconcerto.ui.touch.ScrollableList;
import org.openconcerto.utils.Pair;
 
import java.awt.Color;
import java.awt.Dimension;
45,27 → 45,27
 
public class TicketPanel extends JPanel implements CaisseListener {
 
static private final DateFormat DF = new SimpleDateFormat("' le' EEEE d MMMM à H:mm:ss");
 
private final DateFormat df = new SimpleDateFormat("' le' d MMMM à H:mm");
private final Image bg;
 
private final ListModel dataModel;
private final List<ListDataListener> listeners = new ArrayList<ListDataListener>();
JLabel lTotal = new JLabel("", SwingConstants.RIGHT);
JLabel lNumero = new JLabel("", SwingConstants.LEFT);
private final ListModel<TicketItem> dataModel;
private final List<ListDataListener> listeners = new ArrayList<>();
private final JLabel lTotal = new JLabel("", SwingConstants.RIGHT);
private final JLabel lNumero = new JLabel("", SwingConstants.LEFT);
private final CaisseControler controler;
 
private final ScrollableList list;
private int xOffset = 0;
 
TicketPanel(final CaisseControler controler) {
this.controler = controler;
this.controler.addCaisseListener(this);
 
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
this.xOffset = -24;
}
this.setOpaque(false);
this.bg = new ImageIcon(TicketPanel.class.getResource("ticket.png")).getImage();
this.setLayout(null);
 
this.dataModel = new ListModel() {
this.dataModel = new ListModel<TicketItem>() {
 
@Override
public void addListDataListener(final ListDataListener l) {
73,7 → 73,7
}
 
@Override
public Object getElementAt(final int index) {
public TicketItem getElementAt(final int index) {
return controler.getItems().get(index);
}
 
95,22 → 95,22
@Override
public void paintCell(final Graphics g, final Object value, final int index, final boolean isSelected, final int posY) {
g.translate(0, posY);
this.renderer.paint(g, TicketPanel.this.list, value, index, isSelected);
this.renderer.paint(g, TicketPanel.this.list, (TicketItem) value, index, isSelected);
g.translate(0, -posY);
}
};
this.list.setOpaque(false);
this.list.setSize(276, 450);
this.list.setSize(315, 450);
this.list.setFixedCellHeight(40);
this.list.setLocation(68, 18);
this.list.setLocation(30 + this.xOffset, 18);
this.add(this.list);
 
this.lTotal.setSize(276 - 10, 32);
this.lTotal.setLocation(68, 500 - 32);
this.lTotal.setLocation(68 + this.xOffset, 500 - 32);
this.lTotal.setFont(new Font("Arial", Font.BOLD, 18));
this.add(this.lTotal);
this.lNumero.setSize(276 - 10, 32);
this.lNumero.setLocation(68, 500);
this.lNumero.setLocation(68 + this.xOffset, 500);
this.lNumero.setForeground(Color.DARK_GRAY);
this.lNumero.setFont(new Font("Arial", Font.BOLD, 12));
this.add(this.lNumero);
122,12 → 122,13
if (!e.getValueIsAdjusting()) {
final Object selectedValue = TicketPanel.this.list.getSelectedValue();
if (selectedValue != null) {
final Article a = ((Pair<Article, Integer>) selectedValue).getFirst();
controler.setArticleSelected(a);
TicketItem item = (TicketItem) selectedValue;
controler.setTicketItemSelected(item);
// If the category of the selected article does not match the current
// category of the categories list,
// then the corresponding article is not selected.
controler.setArticleSelected(a); // Dirty fix : use two refresh
controler.setTicketItemSelected(item); // Dirty fix : use two refresh
 
}
}
 
138,19 → 139,28
 
@Override
protected void paintComponent(final Graphics g) {
g.drawImage(this.bg, 0, 0, null);
g.drawImage(this.bg, this.xOffset, 0, null);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
try {
final RegisterState registerState = this.controler.getCaisseFrame().getFiles().getLastLog().getRegisterState();
 
// Display caisse and Vendor ID
String InfoCaisseVendeur = "Caisse " + this.controler.getPOSConf().getPosID() + " Vendeur " + this.controler.getPOSConf().getUserID();
final String infoCaisseVendeur = "Caisse " + this.controler.getPOSConf().getPosID() + " Vendeur " + this.controler.getPOSConf().getUserID();
final String infoCaisse = (registerState.getStatus() == Status.OPEN ? "Ouverte" : "Fermée") + registerState.formatDate(this.df);
g.setColor(new Color(230, 230, 230));
g.setFont(getFont().deriveFont(28.0f));
g.drawString(InfoCaisseVendeur, 20, this.getHeight() - 50);
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
g.setFont(getFont().deriveFont(16.0f));
} else {
g.setFont(getFont().deriveFont(14.0f));
}
int w1 = g.getFontMetrics().stringWidth(infoCaisseVendeur);
int w2 = g.getFontMetrics().stringWidth(infoCaisse);
 
int x = 330 - Math.max(w1, w2) + this.xOffset;
g.drawString(infoCaisseVendeur, x, this.getHeight() - 40);
g.setColor(Color.LIGHT_GRAY);
g.setFont(getFont().deriveFont(18.0f));
final RegisterState registerState = this.controler.getCaisseFrame().getFiles().getLastLog().getRegisterState();
g.drawString("Caisse " + (registerState.getStatus() == Status.OPEN ? "ouverte" : "fermée") + registerState.formatDate(DF), 20, this.getHeight() - 25);
 
g.drawString(infoCaisse, x, this.getHeight() - 25);
} catch (Exception e) {
POSConfiguration.getLogger().log(Level.WARNING, "Couldn't find register state", e);
}
157,14 → 167,28
super.paintComponent(g);
}
 
int getMinWidth() {
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
return 330;
}
return 480;
}
 
int getMaxHeight() {
if (this.controler.getPOSConf().getScreenHeight() < 1000) {
return 550;
}
return 707;
}
 
@Override
public Dimension getMinimumSize() {
return new Dimension(480, 550);
return new Dimension(getMinWidth(), 550);
}
 
@Override
public Dimension getPreferredSize() {
return new Dimension(480, 707);
return new Dimension(getMinWidth(), getMaxHeight());
}
 
public void fire() {
189,7 → 213,7
}
try {
// Deja selectionné
if (this.list.getSelectedValue() != null && articleSelected != null && articleSelected.equals(((Pair<Article, Integer>) this.list.getSelectedValue()).getFirst())) {
if (this.list.getSelectedValue() != null && articleSelected.equals(((TicketItem) this.list.getSelectedValue()).getArticle())) {
return;
}
} catch (final Exception e) {
196,16 → 220,14
e.printStackTrace();
}
 
if (articleSelected != null) {
 
for (int i = 0; i < this.dataModel.getSize(); i++) {
final Pair<Article, Integer> item = (Pair<Article, Integer>) this.dataModel.getElementAt(i);
if (item.getFirst().equals(articleSelected)) {
final TicketItem item = this.dataModel.getElementAt(i);
if (item.getArticle().equals(articleSelected)) {
this.list.setSelectedValue(item, true);
break;
}
}
 
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/TicketCellRenderer.java
14,8 → 14,8
package org.openconcerto.erp.core.sales.pos.ui;
 
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
import org.openconcerto.ui.touch.ScrollableList;
import org.openconcerto.utils.Pair;
 
import java.awt.Color;
import java.awt.Component;
35,12 → 35,11
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
 
public class TicketCellRenderer implements ListCellRenderer {
public class TicketCellRenderer implements ListCellRenderer<TicketItem> {
 
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
@SuppressWarnings("unchecked")
Pair<Article, Integer> item = (Pair<Article, Integer>) value;
public Component getListCellRendererComponent(JList<? extends TicketItem> list, TicketItem item, int index, boolean isSelected, boolean cellHasFocus) {
 
JPanel p = new JPanel();
p.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
48,12 → 47,12
 
c.fill = GridBagConstraints.HORIZONTAL;
c.insets = new Insets(5, 5, 5, 5);
final JLabel l1 = new JLabel(item.getSecond().toString(), SwingConstants.RIGHT);
final JLabel l1 = new JLabel(item.getArticle().toString(), SwingConstants.RIGHT);
 
p.add(l1, c);
c.gridx++;
c.weightx = 1;
Article article = item.getFirst();
Article article = item.getArticle();
final JLabel l2 = new JLabel(article.getName().toUpperCase(), SwingConstants.LEFT);
p.add(l2, c);
c.gridx++;
82,9 → 81,7
return p;
}
 
public void paint(Graphics g, ScrollableList list, Object value, int index, boolean isSelected) {
@SuppressWarnings("unchecked")
final Pair<Article, Integer> item = (Pair<Article, Integer>) value;
public void paint(Graphics g, ScrollableList list, TicketItem item, int index, boolean isSelected) {
 
if (isSelected) {
g.setColor(new Color(232, 242, 254));
97,20 → 94,34
g.setFont(new Font("Arial", Font.PLAIN, 16));
final int height = g.getFontMetrics().getMaxAscent() + g.getFontMetrics().getMaxDescent() + inset;
 
final String s1 = item.getSecond().toString();
System.err.println("TicketCellRenderer.paint()" + item);
 
Article article = item.getArticle();
final BigDecimal qty = item.getQty();
String s1 = qty.toString();
if (article.getSalesUnit() != null) {
s1 = qty.toString() + article.getSalesUnit();
}
g.drawString(s1, inset, height);
final int width1 = (int) g.getFontMetrics().getStringBounds("999 ", g).getWidth() + inset * 2;
final int width1 = (int) g.getFontMetrics().getStringBounds("1999kg ", g).getWidth() + inset * 2;
 
Article article = item.getFirst();
String s2 = article.getName().toUpperCase();
final int maxLength = 13;
String s2 = article.getName().toUpperCase().trim();
 
final int maxLength = 15;
if (s2.length() > maxLength)
s2 = s2.substring(0, maxLength + 1) + '…';
g.drawString(s2, width1 + inset, height);
 
final String s3 = centsToString(article.getPriceWithTax().movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue());
final int width3 = (int) g.getFontMetrics().getStringBounds(s3, g).getWidth() + inset * 2;
g.drawString(s3, list.getWidth() - width3, height);
final String s3 = centsToString(article.getPriceWithTax().multiply(qty).movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()) + "€";
final int width3 = (int) g.getFontMetrics().getStringBounds(s3, g).getWidth() + +inset;
g.drawString(s3, list.getWidth() - width3, height - 4);
 
g.setFont(g.getFont().deriveFont(12f));
final String s4 = qty.toPlainString() + " x " + centsToString(article.getPriceWithTax().movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue());
 
final int width4 = (int) g.getFontMetrics().getStringBounds(s4, g).getWidth() + +inset;
g.drawString(s4, list.getWidth() - width4, height + 11);
 
}
 
public static String centsToString(int cents) {
125,4 → 136,5
public static String toString(final BigDecimal p) {
return centsToString(p.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue());
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/PaiementPanel.java
15,6 → 15,7
 
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.Paiement;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
 
import java.awt.Color;
import java.awt.Dimension;
26,6 → 27,7
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.math.BigDecimal;
import java.util.List;
 
import javax.swing.JOptionPane;
66,14 → 68,16
 
@Override
public void paint(Graphics g) {
 
Graphics2D g2 = (Graphics2D) g;
g.setColor(new Color(250, 250, 250));
g.fillRect(0, 0, this.getWidth(), this.getHeight());
 
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.LIGHT_GRAY);
g.drawLine(0, 0, 0, this.getHeight());
int y = PAYMENT_POS_Y;
for (Paiement p : controller.getPaiements()) {
for (Paiement p : this.controller.getPaiements()) {
if (p.getType() == Paiement.CB) {
drawMontant(g, "CB", p, 242 - 15, y, true);
} else if (p.getType() == Paiement.CHEQUE) {
109,6 → 113,7
 
drawCalculator(g);
super.paint(g);
 
}
 
private void drawKey(Graphics2D g2, String string, int col, int row, int w, int h, Color color) {
137,7 → 142,7
Graphics2D g2 = (Graphics2D) g;
 
// LCD
if (controller.getArticleSelected() != null || controller.getPaiementSelected() != null) {
if (this.controller.getArticleSelected() != null || this.controller.getPaiementSelected() != null) {
g.setColor(new Color(232, 242, 254));
} else {
g.setColor(new Color(240, 240, 240));
147,10 → 152,10
int y = this.getHeight() - this.calcHeight - 10;
g.setFont(new Font("Arial", Font.PLAIN, 32));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final Article article = controller.getArticleSelected();
final Article article = this.controller.getArticleSelected();
g.setColor(Color.DARK_GRAY);
if (article != null) {
String string = calculatorValue;
String string = this.calculatorValue;
g.setFont(g.getFont().deriveFont(52f));
Rectangle2D r1 = g.getFontMetrics().getStringBounds(string, g2);
g.drawString(string, (int) (260 - r1.getWidth()), y);
158,9 → 163,9
g.drawString("Quantité", 10, 460 + y);
 
} else {
final Paiement paiement = controller.getPaiementSelected();
final Paiement paiement = this.controller.getPaiementSelected();
if (paiement != null) {
String string = calculatorValue;
String string = this.calculatorValue;
g.setFont(g.getFont().deriveFont(52f));
Rectangle2D r1 = g.getFontMetrics().getStringBounds(string, g2);
g.drawString(string, (int) (260 - r1.getWidth()), y);
179,7 → 184,7
}
}
g.setFont(g.getFont().deriveFont(14f));
g.drawString("" + mode, 10, y - 20);
g.drawString("" + this.mode, 10, y - 20);
}
 
private char getToucheFrom(int x, int y) {
299,23 → 304,23
 
@Override
public Dimension getPreferredSize() {
return new Dimension(calcWidth, 768);
return new Dimension(this.calcWidth, 768);
}
 
public Dimension getMinimumSize() {
return new Dimension(calcWidth, 768);
return new Dimension(this.calcWidth, 768);
}
 
@Override
public void caisseStateChanged() {
if (controller.getArticleSelected() != null) {
if (this.controller.getArticleSelected() != null) {
initCaisseArticle();
} else if (controller.getPaiementSelected() != null) {
} else if (this.controller.getPaiementSelected() != null) {
initCaissePaiement();
}
// Add / Remove solde if needed
boolean soldeIsShown = false;
for (Paiement p : controller.getPaiements()) {
for (Paiement p : this.controller.getPaiements()) {
if (p.getType() == Paiement.SOLDE) {
soldeIsShown = true;
break;
322,19 → 327,19
}
}
 
if (controller.isClientDefined()) {
if (!soldeIsShown && controller.getClient().getSolde().signum() == 1) {
if (this.controller.isClientDefined()) {
if (!soldeIsShown && this.controller.getClient().getSolde().signum() == 1) {
// add
controller.addPaiement(new Paiement(Paiement.SOLDE));
this.controller.addPaiement(new Paiement(Paiement.SOLDE));
}
} else {
if (soldeIsShown) {
// remove
final List<Paiement> paiements = controller.getPaiements();
final List<Paiement> paiements = this.controller.getPaiements();
for (int i = 0; i < paiements.size(); i++) {
final Paiement p = paiements.get(i);
if (p.getType() == Paiement.SOLDE) {
controller.getPaiements().remove(i);
this.controller.getPaiements().remove(i);
break;
}
}
345,15 → 350,19
}
 
private void initCaisseArticle() {
calculatorValue = String.valueOf(controller.getItemCount(controller.getArticleSelected()));
init = true;
mode = ' ';
if (this.controller.getTicketItemSelected() != null) {
this.calculatorValue = this.controller.getTicketItemSelected().getQty().toPlainString();
} else {
this.calculatorValue = "";
}
this.init = true;
this.mode = ' ';
}
 
private void initCaissePaiement() {
calculatorValue = TicketCellRenderer.centsToString(controller.getPaiementSelected().getMontantInCents());
init = true;
mode = ' ';
this.calculatorValue = TicketCellRenderer.centsToString(this.controller.getPaiementSelected().getMontantInCents());
this.init = true;
this.mode = ' ';
}
 
@Override
384,32 → 393,32
} else {
Paiement p = getPaiementFrom(e.getY());
if (p != null) {
if (e.getX() > this.getWidth() - 68 && p.getType() != Paiement.ESPECES && controller.canAddPaiement(p.getType())) {
if (e.getX() > this.getWidth() - 68 && p.getType() != Paiement.ESPECES && this.controller.canAddPaiement(p.getType())) {
p = new Paiement(p.getType());
controller.addPaiement(p);
this.controller.addPaiement(p);
}
controller.autoFillPaiement(p);
this.controller.autoFillPaiement(p);
this.calculatorValue = TicketCellRenderer.centsToString(p.getMontantInCents());
if (p.getType() == Paiement.ESPECES) {
try {
controller.openDrawer();
this.controller.openDrawer();
} catch (Throwable ex) {
JOptionPane.showMessageDialog(PaiementPanel.this, "Ouverture du tiroir caisse impossible");
}
} else if (p.getType() == Paiement.CB) {
controller.sendCBRequest(p);
this.controller.sendCBRequest(p);
}
 
}
controller.setPaiementSelected(p);
this.controller.setPaiementSelected(p);
}
}
 
public void lcdPressed() {
System.err.println("PaiementPanel.lcdPressed()");
final Article articleSelected = controller.getArticleSelected();
final TicketItem articleSelected = this.controller.getTicketItemSelected();
if (articleSelected != null) {
controller.openPriceEditor(articleSelected);
this.controller.openPriceEditor(articleSelected);
}
repaint();
 
419,10 → 428,10
System.out.println("Handle: " + c);
if (c == '?')
return;
final Article article = controller.getArticleSelected();
final TicketItem article = this.controller.getTicketItemSelected();
 
if (c == '+' || c == '-' || c == '*') {
mode = c;
this.mode = c;
 
repaint();
return;
432,66 → 441,71
// Changement de quantité
if (c == 'c' || c == '/') {
System.out.println("Clear quantité");
mode = ' ';
controller.clearArticle(article);
this.mode = ' ';
this.controller.removeTicketItem(article);
} else if (c == '=' || c == '\n') {
if (!init) {
int v = Integer.parseInt(calculatorValue);
if (mode == ' ') {
controller.setArticleCount(article, v);
} else if (mode == '+') {
controller.setArticleCount(article, controller.getItemCount(article) + v);
} else if (mode == '-') {
controller.setArticleCount(article, controller.getItemCount(article) - v);
} else if (mode == '*') {
controller.setArticleCount(article, controller.getItemCount(article) * v);
if (!this.init) {
BigDecimal v = new BigDecimal(this.calculatorValue);
if (this.mode == ' ') {
article.setQty(v);
} else if (this.mode == '+') {
article.setQty(article.getQty().add(v));
} else if (this.mode == '-') {
article.setQty(article.getQty().subtract(v));
} else if (this.mode == '*') {
article.setQty(article.getQty().multiply(v));
}
// Reselect to fire a refresh
this.controller.setTicketItemSelected(article);
}
initCaisseArticle();
} else if (Character.isDigit(c)) {
if (init) {
calculatorValue = "";
init = false;
if (this.init) {
this.calculatorValue = "";
this.init = false;
}
if (calculatorValue.length() < 8) {
calculatorValue += c;
if (this.calculatorValue.length() < 8) {
this.calculatorValue += c;
}
}
if (article.getArticle().getSalesUnit() != null && c == '.' && (this.calculatorValue.indexOf('.') < 0)) {
this.calculatorValue += ".";
}
 
} else {
final Paiement paiement = controller.getPaiementSelected();
final Paiement paiement = this.controller.getPaiementSelected();
if (paiement != null) {
// Changement de paiement
if (c == 'c' || c == '/') {
System.out.println("Clear paiement");
mode = ' ';
controller.clearPaiement(paiement);
} else if (c == '.' && (calculatorValue.indexOf('.') < 0)) {
calculatorValue += ".";
this.mode = ' ';
this.controller.clearPaiement(paiement);
} else if (c == '.' && (this.calculatorValue.indexOf('.') < 0)) {
this.calculatorValue += ".";
} else if (c == '=' || c == '\n') {
if (!init) {
if (!this.init) {
int v = getCentsFrom(this.calculatorValue);
if (mode == ' ') {
controller.setPaiementValue(paiement, v);
} else if (mode == '+') {
controller.setPaiementValue(paiement, paiement.getMontantInCents() + v);
} else if (mode == '-') {
controller.setPaiementValue(paiement, paiement.getMontantInCents() - v);
} else if (mode == '*') {
controller.setPaiementValue(paiement, paiement.getMontantInCents() * v);
if (this.mode == ' ') {
this.controller.setPaiementValue(paiement, v);
} else if (this.mode == '+') {
this.controller.setPaiementValue(paiement, paiement.getMontantInCents() + v);
} else if (this.mode == '-') {
this.controller.setPaiementValue(paiement, paiement.getMontantInCents() - v);
} else if (this.mode == '*') {
this.controller.setPaiementValue(paiement, paiement.getMontantInCents() * v);
}
}
initCaissePaiement();
controller.setPaiementSelected(null);
this.controller.setPaiementSelected(null);
} else if (Character.isDigit(c)) {
if (init) {
calculatorValue = "";
init = false;
if (this.init) {
this.calculatorValue = "";
this.init = false;
}
if (calculatorValue.length() < 9) {
int i = calculatorValue.indexOf('.');
if (i < 0 || (calculatorValue.length() - i < 3)) {
calculatorValue += c;
if (this.calculatorValue.length() < 9) {
int i = this.calculatorValue.indexOf('.');
if (i < 0 || (this.calculatorValue.length() - i < 3)) {
this.calculatorValue += c;
}
}
}
534,8 → 548,8
 
private Paiement getPaiementFrom(int y) {
int index = (y - PAYMENT_POS_Y) / PAYMENT_LINE_HEIGHT;
if (index < controller.getPaiements().size() && index >= 0) {
return controller.getPaiements().get(index);
if (index < this.controller.getPaiements().size() && index >= 0) {
return this.controller.getPaiements().get(index);
}
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaisseFrame.java
16,7 → 16,6
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.config.Gestion;
import org.openconcerto.erp.core.sales.pos.POSConfiguration;
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.Client;
import org.openconcerto.erp.core.sales.pos.model.DBState;
import org.openconcerto.erp.core.sales.pos.model.ReceiptCode;
26,6 → 25,7
import org.openconcerto.erp.core.sales.pos.model.RegisterState;
import org.openconcerto.erp.core.sales.pos.model.RegisterState.Status;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
import org.openconcerto.erp.utils.TM;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.RemoteShell;
225,11 → 225,6
public void run() {
 
try {
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
try {
CaisseFrame f = new CaisseFrame(posConf, conf, registerFiles, registerDB);
f.setUndecorated(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
248,9 → 243,9
}
System.out.println("Affichage de l'interface");
f.setVisible(true);
if (screenSize.getWidth() < 1280 || screenSize.getHeight() < 720) {
if (screenSize.getWidth() < 1024 || screenSize.getHeight() < 720) {
JOptionPane.showMessageDialog(f,
"La résolution de votre écran est trop faible.\nLa largeur doit être au minium de 1280 pixels.\nLa hauteur doit être au minium de 720 pixels.");
"La résolution de votre écran est trop faible.\nLa largeur doit être au minium de 1024 pixels.\nLa hauteur doit être au minium de 720 pixels.");
}
} catch (Throwable e) {
// Catch throwable to be able to see NoClassDefFound and other hard issues
515,11 → 510,11
this.repaint();
}
 
public void showPriceEditor(Article article, CaisseControler caisseControler) {
public void showPriceEditor(TicketItem item, CaisseControler caisseControler) {
getControler().disableBarcodeReader();
System.out.println("CaisseFrame.showPriceEditor()");
this.invalidate();
final PriceEditorPanel panel = new PriceEditorPanel(this, article);
final PriceEditorPanel panel = new PriceEditorPanel(this, item);
 
final POSGlassPane glassPane2 = new POSGlassPane(panel, (getWidth() - panel.getPreferredSize().width) / 2, 100) {
@Override
585,4 → 580,16
this.validate();
this.repaint();
}
 
public void showPostalCodeFrame(CaissePanel caissePanel) {
System.out.println("CaisseFrame.showPostalCodeFrame()");
this.invalidate();
final PostalCodeEditorPanel panel = new PostalCodeEditorPanel(this, caissePanel);
final POSGlassPane glassPane2 = new POSGlassPane(panel, (getWidth() - panel.getPreferredSize().width) / 2, 100);
this.setGlassPane(glassPane2);
this.getGlassPane().setVisible(true);
this.validate();
this.repaint();
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/ListeDesTicketsPanel.java
16,7 → 16,6
import org.openconcerto.erp.core.sales.pos.TicketPrinterConfiguration;
import org.openconcerto.erp.core.sales.pos.io.Printable;
import org.openconcerto.erp.core.sales.pos.io.TicketPrinter;
import org.openconcerto.erp.core.sales.pos.model.Article;
import org.openconcerto.erp.core.sales.pos.model.RegisterFiles;
import org.openconcerto.erp.core.sales.pos.model.RegisterLog;
import org.openconcerto.erp.core.sales.pos.model.Ticket;
23,7 → 22,6
import org.openconcerto.ui.DefaultListModel;
import org.openconcerto.ui.touch.ScrollableList;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Pair;
 
import java.awt.Color;
import java.awt.Component;
111,7 → 109,7
}
 
@Override
protected final List<Ticket> getReceipts() throws ParseException {
protected final List<Ticket> getReceipts() throws ParseException, IOException {
return this.getLog().parseReceipts();
}
 
160,22 → 158,22
try {
final RegisterLog lastLog = this.frame.getFiles().getLastLog();
final List<Ticket> receipts = lastLog.parseReceipts();
ticketLlistModel = new DefaultListModel();
ticketLlistModel.addElement(new X(lastLog, receipts));
ticketLlistModel.addElement(new XLite(lastLog, receipts));
this.ticketLlistModel = new DefaultListModel();
this.ticketLlistModel.addElement(new X(lastLog, receipts));
this.ticketLlistModel.addElement(new XLite(lastLog, receipts));
final Date previousDate = lastLog.getFirstRegisterEvent().getPreviousDate();
if (previousDate != null) {
final Calendar cal = Calendar.getInstance();
cal.setTime(previousDate);
ticketLlistModel.addElement(new Z(this.frame.getFiles(), cal));
this.ticketLlistModel.addElement(new Z(this.frame.getFiles(), cal));
}
ticketLlistModel.addAll(receipts);
this.ticketLlistModel.addAll(receipts);
 
} catch (Exception exn) {
ExceptionHandler.handle(this.frame, "Impossible de charger les tickets", exn);
}
final Font f = new Font(ARIAL_FONT, Font.PLAIN, 24);
ticketList = new ScrollableList(ticketLlistModel) {
this.ticketList = new ScrollableList(this.ticketLlistModel) {
@Override
public void paintCell(Graphics g, Object object, int index, boolean isSelected, int posY) {
g.setFont(f);
211,24 → 209,25
}
}
};
this.add(ticketList, c);
this.add(this.ticketList, c);
// Ticket
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0;
c.gridx++;
c.gridheight = 1;
c.insets = new Insets(10, 10, 10, 10);
ticketP = new TextAreaTicketPrinter();
this.ticketP = new TextAreaTicketPrinter();
 
JScrollPane scrollPane = new JScrollPane(ticketP);
JScrollPane scrollPane = new JScrollPane(this.ticketP);
scrollPane.setPreferredSize(new Dimension(400, 200));
scrollPane.setMinimumSize(new Dimension(400, 200));
this.add(scrollPane, c);
 
ticketList.addListSelectionListener(new ListSelectionListener() {
this.ticketList.addListSelectionListener(new ListSelectionListener() {
 
@Override
public void valueChanged(ListSelectionEvent e) {
Object selectedValue = ticketList.getSelectedValue();
Object selectedValue = ListeDesTicketsPanel.this.ticketList.getSelectedValue();
setSelectedTicket(selectedValue);
}
});
239,8 → 238,8
c.weighty = 0;
c.fill = GridBagConstraints.NONE;
final Font font = new Font(ARIAL_FONT, Font.PLAIN, 46);
l = new JList(new String[] { "Imprimer", "Annuler" });
l.setCellRenderer(new ListCellRenderer() {
this.l = new JList(new String[] { "Imprimer", "Annuler le ticket" });
this.l.setCellRenderer(new ListCellRenderer() {
 
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
259,11 → 258,11
}
 
});
l.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
l.getSelectionModel().addListSelectionListener(this);
this.l.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.l.getSelectionModel().addListSelectionListener(this);
 
l.setFixedCellHeight(160);
this.add(l, c);
this.l.setFixedCellHeight(100);
this.add(this.l, c);
 
setFont(new Font(ARIAL_FONT, Font.BOLD, 24));
 
272,7 → 271,7
 
@Override
public void actionPerformed(ActionEvent e) {
frame.showCaisse();
ListeDesTicketsPanel.this.frame.showCaisse();
 
}
});
284,30 → 283,25
if (e.getValueIsAdjusting()) {
return;
}
Object selectedValue = ticketList.getSelectedValue();
int selectedIndex = l.getSelectedIndex();
Object selectedValue = this.ticketList.getSelectedValue();
int selectedIndex = this.l.getSelectedIndex();
if (selectedIndex == 0 && selectedValue != null) {
this.frame.getPOSConf().printOnceOnFirstPrinter(((Printable) selectedValue));
} else if (selectedIndex == 1 && selectedValue != null) {
// Annulation du ticket
} else if (selectedIndex == 1 && selectedValue != null && selectedValue instanceof Ticket) {
Ticket t = (Ticket) selectedValue;
for (Pair<Article, Integer> a : t.getArticles()) {
frame.getControler().addArticle(a.getFirst());
frame.getControler().setArticleCount(a.getFirst(), -a.getSecond());
frame.getControler().setArticleHT(a.getFirst(), a.getFirst().getPriceWithoutTax());
this.frame.getControler().cancel(t);
 
}
frame.showCaisse();
this.l.clearSelection();
}
l.clearSelection();
}
 
public void setSelectedTicket(Object selectedValue) {
ticketP.clear();
this.ticketP.clear();
if (selectedValue != null) {
this.frame.getPOSConf().print(((Printable) selectedValue), new TicketPrinterConfiguration() {
@Override
public TicketPrinter createTicketPrinter() {
return ticketP;
return ListeDesTicketsPanel.this.ticketP;
}
 
@Override
321,11 → 315,11
}
});
try {
ticketP.printBuffer();
this.ticketP.printBuffer();
} catch (Exception e1) {
e1.printStackTrace();
}
}
ticketList.setSelectedValue(selectedValue, true);
this.ticketList.setSelectedValue(selectedValue, true);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/ArticleSelector.java
36,7 → 36,7
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
 
public class ArticleSelector extends JPanel implements ListSelectionListener, CaisseListener {
public class ArticleSelector extends JPanel implements CaisseListener {
private ArticleModel model;
private ScrollableList list;
private StatusBar comp;
52,28 → 52,34
c.gridy = 0;
c.weightx = 1;
c.fill = GridBagConstraints.BOTH;
comp = new StatusBar();
comp.setLayout(new FlowLayout(FlowLayout.LEFT));
comp.setTitle("Articles");
this.comp = new StatusBar();
this.comp.setLayout(new FlowLayout(FlowLayout.LEFT));
this.comp.setTitle("Articles");
final POSButton bSwitch = new POSButton("-");
bSwitch.setForeground(Color.WHITE);
bSwitch.setBackground(CaissePanel.DARK_BLUE);
comp.add(bSwitch);
this.add(comp, c);
this.comp.add(bSwitch);
this.add(this.comp, c);
 
c.weighty = 1;
c.gridy++;
model = new ArticleModel();
model.setCategorie(null);
this.model = new ArticleModel();
this.model.setCategorie(null);
 
final Font f = new Font("Arial", Font.PLAIN, 21);
list = new ScrollableList(model) {
final Font f;
if (controller.getPOSConf().getScreenWidth() < 1280) {
f = new Font("Arial", Font.PLAIN, 18);
} else {
f = new Font("Arial", Font.PLAIN, 21);
}
 
this.list = new ScrollableList(this.model) {
int maxStringWidth = 0;
 
@Override
public void paint(Graphics g) {
 
if (maxStringWidth == 0) {
if (this.maxStringWidth == 0) {
g.setFont(f);
int w = this.getWidth();
int priceWidth = (int) g.getFontMetrics(f).getStringBounds(getPrice(BigDecimal.valueOf(999)), g).getWidth();
85,8 → 91,7
str += "a";
} while (strW < maxW);
 
maxStringWidth = Math.max(1, str.length() - 1);
System.out.println(w + " " + priceWidth + " " + maxStringWidth);
this.maxStringWidth = Math.max(1, str.length() - 1);
 
}
super.paint(g);
97,24 → 102,39
@Override
public void paintCell(Graphics g, Object object, int index, boolean isSelected, int posY) {
Article article = (Article) object;
paintArticle(f, g, article, isSelected, posY, this.getWidth(), this.getCellHeight(), maxStringWidth, getLeftMargin());
paintArticle(f, g, article, isSelected, posY, this.getWidth(), this.getCellHeight(), this.maxStringWidth, getLeftMargin());
 
}
};
 
list.setFixedCellHeight(64);
list.setOpaque(true);
this.add(list, c);
list.addListSelectionListener(this);
this.list.setFixedCellHeight(64);
this.list.setOpaque(true);
this.add(this.list, c);
this.list.addListSelectionListener(new ListSelectionListener() {
 
list.addMouseListener(new MouseAdapter() {
@Override
public void valueChanged(ListSelectionEvent e) {
Object sel = ArticleSelector.this.list.getSelectedValue();
if (sel != null && !e.getValueIsAdjusting()) {
Article article = (Article) sel;
controller.setArticleSelected(article);
}
 
}
});
 
this.list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
 
Object sel = ArticleSelector.this.list.getSelectedValue();
if (sel != null) {
int nb = e.getClickCount();
if (nb > 1) {
Object sel = list.getSelectedValue();
if (sel != null) {
if (nb == 1) {
Article article = (Article) sel;
controller.addArticle(article);
} else if (nb > 1) {
Article article = (Article) sel;
controller.incrementArticle(article);
controller.setArticleSelected(article);
}
130,24 → 150,14
 
}
});
comp.addMouseListener(new MouseAdapter() {
this.comp.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
list.scrollToOffset(0);
ArticleSelector.this.list.scrollToOffset(0);
}
});
}
 
@Override
public void valueChanged(ListSelectionEvent e) {
Object sel = list.getSelectedValue();
if (sel != null && !e.getValueIsAdjusting()) {
Article article = (Article) sel;
controller.setArticleSelected(article);
controller.addArticle(article);
}
}
 
public ArticleModel getModel() {
return this.model;
}
155,22 → 165,22
@Override
public void caisseStateChanged() {
 
final Article articleSelected = controller.getArticleSelected();
final Article articleSelected = this.controller.getArticleSelected();
if (articleSelected == null) {
list.clearSelection();
this.list.clearSelection();
return;
}
 
Object selectedValue = null;
try {
selectedValue = list.getSelectedValue();
selectedValue = this.list.getSelectedValue();
} catch (Exception e) {
e.printStackTrace();
}
if (!articleSelected.equals(selectedValue)) {
Categorie c = articleSelected.getCategorie();
model.setCategorie(c);
list.setSelectedValue(articleSelected, true);
this.model.setCategorie(c);
this.list.setSelectedValue(articleSelected, true);
}
 
}
226,10 → 236,35
g.drawString(label, leftMargin, posY + 26);
g.drawString(label2, leftMargin, posY + 52);
}
 
if (isSelected) {
g.setColor(new Color(232, 242, 254));
} else {
g.setColor(Color.WHITE);
}
g.fillRect(cellWidth - wEuro - 12, posY + 1, wEuro + 12, cellHeight - 2);
 
// Price
if (isSelected) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
if (article.getSalesUnit() != null) {
String unit = "/" + article.getSalesUnit();
int wUnit = (int) g.getFontMetrics().getStringBounds(unit, g).getWidth();
g.drawString(euro, cellWidth - 5 - wEuro, posY + 28);
g.drawString(unit, cellWidth - 5 - wUnit, posY + 50);
} else {
g.drawString(euro, cellWidth - 5 - wEuro, posY + 39);
}
 
}
 
public int getLeftMargin() {
if (this.controller.getPOSConf().getScreenWidth() < 1280) {
return 3;
}
return 10;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaissePanel.java
20,7 → 20,10
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
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.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.SQLTable.VirtualFields;
61,7 → 64,7
private ArticleSelectorPanel articleSelectorPanel;
private ArticleSearchPanel articleSearchPanel;
 
private JPanel articleSelector;
private JPanel selector;
 
public CaissePanel(final CaisseFrame caisseFrame) throws Exception {
final SQLElementDirectory dir = caisseFrame.getConf().getDirectory();
70,40 → 73,36
this.setBackground(Color.WHITE);
this.setOpaque(isOpaque());
GridBagConstraints c = new GridBagConstraints();
 
// Column 1
c.gridx = 0;
c.gridy = 0;
c.weightx = 0;
c.weighty = 0;
 
this.controler = new CaisseControler(caisseFrame);
 
c.fill = GridBagConstraints.HORIZONTAL;
this.st = createStatusBar(caisseFrame);
 
this.add(this.st, c);
 
TicketPanel t = new TicketPanel(this.controler);
// fillExampleArticle();
loadArticles(dir);
c.gridx = 0;
c.gridy++;
c.weightx = 0;
c.weighty = 1;
c.gridwidth = 1;
c.anchor = GridBagConstraints.SOUTHWEST;
c.fill = GridBagConstraints.NONE;
this.add(t, c);
 
// Column 2
c.fill = GridBagConstraints.BOTH;
c.gridx++;
c.gridy = 0;
c.weightx = 1;
c.gridy--;
c.gridheight = 2;
articleSelectorPanel = new ArticleSelectorPanel(this.controler);
articleSearchPanel = new ArticleSearchPanel(this.controler);
articleSelector = articleSelectorPanel;
this.add(articleSelector, c);
 
this.articleSelectorPanel = new ArticleSelectorPanel(this.controler);
this.articleSearchPanel = new ArticleSearchPanel(this.controler);
this.selector = this.articleSelectorPanel;
this.add(this.selector, c);
// Column 3
c.gridx++;
c.weightx = 0;
this.add(new PaiementPanel(this.controler), c);
114,7 → 113,11
final StatusBar s = new StatusBar();
s.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
c.insets = new Insets(0, 2, 0, 2);
} else {
c.insets = new Insets(0, 10, 0, 10);
}
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
199,11 → 202,17
}
 
private void loadArticles(final SQLElementDirectory dir) {
final SQLSelect selUniteVente = new SQLSelect();
selUniteVente.addSelectStar(dir.getElement("UNITE_VENTE").getTable());
final Map<Integer, String> mapUniteVenteName = new HashMap<>();
for (SQLRow row : SQLRowListRSH.execute(selUniteVente)) {
mapUniteVenteName.put(row.getID(), row.getString("CODE"));
}
 
final Set<Integer> favoriteProductsIds = controler.loadFavoriteProductsIds();
final Set<Integer> favoriteProductsIds = this.controler.loadFavoriteProductsIds();
final List<Article> favoriteProducts = new ArrayList<>();
 
final Map<Integer, Categorie> categoriesMap = new HashMap<Integer, Categorie>();
final Map<Integer, Categorie> categoriesMap = new HashMap<>();
 
SQLElement eltFam = dir.getElement("FAMILLE_ARTICLE");
SQLElement eltArticle = dir.getElement("ARTICLE");
229,7 → 238,7
final SQLSelect selArticle = new SQLSelect();
final SQLTable tableArticle = eltArticle.getTable();
selArticle.addAllSelect(tableArticle.getFields(VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE)));
selArticle.addAllSelect(tableArticle, Arrays.asList("ID_FAMILLE_ARTICLE", "NOM", "CODE", "CODE_BARRE", "ID_TAXE", "PV_HT", "PV_TTC", "ADDITIONAL_TICKET_COPY"));
selArticle.addAllSelect(tableArticle, Arrays.asList("ID_FAMILLE_ARTICLE", "NOM", "CODE", "CODE_BARRE", "ID_TAXE", "PV_HT", "PV_TTC", "ADDITIONAL_TICKET_COPY", "ID_UNITE_VENTE"));
selArticle.setWhere(new Where(tableArticle.getField("OBSOLETE"), "=", Boolean.FALSE).and(new Where(tableArticle.getField("MASQUE_CAISSE"), "=", Boolean.FALSE)));
 
final Categorie cUnclassified = new Categorie("Non classés", true);
252,6 → 261,9
a.setPriceWithoutTax(row.getBigDecimal("PV_HT"));
a.setPriceWithTax(row.getBigDecimal("PV_TTC"));
a.setAdditionalCopyRequested(row.getBoolean("ADDITIONAL_TICKET_COPY"));
if (row.getInt("ID_UNITE_VENTE") != 2) {
a.setSalesUnit(mapUniteVenteName.get(row.getInt("ID_UNITE_VENTE")));
}
final Integer idProduct = a.getId();
if (favoriteProductsIds.contains(idProduct)) {
favoriteProducts.add(a);
260,8 → 272,39
}
}
Categorie.setFavoriteProducts(favoriteProducts);
initCacheArticleMap(dir);
}
 
private static Map<Integer, SQLRowAccessor> cacheArticle = new HashMap<>();
 
public static SQLRowAccessor getArticleRowValuesFromCache(int id) {
return cacheArticle.get(id);
}
 
private void initCacheArticleMap(final SQLElementDirectory dir) {
final SQLTable tableArt = dir.getElement("ARTICLE").getTable();
SQLRowValues rowValsArt = new SQLRowValues(tableArt);
rowValsArt.putNulls(tableArt.getFieldsName());
final SQLTable tableArtCatComptable = dir.getElement("ARTICLE_CATEGORIE_COMPTABLE").getTable();
SQLRowValues rowValsArtCatComptable = new SQLRowValues(tableArtCatComptable);
rowValsArtCatComptable.putNulls(tableArtCatComptable.getFieldsName());
rowValsArtCatComptable.put("ID_ARTICLE", rowValsArt);
final SQLRowValues rowValsCaCompt = rowValsArtCatComptable.putRowValues("ID_CATEGORIE_COMPTABLE");
rowValsCaCompt.putNulls(rowValsCaCompt.getTable().getFieldsName());
 
final SQLRowValues rowValsFam = rowValsArt.putRowValues("ID_FAMILLE_ARTICLE");
rowValsFam.putNulls(rowValsFam.getTable().getFieldsName());
final SQLRowValues rowValuesFamP = rowValsFam.putRowValues("ID_FAMILLE_ARTICLE_PERE");
rowValuesFamP.putNulls(rowValuesFamP.getTable().getFieldsName());
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsArt);
List<SQLRowValues> res = fetcher.fetch();
for (SQLRowValues sqlRowValues : res) {
cacheArticle.put(sqlRowValues.getID(), sqlRowValues);
}
 
}
 
@Override
public void paint(Graphics g) {
System.err.println("CaissePanel.paint()" + this.getWidth() + " x " + this.getHeight());
279,9 → 322,12
g.drawString("Solde : " + new DecimalFormat("#0.00").format(this.controler.getClient().getSolde()), 20, 120);
 
}
 
int xPos = 300;
if (this.controler.getPOSConf().getScreenWidth() < 1280) {
xPos = 270;
}
// Prix
int x = 300;
int x = xPos;
int y = 110;
String euros;
String cents;
303,7 → 349,7
g.drawString(cents, x + (int) r.getWidth(), y);
// Paiement
y += 40;
x = 300;
x = xPos;
final int paye = this.controler.getPaidTotal();
euros = CaisseControler.getEuros(paye) + ".";
cents = CaisseControler.getCents(paye);
327,7 → 373,7
final boolean minimalHeight = this.getHeight() < 750;
if (!minimalHeight) {
y += 40;
x = 300;
x = xPos;
} else {
x = 140;
}
372,15 → 418,16
 
public void switchListMode() {
 
GridBagConstraints c = ((GridBagLayout) this.getLayout()).getConstraints(articleSelector);
this.remove(articleSelector);
GridBagConstraints c = ((GridBagLayout) this.getLayout()).getConstraints(this.selector);
this.remove(this.selector);
 
if (articleSelector == this.articleSearchPanel) {
articleSelector = this.articleSelectorPanel;
if (this.selector == this.articleSearchPanel) {
this.selector = this.articleSelectorPanel;
} else {
articleSelector = this.articleSearchPanel;
this.selector = this.articleSearchPanel;
}
this.add(articleSelector, c);
System.err.println("CaissePanel.switchListMode()" + this.selector.getMinimumSize() + " " + this.selector.getPreferredSize() + " " + this.selector.getMaximumSize());
this.add(this.selector, c);
this.validate();
this.repaint();
 
387,6 → 434,36
}
 
public CaisseControler getControler() {
return controler;
return this.controler;
}
 
public void validateTicket(final CaisseFrame caisseFrame) {
final Ticket savedReceipt;
try {
savedReceipt = CaissePanel.this.controler.saveAndClearTicket(caisseFrame.getFiles(), caisseFrame.getConf().getDirectory());
} catch (DifferentDayException ex) {
JOptionPane.showMessageDialog(CaissePanel.this, "Impossible de laisser la caisse ouverte plusieurs jours. Veuillez la clôturer pour pouvoir faire de nouveaux tickets.", "Erreur",
JOptionPane.ERROR_MESSAGE);
return;
} catch (Throwable ex) {
ExceptionHandler.handle(CaissePanel.this, "Erreur de sauvegarde des informations du ticket", ex);
return;
}
if (savedReceipt != null) {
// Valider
CaissePanel.this.controler.setLCD("Impression de", "votre ticket...", 0);
try {
caisseFrame.getPOSConf().print(savedReceipt, (savedReceipt.isAdditionnalCopyRequested() ? 1 : 0));
} catch (UnsatisfiedLinkError ex) {
JOptionPane.showMessageDialog(CaissePanel.this, "Erreur de configuration de la liaison à l'imprimante");
} catch (Throwable ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(CaissePanel.this, "Erreur d'impression du ticket");
}
 
CaissePanel.this.controler.setLCDDefaultDisplay(2);
} else {
System.err.println("CaissePanel.validateTicket() ticket non sauvé");
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/TextAreaTicketPanel.java
23,7 → 23,10
import org.openconcerto.erp.core.sales.pos.model.Ticket;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.DecimalUtils;
 
33,7 → 36,9
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.swing.JButton;
import javax.swing.JPanel;
77,6 → 82,7
}
 
private Ticket createTicket(SQLRow row) {
// TODO merger ce code avec CaissepPanel.loadArticles si possible
final Ticket t;
try {
t = new Ticket(new ReceiptCode(row.getString("NUMERO")), row.getDate("DATE"), row.getString("FILE_HASH_PREVIOUS"));
84,7 → 90,8
throw new IllegalStateException("Couldn't parse " + row, e);
}
 
SQLElement eltEncaisser = Configuration.getInstance().getDirectory().getElement("ENCAISSER_MONTANT");
final SQLElementDirectory directory = Configuration.getInstance().getDirectory();
SQLElement eltEncaisser = directory.getElement("ENCAISSER_MONTANT");
List<SQLRow> l = row.getReferentRows(eltEncaisser.getTable());
for (SQLRow row2 : l) {
long montant = row2.getLong("MONTANT");
106,20 → 113,35
t.addPaiement(p);
}
 
SQLElement eltArticle = Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE_ELEMENT");
SQLElement eltArticle = directory.getElement("SAISIE_VENTE_FACTURE_ELEMENT");
 
final SQLSelect selUniteVente = new SQLSelect();
selUniteVente.addSelectStar(directory.getElement("UNITE_VENTE").getTable());
final Map<Integer, String> mapUniteVenteName = new HashMap<>();
for (SQLRow rowUniteVente : SQLRowListRSH.execute(selUniteVente)) {
mapUniteVenteName.put(rowUniteVente.getID(), rowUniteVente.getString("CODE"));
}
 
List<SQLRow> l2 = row.getReferentRows(eltArticle.getTable());
Categorie c = new Categorie("");
for (SQLRow row2 : l2) {
Article a = new Article(c, row2.getString("NOM"), row2.getInt("ID_ARTICLE"));
if (row2.getInt("ID_UNITE_VENTE") != 2) {
a.setSalesUnit(mapUniteVenteName.get(row2.getInt("ID_UNITE_VENTE")));
}
BigDecimal ht = (BigDecimal) row2.getObject("PV_HT");
a.setPriceWithoutTax(ht);
int idTaxe = row2.getInt("ID_TAXE");
float tva = TaxeCache.getCache().getTauxFromId(idTaxe);
a.setPriceWithTax(ht.multiply(new BigDecimal(1.0 + (tva / 100.0D)), DecimalUtils.HIGH_PRECISION));
a.setPriceWithTax(ht.multiply(BigDecimal.valueOf(1.0 + (tva / 100.0D)), DecimalUtils.HIGH_PRECISION));
a.setIdTaxe(idTaxe);
t.addArticle(a);
t.setArticleCount(a, row2.getInt("QTE"));
if (a.getSalesUnit() == null) {
t.setArticleCount(a, new BigDecimal(row2.getInt("QTE")));
} else {
t.setArticleCount(a, row2.getBigDecimal("QTE_UNITAIRE"));
}
}
 
return t;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/Article.java
31,6 → 31,8
private String barCode = "empty barcode";
private String code = "";
private final int id;
// unité de vente (null si à la pièce)
private String salesUnit;
private static Map<String, Article> codes = new HashMap<String, Article>();
 
public Article(Categorie s1, String string, int id) {
48,11 → 50,12
this.priceHT = a.priceHT;
this.barCode = a.barCode;
this.id = a.id;
this.salesUnit = a.salesUnit;
this.s.addArticle(this);
}
 
public boolean isAdditionalCopyRequested() {
return additionalCopyRequested;
return this.additionalCopyRequested;
}
 
public void setAdditionalCopyRequested(boolean additionalCopyRequested) {
114,7 → 117,7
 
@Override
public String toString() {
return "Article:" + this.name + " " + this.priceTTC + " cents" + "(HT:" + priceHT + ")";
return "Article:" + this.name + " " + this.priceTTC + " cents" + "(HT:" + this.priceHT + ") " + getSalesUnit();
}
 
public static Article getArticleFromBarcode(String code) {
139,12 → 142,20
}
 
public static BigDecimal computePriceWithTax(BigDecimal ht, int idTaxe) {
final BigDecimal tax = new BigDecimal(TaxeCache.getCache().getTauxFromId(idTaxe)).movePointLeft(2).add(BigDecimal.ONE);
final BigDecimal tax = BigDecimal.valueOf(TaxeCache.getCache().getTauxFromId(idTaxe)).movePointLeft(2).add(BigDecimal.ONE);
return ht.multiply(tax).setScale(2, RoundingMode.HALF_UP);
}
 
public static BigDecimal computePriceWithoutTax(BigDecimal ttc, int idTaxe) {
final BigDecimal tax = new BigDecimal(TaxeCache.getCache().getTauxFromId(idTaxe)).movePointLeft(2).add(BigDecimal.ONE);
final BigDecimal tax = BigDecimal.valueOf(TaxeCache.getCache().getTauxFromId(idTaxe)).movePointLeft(2).add(BigDecimal.ONE);
return ttc.divide(tax, DecimalUtils.HIGH_PRECISION).setScale(6, RoundingMode.HALF_UP);
}
 
public void setSalesUnit(String name) {
this.salesUnit = name;
}
 
public String getSalesUnit() {
return this.salesUnit;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/Ticket.java
24,6 → 24,7
import org.openconcerto.erp.core.sales.pos.io.Printable;
import org.openconcerto.erp.core.sales.pos.io.TicketPrinter;
import org.openconcerto.erp.core.sales.pos.model.RegisterFiles.HashMode;
import org.openconcerto.erp.core.sales.pos.ui.CaissePanel;
import org.openconcerto.erp.core.sales.pos.ui.TicketCellRenderer;
import org.openconcerto.erp.generationEcritures.GenerationEcritures;
import org.openconcerto.erp.generationEcritures.GenerationMvtVirement;
30,6 → 31,8
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLBackgroundTableCacheItem;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
36,7 → 39,6
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.Pair;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.XMLDateFormat;
 
66,14 → 68,14
private static final XMLDateFormat DATE_FMT = new XMLDateFormat();
 
// Propre a ticket
private final List<Paiement> paiements = new ArrayList<Paiement>();
private final List<Pair<Article, Integer>> items = new ArrayList<Pair<Article, Integer>>();
private final List<Paiement> paiements = new ArrayList<>();
private final List<TicketItem> items = new ArrayList<>();
private Calendar creationCal;
private Client client = Client.NONE;
private final int number;
private final String previousHash;
private boolean additionnalCopyRequested = false;
 
private String codePostal = "";
// Propre à la caisse
private final int caisseNumber;
 
94,6 → 96,15
}
}
 
public String getCodePostal() {
return this.codePostal;
}
 
public void setCodePostal(String codePostal) {
this.codePostal = codePostal;
 
}
 
public void setClient(final Client client) {
this.client = client;
}
102,15 → 113,11
return this.client;
}
 
public static Ticket parseFile(final File file) {
public static Ticket parseFile(final File file) throws IOException {
return parseFile(file, HashMode.REQUIRED);
}
 
public static Ticket parseFile(final File file, final HashMode hashMode) {
if (!file.exists()) {
return null;
}
 
public static Ticket parseFile(final File file, final HashMode hashMode) throws IOException {
try {
// XML Reading
 
131,10 → 138,12
final Ticket t = new Ticket(receiptCode, c, root.getAttributeValue("previousHash"));
t.setClient(new Client(Integer.parseInt(client), "", BigDecimal.ZERO));
 
t.setCodePostal(root.getAttributeValue("codePostal", ""));
 
// article
final List<Element> children = root.getChildren("article");
for (final Element element : children) {
final int qte = Integer.parseInt(element.getAttributeValue("qte"));
final BigDecimal qte = new BigDecimal(element.getAttributeValue("qte"));
final BigDecimal prix_unitaire_cents_ht = new BigDecimal(element.getAttributeValue("prixHT"));
final int idTaxe = Integer.parseInt(element.getAttributeValue("idTaxe"));
final BigDecimal prix_unitaire_cents = new BigDecimal(element.getAttributeValue("prix"));
142,6 → 151,7
final String name = element.getValue();
final String codebarre = element.getAttributeValue("codebarre");
final String codeArt = element.getAttributeValue("code");
final String salesUnit = element.getAttributeValue("unit");
final Categorie cat = new Categorie(categorie);
 
final String valueID = element.getAttributeValue("id");
153,7 → 163,8
art.setPriceWithoutTax(prix_unitaire_cents_ht);
art.setIdTaxe(idTaxe);
art.setBarCode(codebarre);
final Pair<Article, Integer> line = new Pair<Article, Integer>(art, qte);
art.setSalesUnit(salesUnit);
final TicketItem line = new TicketItem(art, qte);
t.items.add(line);
 
}
181,10 → 192,10
}
 
return t;
} catch (final Exception e) {
System.err.println("Error with ticket : " + file + " : " + e.getMessage());
e.printStackTrace();
return null;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException("Couldn't parse " + file, e);
}
}
 
211,6 → 222,13
return this.previousHash;
}
 
public void clear() {
this.client = Client.NONE;
this.codePostal = "";
this.paiements.clear();
 
}
 
public final ReceiptCode getReceiptCode() {
// TODO replace our fields by one ReceiptCode
return new ReceiptCode(this.getCaisseNumber(), this.getCreationCal(), this.getNumber());
252,19 → 270,24
topLevel.setAttribute("previousHash", this.getPreviousHash());
topLevel.setAttribute("creationDate", DATE_FMT.format(c.getTime()));
topLevel.setAttribute("clientID", String.valueOf(this.client.getId()));
topLevel.setAttribute("codePostal", this.codePostal);
// Articles
for (final Pair<Article, Integer> item : this.items) {
for (final TicketItem item : this.items) {
final Element e = new Element("article");
e.setAttribute("qte", String.valueOf(item.getSecond()));
e.setAttribute("qte", String.valueOf(item.getQty()));
// Prix unitaire
e.setAttribute("prix", String.valueOf(item.getFirst().getPriceWithTax()));
e.setAttribute("prixHT", String.valueOf(item.getFirst().getPriceWithoutTax()));
e.setAttribute("idTaxe", String.valueOf(item.getFirst().getIdTaxe()));
e.setAttribute("categorie", item.getFirst().getCategorie().getName());
e.setAttribute("codebarre", item.getFirst().getBarCode());
e.setAttribute("code", item.getFirst().getCode());
e.setAttribute("id", String.valueOf(item.getFirst().getId()));
e.setText(item.getFirst().getName());
final Article article = item.getArticle();
e.setAttribute("prix", String.valueOf(article.getPriceWithTax()));
e.setAttribute("prixHT", String.valueOf(article.getPriceWithoutTax()));
e.setAttribute("idTaxe", String.valueOf(article.getIdTaxe()));
e.setAttribute("categorie", article.getCategorie().getName());
e.setAttribute("codebarre", article.getBarCode());
e.setAttribute("code", article.getCode());
e.setAttribute("id", String.valueOf(article.getId()));
if (article.getSalesUnit() != null) {
e.setAttribute("unit", article.getSalesUnit());
}
e.setText(article.getName());
topLevel.addContent(e);
}
// Paiements
360,13 → 383,13
final SimpleDateFormat df = new SimpleDateFormat("EEEE d MMMM yyyy à HH:mm", Locale.FRENCH);
prt.addToBuffer(DefaultTicketPrinter.formatCenter(maxWidth, "Le " + df.format(getCreationDate())));
prt.addToBuffer("");
List<Pair<Article, Integer>> itemsToPrint = new ArrayList<>(this.items);
Collections.sort(itemsToPrint, new Comparator<Pair<Article, Integer>>() {
List<TicketItem> itemsToPrint = new ArrayList<>(this.items);
Collections.sort(itemsToPrint, new Comparator<TicketItem>() {
 
@Override
public int compare(Pair<Article, Integer> o1, Pair<Article, Integer> o2) {
final Article p1 = o1.getFirst();
final Article p2 = o2.getFirst();
public int compare(TicketItem o1, TicketItem o2) {
final Article p1 = o1.getArticle();
final Article p2 = o2.getArticle();
final Categorie c1 = p1.getCategorie();
final Categorie c2 = p2.getCategorie();
if (c1.equals(c2)) {
384,8 → 407,9
}
});
Categorie currentCategorie = null;
for (final Pair<Article, Integer> item : this.items) {
final Article article = item.getFirst();
for (final TicketItem item : this.items) {
final Article article = item.getArticle();
System.err.println("Ticket.print()" + item);
if (currentCategorie == null || !currentCategorie.getName().equals(article.getCategorie().getName())) {
// Print category name, except for unknown
currentCategorie = article.getCategorie();
393,20 → 417,29
prt.addToBuffer(currentCategorie.getName(), TicketPrinter.BOLD);
}
}
final Integer nb = item.getSecond();
final BigDecimal nb = item.getQty();
final Float tauxFromId = TaxeCache.getCache().getTauxFromId(article.getIdTaxe());
final BigDecimal tauxTVA = new BigDecimal(tauxFromId).movePointLeft(2).add(BigDecimal.ONE);
final BigDecimal tauxTVA = BigDecimal.valueOf(tauxFromId).movePointLeft(2).add(BigDecimal.ONE);
final BigDecimal unitPrice = article.getPriceWithoutTax().multiply(tauxTVA, DecimalUtils.HIGH_PRECISION);
final BigDecimal multiply = article.getPriceWithoutTax().multiply(new BigDecimal(nb), DecimalUtils.HIGH_PRECISION).multiply(tauxTVA, DecimalUtils.HIGH_PRECISION);
final BigDecimal multiply = article.getPriceWithoutTax().multiply(nb, DecimalUtils.HIGH_PRECISION).multiply(tauxTVA, DecimalUtils.HIGH_PRECISION);
 
final String qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, String.valueOf(nb));
final String priceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, TicketCellRenderer.centsToString(multiply.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()));
String qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, String.valueOf(nb));
final String priceUnformated = TicketCellRenderer.centsToString(multiply.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue());
final String priceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, priceUnformated);
String unitPriceString = "";
if (nb != 1) {
if (article.getSalesUnit() == null) {
if (nb.intValue() != 1) {
unitPriceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, TicketCellRenderer.centsToString(unitPrice.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()));
}
 
if (article.getCode() != null && !article.getCode().isEmpty()) {
} else {
unitPriceString = DefaultTicketPrinter.formatRight(MAX_PRICE_WIDTH, "");
if (nb.signum() >= 0) {
qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, "1");
} else {
qtyString = DefaultTicketPrinter.formatRight(MAX_QTE_WIDTH, "-1");
}
}
if (article.getCode() != null && !article.getCode().isEmpty() && !article.getCode().equalsIgnoreCase(article.getName())) {
// 2 lines
final String codeString = DefaultTicketPrinter.formatLeft(maxWidth - 2 - MAX_PRICE_WIDTH - MAX_QTE_WIDTH - 1 - unitPriceString.length(), article.getCode());
prt.addToBuffer(qtyString + " " + codeString + " " + unitPriceString + " " + priceString);
417,8 → 450,11
final String nameString = DefaultTicketPrinter.formatLeft(maxWidth - 2 - MAX_PRICE_WIDTH - MAX_QTE_WIDTH - 1 - unitPriceString.length(), article.getName());
prt.addToBuffer(qtyString + " " + nameString + " " + unitPriceString + " " + priceString);
}
 
if (article.getSalesUnit() != null) {
prt.addToBuffer(
" (" + nb.abs() + " " + article.getSalesUnit() + " x " + TicketCellRenderer.centsToString(unitPrice.movePointRight(2).setScale(0, RoundingMode.HALF_UP).intValue()) + ")");
}
}
 
final StringBuilder spacer = new StringBuilder();
for (int i = 0; i <= MAX_QTE_WIDTH; i++) {
460,16 → 496,20
type = "Remboursement ";
}
if (paiement.getType() == Paiement.CB) {
type = "CB";
type += "CB";
} else if (paiement.getType() == Paiement.CHEQUE) {
type = "par chèque";
type += "par chèque";
} else if (paiement.getType() == Paiement.ESPECES) {
type = "en espèces";
type += "en espèces";
} else if (paiement.getType() == Paiement.SOLDE) {
type = "depuis solde";
type += "depuis solde";
}
if (montantInCents > 0) {
type += " de " + TicketCellRenderer.centsToString(montantInCents);
if (montantInCents > 100) {
} else {
type += " de " + TicketCellRenderer.centsToString(-montantInCents);
}
if (Math.abs(montantInCents) > 100) {
type += " euros";
} else {
type += " euro";
481,7 → 521,7
if (getTotalInCents() < getPaidTotal()) {
final int montantInCents = getPaidTotal() - getTotalInCents();
String type = "Rendu : " + TicketCellRenderer.centsToString(montantInCents);
if (montantInCents > 100) {
if (Math.abs(montantInCents) > 100) {
type += " euros";
} else {
type += " euro";
525,23 → 565,25
}
 
public boolean isAdditionnalCopyRequested() {
return additionnalCopyRequested;
return this.additionnalCopyRequested;
}
 
public void addArticle(final Article a) {
System.err.println("Ticket.addArticle()" + a);
boolean alreadyExist = false;
if (a.isAdditionalCopyRequested()) {
this.additionnalCopyRequested = true;
}
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(a)) {
if (a.getSalesUnit() == null) {
for (final TicketItem line : this.items) {
if (line.getArticle().equals(a)) {
alreadyExist = true;
break;
}
}
 
}
if (!alreadyExist) {
final Pair<Article, Integer> line = new Pair<Article, Integer>(new Article(a), 1);
final TicketItem line = new TicketItem(new Article(a), BigDecimal.ONE);
this.items.add(line);
}
 
548,21 → 590,29
}
 
public void incrementArticle(final Article a) {
System.err.println("Ticket.incrementArticle()" + a.getName());
 
boolean alreadyExist = false;
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(a)) {
if (a.getSalesUnit() == null) {
for (final TicketItem line : this.items) {
if (line.getArticle().equals(a)) {
alreadyExist = true;
line.setSecond(line.getSecond() + 1);
line.setQty(line.getQty().add(BigDecimal.ONE));
break;
}
}
}
if (!alreadyExist) {
final Pair<Article, Integer> line = new Pair<Article, Integer>(a, 1);
final TicketItem line = new TicketItem(a, BigDecimal.ONE);
this.items.add(line);
}
 
}
 
public void addItem(TicketItem item) {
this.items.add(item);
}
 
public List<Paiement> getPaiements() {
return this.paiements;
}
581,14 → 631,19
calc.setServiceActive(bServiceActive != null && bServiceActive);
final int size = this.items.size();
for (int i = 0; i < size; i++) {
final Pair<Article, Integer> line = this.items.get(i);
final int count = line.getSecond();
final Article art = line.getFirst();
final TicketItem line = this.items.get(i);
final BigDecimal count = line.getQty();
final Article art = line.getArticle();
final SQLRowValues rowVals = new SQLRowValues(tableElt);
rowVals.put("T_PV_HT", art.getPriceWithoutTax().multiply(new BigDecimal(count)));
rowVals.put("QTE", count);
rowVals.put("T_PV_HT", art.getPriceWithoutTax().multiply(count));
if (art.getSalesUnit() != null) {
rowVals.put("QTE_UNITAIRE", count);
rowVals.put("QTE", BigDecimal.ONE);
} else {
rowVals.put("QTE", count.intValue());
}
rowVals.put("ID_TAXE", art.getIdTaxe());
calc.addLine(rowVals, tableArticle.getRow(art.getId()), i, false);
calc.addLine(rowVals, CaissePanel.getArticleRowValuesFromCache(art.getId()), i, false);
 
}
calc.checkResult();
595,14 → 650,14
return calc;
}
 
public List<Pair<Article, Integer>> getArticles() {
public List<TicketItem> getItems() {
return this.items;
}
 
public void clearArticle(final Article article) {
Pair<Article, Integer> toRemove = null;
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(article)) {
TicketItem toRemove = null;
for (final TicketItem line : this.items) {
if (line.getArticle().equals(article)) {
toRemove = line;
break;
}
612,32 → 667,46
}
}
 
public void setArticleCount(final Article article, final int count) {
public void removeTicketItem(TicketItem item) {
TicketItem toRemove = null;
for (final TicketItem line : this.items) {
if (line.equals(item)) {
toRemove = line;
break;
}
}
if (toRemove != null) {
this.items.remove(toRemove);
}
 
}
 
public void setArticleCount(final Article article, final BigDecimal count) {
// TODO Allow only if annulation?
// if (count <= 0) {
// this.clearArticle(article);
// return;
// }
Pair<Article, Integer> toModify = null;
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(article)) {
TicketItem toModify = null;
for (final TicketItem line : this.items) {
if (line.getArticle().equals(article)) {
toModify = line;
break;
}
}
if (toModify != null) {
toModify.setSecond(count);
toModify.setQty(count);
}
 
}
 
public int getItemCount(final Article article) {
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(article)) {
return line.getSecond();
public BigDecimal getItemCount(final Article article) {
for (final TicketItem line : this.items) {
if (line.getArticle().equals(article)) {
return line.getQty();
}
}
return 0;
return BigDecimal.ZERO;
}
 
public int getPaidTotal() {
649,14 → 718,14
}
 
public void removeArticle(final Article a) {
Pair<Article, Integer> lineToDelete = null;
for (final Pair<Article, Integer> line : this.items) {
if (line.getFirst().equals(a)) {
final int count = line.getSecond() + 1;
if (count <= 0) {
TicketItem lineToDelete = null;
for (final TicketItem line : this.items) {
if (line.getArticle().equals(a)) {
final BigDecimal count = line.getQty().add(BigDecimal.ONE);
if (count.signum() <= 0) {
lineToDelete = line;
}
line.setSecond(count);
line.setQty(count);
break;
}
}
751,4 → 820,5
 
getReceiptCode().markDeleted();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/ReceiptCode.java
229,10 → 229,6
return this.dayIndex;
}
 
public final String getCodePrefix() {
return this.code.substring(0, this.code.length() - INDEX_FORMAT.getMinimumIntegerDigits());
}
 
public final String getCode() {
return this.code;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/RegisterLog.java
163,8 → 163,9
*
* @return the list of current receipts in this.
* @throws ParseException if an entry couldn't be parsed.
* @throws IOException if the receipts couldn't be parsed.
*/
public final List<Ticket> parseReceipts() throws ParseException {
public final List<Ticket> parseReceipts() throws ParseException, IOException {
final List<Ticket> receipts = new ArrayList<>();
final Path toUse = this.getLogFile().getParent();
final List<ReceiptEntry> receiptEvents = this.getReceiptEvents();
172,7 → 173,13
int index = 1;
for (final ReceiptEntry receiptEntry : receiptEvents) {
final Path receiptFile = toUse.resolve(receiptEntry.getCode().getFileName());
final Ticket receipt = Ticket.parseFile(receiptFile.toFile(), HashMode.equalTo(receiptEntry.getFileHash()));
final Ticket receipt;
try {
receipt = Ticket.parseFile(receiptFile.toFile(), HashMode.equalTo(receiptEntry.getFileHash()));
} catch (Exception e) {
throw new IOException("Couldn't parse file of " + receiptEntry + " : " + receiptFile, e);
}
assert receipt != null;
if (!receipt.getCode().equals(receiptEntry.getCodeString()))
throw new IllegalStateException("Code mismatch");
if (!CompareUtils.equals(lastHash, receipt.getPreviousHash()))
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/RegisterDB.java
42,6 → 42,7
import org.openconcerto.utils.TimeUtils;
import org.openconcerto.utils.cc.ITransformer;
 
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.text.ParseException;
218,7 → 219,7
 
// TODO monthly and yearly closures
 
public final DBState close(final POSConfiguration posConf, final RegisterLog log) throws SQLException, ParseException {
public final DBState close(final POSConfiguration posConf, final RegisterLog log) throws SQLException, ParseException, IOException {
final List<ReceiptEntry> receiptEvents = log.getReceiptEvents();
final RegisterEntry closureEntry = log.getLastRegisterEvent();
if (closureEntry.getType() != EventType.REGISTER_CLOSURE)
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/TicketItem.java
New file
0,0 → 1,48
/*
* 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.pos.model;
 
import java.math.BigDecimal;
 
public class TicketItem {
private Article article;
private BigDecimal qty;
 
public TicketItem(Article a, BigDecimal qty) {
this.article = a;
this.qty = qty;
}
 
public Article getArticle() {
return this.article;
}
 
public void setArticle(Article newArticle) {
this.article = newArticle;
}
 
public BigDecimal getQty() {
return this.qty;
}
 
public void setQty(BigDecimal qty) {
this.qty = qty;
}
 
@Override
public String toString() {
return this.article + " : " + this.qty;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/model/RegisterFiles.java
78,6 → 78,10
public static final String STRUCT_VERSION_2013 = "v20131206";
public static final String STRUCT_VERSION = "v20171220";
 
private static final String PREVIOUS_SUBDIR = "previous";
private static final String CURRENT_SUBDIR = "current";
private static final String STAGING_SUBDIR = "staging";
 
private static final String LOG_FILENAME = "log.xml";
static final String HASH_SUFFIX = ".hash";
private static final String LOG_HASH_FILENAME = LOG_FILENAME + HASH_SUFFIX;
333,7 → 337,7
}
 
private final Path getDayDirToUse(final Path dayDir) throws IOException {
for (final Path subdir : new Path[] { dayDir.resolve("current"), dayDir.resolve("previous") }) {
for (final Path subdir : new Path[] { dayDir.resolve(CURRENT_SUBDIR), dayDir.resolve(PREVIOUS_SUBDIR) }) {
if (Files.exists(subdir)) {
final ValidState validity = getDayDirValidity(subdir);
if (validity.isValid())
413,9 → 417,9
if (dayDirToUse != null)
throw new IllegalStateException(cal.getTime() + " already open");
 
final Path stagingDir = dayDir.resolve("staging");
final Path currentDir = stagingDir.resolveSibling("current");
final Path prevDir = stagingDir.resolveSibling("previous");
final Path stagingDir = dayDir.resolve(STAGING_SUBDIR);
final Path currentDir = stagingDir.resolveSibling(CURRENT_SUBDIR);
final Path prevDir = stagingDir.resolveSibling(PREVIOUS_SUBDIR);
FileUtils.rm_R(stagingDir);
FileUtils.rm_R(currentDir);
FileUtils.rm_R(prevDir);
425,7 → 429,20
rootElem.addContent(new RegisterLogEntry.RegisterEntry(EventType.REGISTER_OPENING, cal.getTime(), userID, input.getPosID(), lastLocalHash, prevDate).toXML());
save(new Document(rootElem), stagingDir.resolve(LOG_FILENAME));
 
for (int i = 0; i < 5; i++) {
try {
Files.move(stagingDir, currentDir, StandardCopyOption.ATOMIC_MOVE);
break;
} catch (Exception e) {
e.printStackTrace();
try {
// Retry 5 times, because can fail under Windows
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
 
POSConfiguration.getLogger().log(Level.INFO, "Finished opening of FS state for register {0}", registerDB);
 
454,9 → 471,9
 
// e.g. 2017/12/21/current/
final Path toUse = lastLog.getLogFile().getParent();
final Path stagingDir = toUse.resolveSibling("staging");
final Path currentDir = stagingDir.resolveSibling("current");
final Path prevDir = stagingDir.resolveSibling("previous");
final Path stagingDir = toUse.resolveSibling(STAGING_SUBDIR);
final Path currentDir = stagingDir.resolveSibling(CURRENT_SUBDIR);
final Path prevDir = stagingDir.resolveSibling(PREVIOUS_SUBDIR);
 
FileUtils.rm_R(stagingDir);
FileUtils.copyDirectory(toUse, stagingDir, input.useHardLinks, StandardCopyOption.COPY_ATTRIBUTES);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/element/SocieteSQLConfElement.java
14,7 → 14,6
package org.openconcerto.erp.core.common.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLField;
26,8 → 25,6
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.ui.light.GroupToLightUIConvertor;
import org.openconcerto.sql.view.EditPanel.EditMode;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelSource;
339,16 → 336,6
}
}
 
public GroupToLightUIConvertor getGroupToLightUIConvertor(final PropsConfiguration configuration, final EditMode editMode, final SQLRowValues sqlRow, final String sessionSecurityToken) {
final GroupToLightUIConvertor convertor = new GroupToLightUIConvertor(configuration);
if (editMode.equals(EditMode.CREATION)) {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForCreation(configuration, sessionSecurityToken));
} else {
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForModification(configuration, sqlRow, sessionSecurityToken));
}
return convertor;
}
 
public List<SQLRowValues> getRowValues(final String fieldName, final long id) {
final SQLTableModelSourceOnline tableSource = this.getTableSource(true);
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/IColorChooser.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/NumericTextField.java
53,7 → 53,7
this(15);
}
 
private NumericTextField(int columns) {
public NumericTextField(int columns) {
super(columns);
 
this.supp = new PropertyChangeSupport(this);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/DeviseTableCellRenderer.java
28,6 → 28,7
private final DecimalFormat decimalFormat;
private final DecimalFormat decimalFormat2;
private BigDecimal oneCents = new BigDecimal(0.01f);
private boolean hideZeroValue = false;
 
public DeviseTableCellRenderer() {
this(new DecimalFormat("##,##0.00#"), new DecimalFormat("##,##0.00#######"));
42,6 → 43,10
decimalFormat2.setDecimalFormatSymbols(symbol);
}
 
public void setHideZeroValue(boolean hideZeroValue) {
this.hideZeroValue = hideZeroValue;
}
 
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
TableCellRendererUtils.setColors(this, table, isSelected);
49,11 → 54,17
if (table.getColumnClass(column) != BigDecimal.class) {
throw new IllegalStateException("Value is not a BigDecimal :" + table.getColumnClass(column));
}
 
if (value != null) {
if (((BigDecimal) value).compareTo(oneCents) < 0)
BigDecimal amount = (BigDecimal) value;
if (this.hideZeroValue && amount.signum() == 0) {
this.setText("");
} else {
if (amount.compareTo(oneCents) < 0)
this.setText(decimalFormat2.format(value));
else
this.setText(decimalFormat.format(value));
}
} else {
this.setText("");
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/PreviewFrame.java
21,6 → 21,8
 
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
35,6 → 37,8
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaSizeName;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
48,16 → 52,31
 
private PreviewFrame(OpenDocument doc, String title) {
super(title);
this.setContentPane(new ODSViewerPanel(doc, createDocumentPrinter()));
init();
final ODSViewerPanel viewerPanel = new ODSViewerPanel(doc, createDocumentPrinter());
this.setContentPane(viewerPanel);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
 
public PreviewFrame(String title, String url, String odspXml) {
this.setContentPane(new ODSViewerPanel(url, odspXml, createDocumentPrinter(), true));
final ODSViewerPanel contentPane = new ODSViewerPanel(url, odspXml, createDocumentPrinter(), true);
 
this.setContentPane(contentPane);
this.setTitle(title);
init();
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
 
public void addTool(String n, Runnable r) {
JButton b = new JButton(n);
((ODSViewerPanel) this.getContentPane()).addTool(b);
b.addActionListener(new ActionListener() {
 
@Ov