OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 155 → Rev 156

/trunk/OpenConcerto/src/META-INF/services/java.nio.file.spi.FileTypeDetector
New file
0,0 → 1,0
ilm.utils.mime.FreeDesktopMimeDetector
/trunk/OpenConcerto/src/org/openconcerto/map/model/Ville.java
15,7 → 15,6
 
import org.openconcerto.map.ui.MapViewerPanel;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.StringUtils;
 
import java.awt.Color;
import java.awt.Polygon;
40,19 → 39,17
 
public class Ville {
// TODO: switch from Lambert to Mercator (see jmapprojlib SF project)
private static Map<String, Ville> map = new HashMap<String, Ville>();
private static Map<String, Ville> map = new HashMap<>();
private static DatabaseAccessor accessor;
private final static List<Ville> villes = new ArrayList<Ville>(39000);
private final static List<String> villesNames = new ArrayList<String>(39000);
private final static List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
private static final List<Ville> villes = new ArrayList<>(39000);
private static final List<String> villesNames = new ArrayList<>(39000);
private static final List<PropertyChangeListener> listeners = new ArrayList<>();
private static Thread init = null;
private static boolean loaded = false;
private int nbMatch = 0;
 
public synchronized static void init(final DatabaseAccessor d, final boolean loadFromFile) {
 
public static synchronized void init(final DatabaseAccessor d, final boolean loadFromFile) {
await();
 
accessor = d;
init = new Thread(new Runnable() {
@Override
132,20 → 129,6
bufReader.close();
}
 
private static final void parseLine(final String line) {
 
final List<String> strs = StringUtils.fastSplit(line, ';');
final Ville v = new Ville(strs.get(3), parsePositiveLong(strs.get(4)), parsePositiveLong(strs.get(8)), parsePositiveLong(strs.get(9)), strs.get(2));
if (strs.size() > 10) {
v.setMinimumZoom(parsePositiveLong(strs.get(10)));
}
if (v.xLambert > 0) {
addVilleSilently(v);
// System.out.println(v);
}
 
}
 
private static synchronized void addVilleSilently(final Ville v) {
villes.add(v);
final String villeEtCode = v.getVilleEtCode();
217,7 → 200,7
 
public static synchronized List<Ville> getVillesContaining(String string) {
string = string.trim().toLowerCase();
List<Ville> list = new ArrayList<Ville>();
List<Ville> list = new ArrayList<>();
final List<Ville> l = getVilles();
final int size = l.size();
for (int i = 0; i < size; i++) {
235,7 → 218,7
}
 
List<Ville> l = getVillesFromCode(codepostal);
if (l.size() == 0) {
if (l.isEmpty()) {
return null;
}
if (l.size() == 1) {
255,8 → 238,7
}
 
private static List<Ville> getVillesFromCode(String cp) {
 
List<Ville> list = new ArrayList<Ville>();
final List<Ville> list = new ArrayList<>();
final List<Ville> l = getVilles();
final int size = l.size();
for (int i = 0; i < size; i++) {
275,13 → 257,13
* @return the cities, or <code>null</code> si l'integralité des villes ou si la selection
* comporte moins de 3 points.
*/
public synchronized static List<Ville> getVilleIn(final MapPointSelection sel) {
ArrayList<Ville> r = null;
public static synchronized List<Ville> getVilleIn(final MapPointSelection sel) {
if (sel == null) {
return null;
}
ArrayList<Ville> r = null;
if (sel.size() > 2) {
r = new ArrayList<Ville>();
r = new ArrayList<>();
final Polygon p = new Polygon();
 
for (int i = 0; i < sel.size(); i++) {
315,7 → 297,6
if (!p.contains(x, y))
continue;
r.add(v);
// System.out.println("match:" + v);
}
}
return r;
323,48 → 304,40
 
public static long parsePositiveLong(String str) {
str = str.trim();
 
long value = 0;
final int stop = str.length();
 
for (int i = 0; i < stop; i++) {
final char c = str.charAt(i);
 
if (c == '.') {
break;
}
 
value *= 10;
value += (c - '0');
 
}
 
// System.out.println("str" + str + "->" + value);
return value;
}
 
public static synchronized long getMinXLambert() {
final List<Ville> l = getVilles();
if (l.size() > 0) {
if (l.isEmpty()) {
return 0;
}
long min = l.get(0).xLambert;
for (int i = 0; i < l.size(); i++) {
final Ville v = l.get(i);
 
if (v.xLambert < min) {
min = v.xLambert;
}
 
}
return min;
} else {
return 0;
}
 
}
 
static synchronized long getMaxXLambert() {
final List<Ville> l = getVilles();
if (l.size() > 0) {
if (l.isEmpty()) {
return 0;
}
long max = l.get(0).xLambert;
for (int i = 0; i < l.size(); i++) {
final Ville v = l.get(i);
373,13 → 346,13
}
}
return max;
} else {
return 0;
}
}
 
public static synchronized long getMinYLambert() {
final List<Ville> l = getVilles();
if (l.isEmpty()) {
return 0;
}
long min = l.get(0).yLambert;
for (int i = 0; i < l.size(); i++) {
final Ville v = l.get(i);
392,6 → 365,9
 
static synchronized long getMaxYLambert() {
final List<Ville> l = getVilles();
if (l.isEmpty()) {
return 0;
}
long max = l.get(0).yLambert;
for (int i = 0; i < l.size(); i++) {
final Ville v = l.get(i);
418,9 → 394,6
 
long population;
 
//
private long minimumZoom;
 
private Color color = null;
 
public String getCodepostal() {
468,15 → 441,6
this.color = color;
}
 
private void setMinimumZoom(final long l) {
this.minimumZoom = l;
 
}
 
public long getMinimumZoom() {
return this.minimumZoom;
}
 
public void setNbMatch(int nb) {
this.nbMatch = nb;
}
495,8 → 459,6
 
Ville.parseFile();
 
// Thread.sleep(10*1000);
 
final long t2 = System.nanoTime();
System.out.println("Parsing: " + (t2 - t1) / 1000000 + " ms");
System.out.println("MinXLambert:" + getMinXLambert() + ",MinYLambert" + getMinYLambert());
/trunk/OpenConcerto/src/org/openconcerto/map/model/villes.txt
176252,4 → 176252,9
75251
664756
6857877
94100
94100
Sainte-Marie-du-Lac-Nuisement
250
834134
6837080
51290
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Table.java
427,8 → 427,13
* @see #getImmutableCellAt(int, int)
*/
public final MutableCell<D> getCellAt(int x, int y) {
return this.getMutableRow(y).getMutableCellAt(x);
final Row<D> r = this.getMutableRow(y);
try {
return r.getMutableCellAt(x);
} catch (Exception e) {
throw new IllegalArgumentException("Couldn't get mutable cell at " + getAddress(x, y), e);
}
}
 
public final MutableCell<D> getCellAt(String ref) {
return this.getCellAt(resolveHint(ref));
1391,8 → 1396,12
* @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);
return getAddress(p.x, p.y);
}
 
static final String getAddress(final int x, final int y) {
if (x < 0 || y < 0)
throw new IllegalArgumentException("negative coordinates : " + x + ":" + y);
return toStr(x) + (y + 1);
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Range.java
16,7 → 16,11
import org.openconcerto.utils.CompareUtils;
 
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/**
* A cell range.
25,6 → 29,14
*/
public final class Range {
 
// added illegal characters to unquoted form from LibreOffice UI, especially ':' to avoid
// mistakenly using it in the table name instead of as a separator
private static final String tableNamePattern = "\\$?([^\\Q. '[]*?:/\\\\E]+|'([^']|'')+')";
// added parens to capture cell addresses
// \1 is sheet name, \4 cell address, \6 second sheet name, \9 second cell address
private static final Pattern cellRangePattern = java.util.regex.Pattern.compile("^(" + tableNamePattern + ")?\\.(\\$?[A-Z]+\\$?[0-9]+)(:(" + tableNamePattern + ")?\\.(\\$?[A-Z]+\\$?[0-9]+))?");
private static final Pattern LIST_SEPARATOR_PATTERN = Pattern.compile("^\\s+");
 
/**
* Parse a range.
*
32,9 → 44,13
* @return the parsed range.
*/
static public final Range parse(String range) {
final Matcher m = SpreadSheet.cellRangePattern.matcher(range);
final Matcher m = cellRangePattern.matcher(range);
if (!m.matches())
throw new IllegalStateException(range + " is not a valid range address");
return parse(m);
}
 
static private final Range parse(final Matcher m) {
final String sheet1 = SpreadSheet.parseSheetName(m.group(1));
final String sheet2 = SpreadSheet.parseSheetName(m.group(6));
 
45,6 → 61,37
return new Range(sheet1, start, sheet2, end);
}
 
// 9.2.5 Cell Range Address List, used by "table:print-ranges" for example.
// e.g. "Feuille1.A1:Feuille1.L65 Feuille1.A67:Feuille1.L107"
static public final List<Range> parseList(String ranges) {
if (ranges.isEmpty())
return Collections.emptyList();
 
final Matcher m = cellRangePattern.matcher(ranges);
m.useAnchoringBounds(true);
if (!m.find())
throw new IllegalStateException(ranges + " is not a valid range address list");
final Range first = parse(m);
final int length = ranges.length();
if (length == m.end())
return Collections.singletonList(first);
 
final List<Range> res = new ArrayList<>();
res.add(first);
final Matcher sepMatcher = LIST_SEPARATOR_PATTERN.matcher(ranges);
sepMatcher.useAnchoringBounds(true);
while (m.end() != length) {
sepMatcher.region(m.end(), length);
if (!sepMatcher.find())
throw new IllegalStateException("Couldn't find separator at " + sepMatcher.regionStart() + " in " + ranges);
m.region(sepMatcher.end(), length);
if (!m.find())
throw new IllegalStateException("Couldn't find range address at " + m.regionStart() + " in " + ranges);
res.add(parse(m));
}
return res;
}
 
private final String sheet1, sheet2;
private final Point start, end;
 
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Row.java
141,7 → 141,7
protected final Cell<D> getValidCellAt(int col) {
final Cell<D> c = this.getCellAt(col);
if (!c.isValid())
throw new IllegalArgumentException("invalid cell " + c);
throw new IllegalArgumentException("invalid cell at column " + col + " (in " + this + ") : " + c);
return c;
}
 
208,4 → 208,11
assert this.getCellCount() == this.getSheet().getColumnCount();
}
 
@Override
public String toString() {
final int firstY = this.getY();
final int lastY = this.getLastY();
final String suffix = firstY == lastY ? "" : " through " + lastY;
return this.getClass().getSimpleName() + " with " + this.getCellCount() + " cell(s) at index " + firstY + suffix;
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/SpreadSheet.java
145,12 → 145,6
// \1 is sheet name, \4 cell address
static final Pattern cellPattern = Pattern.compile("(\\$?([^\\. ']+|'([^']|'')+'))?\\.(" + minCell + ")");
static final Pattern minCellPattern = Pattern.compile(minCell);
// added illegal characters to unquoted form from LibreOffice UI, especially ':' to avoid
// mistakenly using it in the table name instead of as a separator
private static String tableNamePattern = "\\$?([^\\Q. '[]*?:/\\\\E]+|'([^']|'')+')";
// added parens to capture cell addresses
// \1 is sheet name, \4 cell address, \6 second sheet name, \9 second cell address
static final Pattern cellRangePattern = java.util.regex.Pattern.compile("(" + tableNamePattern + ")?\\.(\\$?[A-Z]+\\$?[0-9]+)(:(" + tableNamePattern + ")?\\.(\\$?[A-Z]+\\$?[0-9]+))?");
 
// see 9.2.1 of OpenDocument-v1.2-cs01-part1
static final Pattern tableNameQuoteQuotePattern = Pattern.compile("''", Pattern.LITERAL);
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/EmailProps.java
13,6 → 13,11
package org.openconcerto.ui.preferences;
 
import org.openconcerto.utils.FileUtils;
 
import java.io.File;
import java.io.IOException;
 
public class EmailProps extends AbstractProps {
public static final int DEFAULT = 0;
public static final int THUNDERBIRD = 1;
19,6 → 24,8
public static final int OUTLOOK = 2;
protected static EmailProps instance;
private String propsFileName = null;
private static String DEFAULT_FILE = "./Configuration/Email.properties";
private String defaultPropsFileName = DEFAULT_FILE;
 
public synchronized static EmailProps getInstance() {
if (instance == null) {
30,14 → 37,36
@Override
protected String getPropsFileName() {
if (this.propsFileName == null) {
return "./Configuration/Email.properties";
return getDefaultPropsFileName();
} else {
return this.propsFileName;
}
}
 
public void setDefaultPropsFileName(String defaultPropsFileName) {
this.defaultPropsFileName = defaultPropsFileName;
}
 
protected String getDefaultPropsFileName() {
if (this.defaultPropsFileName == null) {
return DEFAULT_FILE;
} else {
return defaultPropsFileName;
}
}
 
public void setPropsFileName(String propsFileName) {
this.propsFileName = propsFileName;
final File file = new File(getPropsFileName());
final File fileDefault = new File(getDefaultPropsFileName());
if (!file.exists() && fileDefault.exists()) {
try {
FileUtils.copyFile(fileDefault, file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
load();
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java
55,6 → 55,7
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
137,9 → 138,10
this.cacheLoading = false;
this.modifyingDoc = false;
 
this.setMinimumSize(new Dimension(80, 22));
final int h = new JTextField("12").getPreferredSize().height;
this.setMinimumSize(new Dimension(80, h));
// Test de Preferred Size pour ne pas exploser les GridBagLayouts
this.setPreferredSize(new Dimension(120, 22));
this.setPreferredSize(new Dimension(120, h));
this.setInteractionMode(InteractionMode.READ_WRITE);
 
// ATTN marche car locked est final, sinon il faudrait pouvoir enlever/ajouter les listeners
/trunk/OpenConcerto/src/org/openconcerto/ui/list/selection/ListSelectionState.java
204,6 → 204,7
final int[] interval = intervals.get(0);
this.getSelModel().setSelectionInterval(interval[0], interval[1]);
} else {
// ATTN minimize calls to the enclosing method as the code below is slow
this.getSelModel().setValueIsAdjusting(true);
this.getSelModel().clearSelection();
for (final int[] interval : intervals) {
/trunk/OpenConcerto/src/org/openconcerto/ui/RangedIntegerTableCellEditor.java
21,6 → 21,7
 
public RangedIntegerTableCellEditor(int min, int max) {
super(new JTextField());
((JTextField) getComponent()).setBorder(null);
this.min = min;
this.max = max;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/EnhancedTableUI.java
100,15 → 100,14
Rectangle clip = g.getClipBounds();
Point upperLeft = clip.getLocation();
Point lowerRight = new Point(clip.x + clip.width - 1, clip.y + clip.height - 1);
int rMin = 0;// table.rowAtPoint(upperLeft);
int rMax = table.getRowCount() - 1;// /table.rowAtPoint(lowerRight);
// This should never happen.
if (rMin == -1) {
int rMin = table.rowAtPoint(upperLeft);
int rMax = table.rowAtPoint(lowerRight);
if (rMin < 0) {
rMin = 0;
}
// If the table does not have enough rows to fill the view we'll get -1.
// Replace this with the index of the last row.
if (rMax == -1) {
if (rMax == -1 || rMax >= table.getRowCount()) {
rMax = table.getRowCount() - 1;
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightControler.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableContent.java
13,15 → 13,20
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class TableContent implements Transferable {
public class TableContent implements Transferable, Externalizable {
private static final long serialVersionUID = 3648381615123520834L;
private String tableId;
private List<Row> rows;
71,6 → 76,10
return this.rows.set(index, row);
}
 
public final synchronized void insertRow(final int index, final Row row) {
this.rows.add(index, row);
}
 
public final synchronized Row removeRow(final int index) {
return this.rows.remove(index);
}
120,4 → 129,28
this.setRows(listRows);
}
}
 
@Override
public synchronized void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(tableId);
out.writeInt(rows.size());
for (Row row : this.rows) {
row.writeExternal(out);
}
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
tableId = in.readUTF();
int size = in.readInt();
this.rows = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
final Row row = new Row();
row.readExternal(in);
this.rows.add(row);
}
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIStrippedImageLine.java
59,16 → 59,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIStrippedImageLine(json);
}
};
}
 
@Override
public String getHTML() {
StringBuilder b = new StringBuilder();
for (LightUIImage image : this.images) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIPasswordField.java
New file
0,0 → 1,57
/*
* 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.ui.light;
 
import org.openconcerto.utils.io.JSONConverter;
 
import net.minidev.json.JSONObject;
 
public class LightUIPasswordField extends LightUserControl {
 
public LightUIPasswordField() {
// Serialization
}
 
public LightUIPasswordField(final String id) {
super(id);
this.setType(TYPE_PASSWORD_FIELD);
this.setValueType(LightUIElement.VALUE_TYPE_STRING);
}
 
public LightUIPasswordField(final JSONObject json) {
super(json);
}
 
public LightUIPasswordField(final LightUIPasswordField text) {
super(text);
}
 
@Override
public Object getValueForContext() {
if (this.getValue() == null || this.getValue().trim().isEmpty()) {
return null;
}
return this.getValue();
}
 
@Override
public void _setValueFromContext(final Object value) {
final String strValue = JSONConverter.getObjectFromJSON(value, String.class);
if (strValue != null && !strValue.trim().isEmpty()) {
this.setValue(strValue);
} else {
this.setValue(null);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/InformationLine.java
16,9 → 16,13
import java.awt.Color;
 
public class InformationLine extends LightUILine {
final LightUILabel keyElement;
final LightUILabel valueElement;
private LightUILabel keyElement;
private LightUILabel valueElement;
 
public InformationLine() {
// Serialization
}
 
public InformationLine(final String key, final String value) {
super();
this.setGridAlignment(ALIGN_GRID);
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButton.java
22,8 → 22,12
import net.minidev.json.JSONObject;
 
public class LightUIButton extends LightUIElement {
private transient List<ActionListener> clickListeners = new ArrayList<ActionListener>();
protected transient List<ActionListener> clickListeners = new ArrayList<>();
 
public LightUIButton() {
// Serialization
}
 
public LightUIButton(final JSONObject json) {
super(json);
}
63,11 → 67,13
}
 
public void addClickListener(final ActionListener listener) {
if (!clickListeners.contains(listener)) {
this.clickListeners.add(listener);
}
}
 
public void removeClickListeners() {
this.clickListeners.clear();
public void removeClickListener(final ActionListener listener) {
this.clickListeners.remove(listener);
}
 
public List<ActionListener> getClickListeners() {
75,7 → 81,11
}
 
public void fireClick() {
for (final ActionListener listener : this.clickListeners) {
final List<ActionListener> listeners = new ArrayList<>(this.clickListeners.size());
listeners.addAll(this.clickListeners);
// The list is duplicated to avoid ConcurrentModificationException when a listener destroys
// this button
for (final ActionListener listener : listeners) {
listener.actionPerformed(new ActionEvent(this, 1, "click"));
}
}
83,16 → 93,7
@Override
public void destroy() {
super.destroy();
this.clickListeners.clear();
this.clickListeners = null;
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(JSONObject json) {
return new LightUIButton(json);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITextArea.java
44,16 → 44,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUITextArea(json);
}
};
}
 
@Override
protected void copy(final LightUIElement element) {
super.copy(element);
if (!(element instanceof LightUITextArea)) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUILabel.java
16,6 → 16,11
import net.minidev.json.JSONObject;
 
public class LightUILabel extends LightUIElement {
 
public LightUILabel() {
// Serialization
}
 
// Init from json constructor
public LightUILabel(final JSONObject json) {
super(json);
45,14 → 50,4
this.setFontBold(isBold);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUILabel(json);
}
};
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowsBulk.java
54,11 → 54,11
if (rowCount == 0) {
this.rows = Collections.emptyList();
} else {
this.rows = new ArrayList<Row>(rowCount);// colcount
this.rows = new ArrayList<>(rowCount);
int columnCount = in.readByte();
// id
for (int j = 0; j < rowCount; j++) {
Row row = new Row((Number) in.readObject(), columnCount);
Row row = new Row((Number) in.readObject());
this.rows.add(row);
}
 
82,7 → 82,7
int rowCount = this.rows.size();
out.writeInt(rowCount);
// content
if (this.rows.size() > 0) {
if (!this.rows.isEmpty()) {
// nbcols
int columnCount = this.rows.get(0).getValues().size();
out.writeByte(columnCount);
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUISlider.java
15,17 → 15,26
 
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashMap;
import java.util.Map;
 
import net.minidev.json.JSONObject;
 
public class LightUISlider extends LightUserControl {
private Integer maxValue = 1;
private Integer minValue = 0;
private Integer increment = 1;
public class LightUISlider extends LightUserControl implements Externalizable {
 
private int minValue = 0;
private int maxValue = 1;
private int increment = 1;
private Map<Integer, String> mapLabels = new HashMap<>();
 
public LightUISlider() {
// Serialization
}
 
public LightUISlider(final String id) {
super(id);
this.setType(TYPE_SLIDER);
149,12 → 158,29
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeInt(this.minValue);
out.writeInt(this.maxValue);
out.writeInt(this.increment);
// map
out.writeInt(this.mapLabels.size());
for (Map.Entry<Integer, String> entry : mapLabels.entrySet()) {
out.writeInt(entry.getKey());
out.writeUTF(entry.getValue());
}
}
 
@Override
public LightUIElement convert(JSONObject json) {
return new LightUISlider(json);
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.minValue = in.readInt();
this.maxValue = in.readInt();
this.increment = in.readInt();
this.mapLabels.clear();
int size = in.readInt();
for (int i = 0; i < size; i++) {
this.mapLabels.put(in.readInt(), in.readUTF());
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightController.java
New file
0,0 → 1,103
/*
* 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.ui.light;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
 
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
import net.minidev.json.JSONObject;
 
public class LightController implements Externalizable, Transferable {
/**
*
*/
private static final long serialVersionUID = 5894135825924339012L;
private String type, src, dest;
public static final String TYPE_ACTIVATION_ON_SELECTION = "activationOnSelection";
public static final String TYPE_ADD_DEFAULT = "addDefault";
public static final String TYPE_INSERT_DEFAULT = "insertDefault";
public static final String TYPE_COPY = "copy";
public static final String TYPE_REMOVE = "remove";
public static final String TYPE_UP = "up";
public static final String TYPE_DOWN = "down";
public static final String TYPE_CLOSE = "close";
public static final String TYPE_TILT_PREVIOUS = "tilt.previous";
public static final String TYPE_TILT_NEXT = "tilt.next";
 
public LightController() {
// Serialization
}
 
public LightController(final JSONObject json) {
this.fromJSON(json);
}
 
public LightController(final String type, final String src, final String dest) {
this.type = type;
this.src = src;
this.dest = dest;
}
 
public String getType() {
return this.type;
}
 
public String getSrc() {
return this.src;
}
 
public String getDest() {
return this.dest;
}
 
@Override
public String toString() {
return super.getClass().getName() + " : " + this.type + " :" + this.src + "," + this.dest;
}
 
@Override
public JSONObject toJSON() {
final JSONObject result = new JSONObject();
result.put("class", "LightControler");
result.put("type", this.type);
result.put("src", this.src);
result.put("dest", this.dest);
return result;
}
 
@Override
public void fromJSON(final JSONObject json) {
this.type = (String) JSONConverter.getParameterFromJSON(json, "type", String.class);
this.src = (String) JSONConverter.getParameterFromJSON(json, "src", String.class);
this.dest = (String) JSONConverter.getParameterFromJSON(json, "dest", String.class);
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this.type);
out.writeUTF(this.src);
out.writeUTF(this.dest);
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.type = in.readUTF();
this.src = in.readUTF();
this.dest = in.readUTF();
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUICheckBox.java
17,6 → 17,10
 
public class LightUICheckBox extends LightUserControl {
 
public LightUICheckBox() {
// for serialization
}
 
public LightUICheckBox(final JSONObject json) {
super(json);
}
49,16 → 53,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUICheckBox(json);
}
};
}
 
@Override
public Object getValueForContext() {
return this.isChecked();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIDropDownButton.java
32,13 → 32,4
super(dropDownElement);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIDropDownButton(json);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIAutoCompleteComboBox.java
New file
0,0 → 1,94
/*
* 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.ui.light;
 
import org.openconcerto.utils.io.JSONConverter;
 
import java.util.List;
import java.util.Optional;
 
import net.minidev.json.JSONObject;
 
public class LightUIAutoCompleteComboBox extends LightUIComboBox {
private static final String FILTER = "filter";
 
private String filter;
 
private LightUIComboRequest request;
 
public LightUIAutoCompleteComboBox() {
}
 
public LightUIAutoCompleteComboBox(final String id) {
super(id);
this.setType(TYPE_AUTOCOMPLETE_COMBOBOX);
}
 
public void setComboRequest(final LightUIComboRequest request) {
this.request = request;
this.setFilter("");
this.setAlreadyFilled(true);
}
 
public LightUIComboRequest getComboRequest() {
return this.request;
}
 
public String getFilter() {
return this.filter;
}
 
public void setFilter(final String filter) {
this.filter = filter;
this.applyFilter();
}
 
private void applyFilter() {
if (this.request != null) {
Integer selectedId = null;
if (this.hasSelectedValue()) {
selectedId = this.getSelectedValue().getId();
}
 
this.clearValues();
if (this.hasNotSpecifedLine()) {
this.addValue(LightUIComboBox.getDefaultValue());
}
 
final Optional<LightUIComboBoxElement> sel = Optional.ofNullable(this.hasSelectedValue() ? this.getSelectedValue() : null);
final List<LightUIComboBoxElement> items = this.request.getItems(this.filter, sel);
 
for (final LightUIComboBoxElement item : items) {
this.addValue(item);
}
 
this.setSelectedId(selectedId);
}
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
json.put(FILTER, this.filter);
return json;
}
 
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
 
this.filter = JSONConverter.getParameterFromJSON(json, FILTER, String.class);
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFrame.java
15,6 → 15,9
 
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
35,6 → 38,10
 
private List<LightUIFrame> childrenFrame;
 
public LightUIFrame() {
// Serialization
}
 
// Init from json constructor
public LightUIFrame(final JSONObject json) {
super(json);
50,6 → 57,22
this.setFooterPanel(frame.footerPanel);
}
 
@Override
public void destroy() {
super.destroy();
if (this.titlePanel != null) {
this.titlePanel.destroy();
}
if (this.footerPanel != null) {
this.footerPanel.destroy();
}
if (this.childrenFrame != null) {
for (LightUIFrame frame : childrenFrame) {
frame.destroy();
}
}
}
 
/**
* Creation of an instance of a frame, this one is initialized with an empty main panel
*
228,16 → 251,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIFrame(json);
}
};
}
 
@Override
public void dump(final PrintStream out, final int depth) {
out.println("------------- LightUIFrame -------------");
super.dump(out, 0);
269,7 → 282,7
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
this.active = JSONConverter.getParameterFromJSON(json, KEY_ACTIVE, Boolean.class, false);
 
this.createTitlePanel();
final JSONObject jsonTitlePanel = JSONConverter.getParameterFromJSON(json, KEY_TITLE_PANEL, JSONObject.class);
if (jsonTitlePanel != null) {
this.titlePanel.fromJSON(jsonTitlePanel);
290,4 → 303,37
}
}
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeBoolean(this.active);
// Title panel
if (this.titlePanel != null) {
out.writeBoolean(true);
out.writeObject(this.titlePanel);
} else {
out.writeBoolean(false);
}
// Footer panel
if (this.footerPanel != null) {
out.writeBoolean(true);
out.writeObject(this.footerPanel);
} else {
out.writeBoolean(false);
}
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.active = in.readBoolean();
if (in.readBoolean()) {
this.titlePanel = (LightUIPanel) in.readObject();
}
if (in.readBoolean()) {
this.footerPanel = (LightUIPanel) in.readObject();
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIPanel.java
17,6 → 17,9
import org.openconcerto.utils.io.Transferable;
 
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
25,14 → 28,17
import net.minidev.json.JSONObject;
 
public class LightUIPanel extends LightUserControlContainer implements Transferable {
 
private static final long serialVersionUID = -3399395824294128572L;
 
private String title;
 
private Color titleColor;
private Color titleBackgroundColor;
private List<LightController> controlers = new ArrayList<>();
 
private final List<LightControler> controlers = new ArrayList<LightControler>();
public LightUIPanel() {
// Serialization
}
 
public LightUIPanel(final JSONObject json) {
super(json);
51,6 → 57,12
this.setFillHeight(true);
}
 
@Override
public void destroy() {
super.destroy();
this.controlers = null;
}
 
public final LightUILine getLastLine() {
final int childCount = this.getChildrenCount();
if (childCount == 0) {
78,11 → 90,11
this.titleBackgroundColor = c;
}
 
public void addControler(final LightControler controler) {
public void addControler(final LightController controler) {
this.controlers.add(controler);
}
 
public List<LightControler> getControlers() {
public List<LightController> getControlers() {
return this.controlers;
}
 
93,7 → 105,7
public void dumpControllers(final PrintStream out, final int depth) {
addSpacer(out, depth);
out.println("Contollers for id:" + this.getId() + " title: " + this.title);
for (LightControler controler : this.controlers) {
for (LightController controler : this.controlers) {
addSpacer(out, depth);
out.println(controler);
}
167,16 → 179,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIPanel(json);
}
};
}
 
@Override
public void dump(final PrintStream out, final int depth) {
this.addSpacer(out, depth);
out.println("------LightUIPanel-----");
254,12 → 256,45
final int controlersSize = jsonControlers.size();
for (int i = 0; i < controlersSize; i++) {
final JSONObject jsonControler = JSONConverter.getObjectFromJSON(jsonControlers.get(i), JSONObject.class);
this.controlers.add(new LightControler((JSONObject) jsonControler));
this.controlers.add(new LightController((JSONObject) jsonControler));
}
}
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
writeIfNotNull(out, this.title);
writeIfNotNull(out, this.titleColor);
writeIfNotNull(out, this.titleBackgroundColor);
out.writeByte(this.controlers.size());
for (LightController lightControler : controlers) {
lightControler.writeExternal(out);
}
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
if (in.readBoolean()) {
this.title = in.readUTF();
}
if (in.readBoolean()) {
this.titleColor = new Color(in.readInt());
}
if (in.readBoolean()) {
this.titleBackgroundColor = new Color(in.readInt());
}
this.controlers.clear();
final int size = in.readByte();
for (int i = 0; i < size; i++) {
final LightController lightControler = new LightController();
lightControler.readExternal(in);
this.controlers.add(lightControler);
}
}
 
@Override
public void setFoldable(boolean foldable) {
super.setFoldable(foldable);
if (foldable && this.title == null) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIBadge.java
29,13 → 29,4
this.setLabel(label);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(JSONObject json) {
return new LightUIBadge(json);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowSelectionSpec.java
43,12 → 43,13
}
public RowSelectionSpec(String tableId) {
this(tableId, new ArrayList<Number>());
this(tableId, new ArrayList<Number>(0));
}
 
public RowSelectionSpec(final String tableId, final List<Number> selectedIds) {
this.tableId = tableId;
this.ids = selectedIds;
this.ids = new ArrayList<>(selectedIds);
this.ids.addAll(selectedIds);
}
 
public final List<Number> getIds() {
56,15 → 57,20
}
public final void setIds(List<Number> ids) {
this.ids = ids;
this.ids.clear();
this.ids.addAll(ids);
}
 
public void clear() {
this.ids.clear();
}
 
public String getTableId() {
return this.tableId;
}
public boolean hasSelectedId(){
return this.getIds() != null && !this.getIds().isEmpty();
return !this.getIds().isEmpty();
}
 
@Override
113,7 → 119,7
public void fromJSON(JSONObject json) {
this.tableId = JSONConverter.getParameterFromJSON(json, "table-id", String.class);
final JSONArray jsonIds = JSONConverter.getParameterFromJSON(json, "ids", JSONArray.class);
this.ids = new ArrayList<Number>();
this.ids = new ArrayList<>(jsonIds.size());
for (final Object jsonId : jsonIds) {
this.ids.add(JSONConverter.getObjectFromJSON(jsonId, Number.class));
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIComboBox.java
16,6 → 16,9
import org.openconcerto.utils.i18n.TranslationManager;
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
33,8 → 36,12
 
private LightUIComboBoxElement selectedValue = null;
 
private List<LightUIComboBoxElement> values = new ArrayList<LightUIComboBoxElement>();
private List<LightUIComboBoxElement> values = new ArrayList<>();
 
public LightUIComboBox() {
// Serialization
}
 
// Init from json constructor
public LightUIComboBox(final JSONObject json) {
super(json);
138,16 → 145,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIComboBox(json);
}
};
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
 
215,6 → 212,45
@Override
public void destroy() {
super.destroy();
this.clearValues();
this.selectedValue = null;
this.values = null;
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeBoolean(this.alreadyFilled);
out.writeBoolean(this.hasNotSpecifedLine);
 
if (this.selectedValue != null) {
out.writeBoolean(true);
this.selectedValue.writeExternal(out);
} else {
out.writeBoolean(false);
}
out.writeInt(this.values.size());
for (LightUIComboBoxElement e : this.values) {
e.writeExternal(out);
}
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.alreadyFilled = in.readBoolean();
this.hasNotSpecifedLine = in.readBoolean();
if (in.readBoolean()) {
this.selectedValue = new LightUIComboBoxElement();
this.selectedValue.readExternal(in);
}
int size = in.readInt();
this.values.clear();
for (int i = 0; i < size; i++) {
LightUIComboBoxElement e = new LightUIComboBoxElement();
e.readExternal(in);
this.values.add(e);
}
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIComboRequest.java
New file
0,0 → 1,21
/*
* 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.ui.light;
 
import java.util.List;
import java.util.Optional;
 
public interface LightUIComboRequest {
public List<LightUIComboBoxElement> getItems(final String filter, final Optional<LightUIComboBoxElement> selection);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIPictureUpload.java
23,6 → 23,9
 
private String filePath = null;
 
public LightUIPictureUpload() {
}
 
public LightUIPictureUpload(final String id, final String sendFileUrl) {
super(id, sendFileUrl);
this.setType(TYPE_PICTURE_UPLOAD);
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButtonWithSelectionContext.java
19,7 → 19,7
 
public class LightUIButtonWithSelectionContext extends LightUIButton {
 
RowSelectionSpec tableSelection;
private RowSelectionSpec tableSelection;
 
public LightUIButtonWithSelectionContext(final JSONObject json) {
super(json);
34,6 → 34,12
super(button);
}
 
@Override
public void destroy() {
super.destroy();
this.tableSelection = null;
}
 
public RowSelectionSpec getTableSelection() {
return this.tableSelection;
}
52,8 → 58,9
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
 
this.tableSelection = (RowSelectionSpec) JSONConverter.getParameterFromJSON(json, "table-selection", RowSelectionSpec.class);
this.tableSelection = new RowSelectionSpec();
final JSONObject o = (JSONObject) json.get("table-selection");
this.tableSelection.fromJSON(o);
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/light/SearchSpec.java
13,19 → 13,28
package org.openconcerto.ui.light;
 
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONAware;
import net.minidev.json.JSONObject;
 
public class SearchSpec implements Transferable, JSONAware {
public class SearchSpec implements Transferable, JSONAware, Externalizable {
private String tableId;
private List<SearchContent> content = new ArrayList<SearchContent>();
private List<SearchContent> content = new ArrayList<>();
 
public SearchSpec() {
// Serialization
}
 
public SearchSpec(final String tableId) {
this.tableId = tableId;
}
69,4 → 78,16
public String toJSONString() {
return toJSON().toJSONString();
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this.tableId);
out.writeObject(this.content);
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.tableId = in.readUTF();
this.content = (List<SearchContent>) in.readObject();
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButtonUnmanaged.java
16,6 → 16,11
import net.minidev.json.JSONObject;
 
public class LightUIButtonUnmanaged extends LightUIElement {
 
public LightUIButtonUnmanaged() {
// Serialization
}
 
public LightUIButtonUnmanaged(final JSONObject json) {
super(json);
}
37,14 → 42,4
super(button);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIButtonUnmanaged(json);
}
};
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIHTMLStrippedPanel.java
34,16 → 34,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIHTMLStrippedPanel(json);
}
};
}
 
@Override
public LightUIElement clone() {
return new LightUIHTMLStrippedPanel(this);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ActivationOnSelectionControler.java
13,10 → 13,10
package org.openconcerto.ui.light;
 
public class ActivationOnSelectionControler extends LightControler {
public class ActivationOnSelectionControler extends LightController {
 
public ActivationOnSelectionControler(String src, String dest) {
super(LightControler.TYPE_ACTIVATION_ON_SELECTION, src, dest);
super(LightController.TYPE_ACTIVATION_ON_SELECTION, src, dest);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITab.java
54,17 → 54,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
 
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUITab(json);
}
};
}
 
@Override
public LightUIElement clone() {
return new LightUITab(this);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/JSONToLightUIConvertorManager.java
20,7 → 20,7
import net.minidev.json.JSONObject;
 
public class JSONToLightUIConvertorManager {
HashMap<String, JSONToLightUIConvertor> map = new HashMap<String, JSONToLightUIConvertor>();
HashMap<String, JSONToLightUIConvertor> map = new HashMap<>();
 
private static final JSONToLightUIConvertorManager instance = new JSONToLightUIConvertorManager();
 
33,15 → 33,206
}
 
public LightUIElement createUIElementFromJSON(final JSONObject jsonElement) {
final Integer elementType = (Integer) JSONConverter.getParameterFromJSON(jsonElement, "type", Integer.class, null);
if (elementType == null) {
throw new IllegalArgumentException("LightUIElement must contains attribute 'type'");
final Integer type = (Integer) JSONConverter.getParameterFromJSON(jsonElement, "type", Integer.class, null);
switch (type) {
case LightUIElement.TYPE_LABEL: {
final LightUILabel l = new LightUILabel();
l.fromJSON(jsonElement);
return l;
}
final String className = (String) JSONConverter.getParameterFromJSON(jsonElement, "class-name", String.class);
if (className == null) {
throw new IllegalArgumentException("class-name must be set");
case LightUIElement.TYPE_TEXT_FIELD: {
final LightUITextField l = new LightUITextField();
l.fromJSON(jsonElement);
return l;
 
}
final JSONToLightUIConvertor convertor = this.map.get(className);
return convertor.convert(jsonElement);
case LightUIElement.TYPE_DATE: {
final LightUIDate l = new LightUIDate();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_COMBOBOX: {
final LightUIComboBox l = new LightUIComboBox();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_TABLE: {
final LightUITable l = new LightUITable();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_CHECKBOX: {
final LightUICheckBox l = new LightUICheckBox();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_TABBED_UI: {
final LightUITabbed l = new LightUITabbed();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_COMBOBOX_ELEMENT: {
// TODO : WTF
throw new IllegalAccessError("WTF");
}
case LightUIElement.TYPE_PANEL: {
final LightUIPanel l = new LightUIPanel();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_TREE: {
// TODO : TYPE_TREE
throw new IllegalAccessError("TODO");
 
}
case LightUIElement.TYPE_TEXT: {
final LightUIText l = new LightUIText(jsonElement);
return l;
 
}
case LightUIElement.TYPE_LIST: {
final LightUIList l = new LightUIList(jsonElement);
return l;
 
}
case LightUIElement.TYPE_DROPDOWN_BUTTON: {
final LightUIDropDownButton l = new LightUIDropDownButton(jsonElement);
return l;
 
}
case LightUIElement.TYPE_FRAME: {
final LightUIFrame l = new LightUIFrame();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_IMAGE: {
final LightUIImage l = new LightUIImage(jsonElement);
return l;
}
case LightUIElement.TYPE_FILE_UPLOAD_WITH_SELECTION: {
final LightUIFileUpload l = new LightUIFileUpload();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_PANEL_LINE: {
final LightUILine l = new LightUILine();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_TAB_ELEMENT: {
final LightUITab l = new LightUITab(jsonElement);
return l;
 
}
case LightUIElement.TYPE_SLIDER: {
final LightUISlider l = new LightUISlider();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_PICTURE_UPLOAD: {
final LightUIPictureUpload l = new LightUIPictureUpload();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_BUTTON: {
final LightUIButton l = new LightUIButton();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_BUTTON_WITH_CONTEXT: {
final LightUIButtonWithContext l = new LightUIButtonWithContext(jsonElement);
return l;
 
}
case LightUIElement.TYPE_BUTTON_CANCEL: {
final LightUIButton button = new LightUIButton();
button.fromJSON(jsonElement);
return button;
}
case LightUIElement.TYPE_BUTTON_UNMANAGED: {
final LightUIButtonUnmanaged l = new LightUIButtonUnmanaged();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_BUTTON_WITH_SELECTION_CONTEXT: {
final LightUIButtonWithSelectionContext l = new LightUIButtonWithSelectionContext(jsonElement);
return l;
}
case LightUIElement.TYPE_BUTTON_LINK: {
final LightUIButtonLink l = new LightUIButtonLink();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_RAW_HTML: {
final LightUIRawHMTL l = new LightUIRawHMTL(jsonElement);
return l;
 
}
case LightUIElement.TYPE_TEXT_AREA: {
final LightUITextArea l = new LightUITextArea(jsonElement);
return l;
 
}
case LightUIElement.TYPE_FILE_UPLOAD: {
final LightUIFileUpload l = new LightUIFileUpload();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_LIST_ROW: {
final LightUIListRow l = new LightUIListRow(jsonElement);
return l;
 
}
case LightUIElement.TYPE_BADGE: {
final LightUIBadge l = new LightUIBadge(jsonElement);
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_AUTOCOMPLETE_COMBOBOX: {
final LightUIAutoCompleteComboBox l = new LightUIAutoCompleteComboBox();
l.fromJSON(jsonElement);
return l;
}
case LightUIElement.TYPE_COLOR_PICKER: {
final LightUIColorPicker l = new LightUIColorPicker(jsonElement);
return l;
 
}
case LightUIElement.TYPE_HOUR_EDITOR: {
final LightUIHourEditor l = new LightUIHourEditor(jsonElement);
return l;
 
}
case LightUIElement.TYPE_RADIO_BUTTONS: {
final LightUIRadioButtons l = new LightUIRadioButtons();
l.fromJSON(jsonElement);
return l;
 
}
case LightUIElement.TYPE_PASSWORD_FIELD: {
final LightUIPasswordField l = new LightUIPasswordField();
l.fromJSON(jsonElement);
return l;
 
}
 
}
throw new IllegalArgumentException("unsupported type " + type);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableSpec.java
16,9 → 16,14
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
 
import net.minidev.json.JSONObject;
 
public class TableSpec implements Transferable {
public class TableSpec implements Transferable, Externalizable {
private String id;
private ColumnsSpec columns;
private TableContent content;
26,6 → 31,10
private SearchSpec search;
private Boolean variableColumnsCount = false;
 
public TableSpec() {
// Serialization
}
 
public TableSpec(final String tableId, final RowSelectionSpec selection, final ColumnsSpec columns) {
this.id = tableId + ".spec";
if (selection == null) {
142,4 → 151,32
 
this.variableColumnsCount = (Boolean) JSONConverter.getParameterFromJSON(json, "variable-columns-count", Boolean.class);
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(id);
this.columns.writeExternal(out);
this.content.writeExternal(out);
 
this.selection.writeExternal(out);
this.search.writeExternal(out);
 
out.writeBoolean(this.variableColumnsCount);
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readUTF();
this.columns = new ColumnsSpec();
this.columns.readExternal(in);
this.content = new TableContent();
this.content.readExternal(in);
this.selection = new RowSelectionSpec();
this.selection.readExternal(in);
this.search = new SearchSpec();
this.search.readExternal(in);
this.variableColumnsCount = in.readBoolean();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIRadioButtons.java
13,6 → 13,9
package org.openconcerto.ui.light;
 
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
22,6 → 25,10
public class LightUIRadioButtons extends LightUserControl {
private final List<String> choices = new ArrayList<>();
 
public LightUIRadioButtons() {
// Serialization
}
 
// Init from json constructor
public LightUIRadioButtons(final JSONObject json) {
super(json);
86,13 → 93,22
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeInt(this.choices.size());
for (String c : this.choices) {
out.writeUTF(c);
}
}
 
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIRadioButtons(json);
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
int size = in.readInt();
this.choices.clear();
for (int i = 0; i < size; i++) {
this.choices.add(in.readUTF());
}
};
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIRawHMTL.java
37,16 → 37,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(JSONObject json) {
return new LightUIRawHMTL(json);
}
};
}
 
@Override
public String getHTML() {
return this.html;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/SimpleTextLine.java
15,6 → 15,10
 
public class SimpleTextLine extends LightUILine {
 
public SimpleTextLine() {
// Serialization
}
 
public SimpleTextLine(final String text) {
this(text, false, LightUIElement.HALIGN_LEFT);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITabbed.java
17,7 → 17,11
 
import net.minidev.json.JSONObject;
 
public abstract class LightUITabbed extends LightUserControlContainer {
public class LightUITabbed extends LightUserControlContainer {
 
public LightUITabbed() {
}
 
// Init from json constructor
public LightUITabbed(final JSONObject json) {
super(json);
42,7 → 46,8
* @param tabId: id of tab which you want to load. The tab id must match with a tab contained in
* childs
*/
public abstract void loadTab(final String tabId);
public void loadTab(final String tabId) {
}
 
@Override
public void setValue(final String value) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUserControl.java
16,6 → 16,11
import net.minidev.json.JSONObject;
 
public abstract class LightUserControl extends LightUIElement {
 
public LightUserControl() {
// Serialization
}
 
public LightUserControl(final JSONObject json) {
super(json);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIContainer.java
15,6 → 15,9
 
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
25,6 → 28,10
public class LightUIContainer extends LightUIElement {
private List<LightUIElement> children = new ArrayList<LightUIElement>(1);
 
public LightUIContainer() {
// Serialization
}
 
public LightUIContainer(final String id) {
super(id);
}
91,6 → 98,11
return this.children.size();
}
 
/**
* Remove all the children from this container
*
* Warning : it doesn't destroy the children
*/
public void clear() {
this.children.clear();
}
273,12 → 285,33
throw new IllegalArgumentException("null element in json parameter");
}
final LightUIElement lightElement = JSONToLightUIConvertorManager.getInstance().createUIElementFromJSON(jsonElement);
this.children.add(lightElement);
this.addChild(lightElement);
}
}
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeInt(this.children.size());
for (LightUIElement e : this.children) {
out.writeObject(e);
}
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
int n = in.readInt();
this.children.clear();
for (int i = 0; i < n; i++) {
LightUIElement e = (LightUIElement) in.readObject();
this.children.add(e);
}
 
}
 
@Override
public void destroy() {
super.destroy();
for (final LightUIElement child : this.children) {
286,13 → 319,4
}
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(JSONObject json) {
return new LightUIContainer(json);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIHourEditor.java
74,16 → 74,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIHourEditor(json);
}
};
}
 
@Override
public Object getValueForContext() {
return getIntVal();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFileUploadWithSelection.java
22,8 → 22,7
private static final String TABLE_ID_JSON_KEY = "table-id";
private String tableId;
 
public LightUIFileUploadWithSelection(final JSONObject json) {
super(json);
public LightUIFileUploadWithSelection() {
}
 
public LightUIFileUploadWithSelection(final LightUIFileUploadWithSelection file) {
39,16 → 38,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIFileUploadWithSelection(json);
}
};
}
 
@Override
public LightUIElement clone() {
return new LightUIFileUploadWithSelection(this);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITextField.java
18,6 → 18,11
import net.minidev.json.JSONObject;
 
public class LightUITextField extends LightUserControl {
 
public LightUITextField() {
// Serialization
}
 
public LightUITextField(final String id) {
super(id);
this.setType(TYPE_TEXT_FIELD);
33,16 → 38,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUITextField(json);
}
};
}
 
@Override
public Object getValueForContext() {
if (this.getValue() == null || this.getValue().trim().isEmpty()) {
return null;
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButtonLink.java
29,6 → 29,10
private Boolean openNewFrame = false;
private Map<String, String> urlParameters = new HashMap<String, String>();
 
public LightUIButtonLink() {
// Serialization
}
 
public LightUIButtonLink(final String id, final String filePath, final boolean openNewFrame) {
super(id);
this.setType(LightUIElement.TYPE_BUTTON_LINK);
44,6 → 48,12
super(button);
}
 
@Override
public void destroy() {
super.destroy();
urlParameters = null;
}
 
public Boolean isOpenNewFrame() {
return this.openNewFrame;
}
81,16 → 91,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIButtonLink(json);
}
};
}
 
@Override
public JSONObject toJSON() {
final JSONObject json = super.toJSON();
 
100,7 → 100,6
if (!this.urlParameters.isEmpty()) {
json.put(URL_PARAMETER_KEY, this.urlParameters);
}
 
return json;
}
 
110,4 → 109,5
this.openNewFrame = JSONConverter.getParameterFromJSON(json, OPEN_NEW_FRAME_KEY, Boolean.class, false);
this.urlParameters = CollectionUtils.castMap(JSONConverter.getParameterFromJSON(json, URL_PARAMETER_KEY, Map.class), String.class, String.class);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIElement.java
18,11 → 18,15
import org.openconcerto.utils.io.Transferable;
 
import java.awt.Color;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.PrintStream;
 
import net.minidev.json.JSONObject;
 
public abstract class LightUIElement implements Transferable {
public abstract class LightUIElement implements Transferable, Externalizable {
 
private static final String HORIZONTALLY_RESIZABLE = "horizontally-resizable";
private static final String VERTICALLY_SCROLLABLE = "vertically-scrollable";
84,6 → 88,8
public static final int TYPE_COLOR_PICKER = 32;
public static final int TYPE_HOUR_EDITOR = 33;
public static final int TYPE_RADIO_BUTTONS = 34;
public static final int TYPE_PASSWORD_FIELD = 35;
 
// valueType
public static final int VALUE_TYPE_STRING = 0;
public static final int VALUE_TYPE_INTEGER = 1;
182,13 → 188,28
private Color foreColor;
 
private LightUIElement parent;
private boolean destroyed;
 
public LightUIElement() {
// Serialization
}
 
public LightUIElement(final String id) {
this.id = id;
this.UUID = java.util.UUID.randomUUID().toString();
this.UUID = getNextUUID();// java.util.UUID.randomUUID().toString();
}
 
JSONToLightUIConvertorManager.getInstance().put(this.getClassName(), this.getConvertor());
private static long count = 0;
private static Integer counterLock = new Integer(123456);
 
private String getNextUUID() {
String result;
synchronized (counterLock) {
count++;
result = "UUID" + count;
}
return result;
}
 
// Init from json constructor
public LightUIElement(final JSONObject json) {
522,10 → 543,6
return this.UUID;
}
 
public void changeUUID() {
this.UUID = java.util.UUID.randomUUID().toString();
}
 
public String getLabel() {
return this.label;
}
727,54 → 744,54
}
 
public final String getTypeAsString() {
String type = "?";
String result = "?";
if (this.type == TYPE_CHECKBOX) {
type = "checkbox";
result = "checkbox";
} else if (this.type == TYPE_COMBOBOX) {
type = "combobox";
result = "combobox";
} else if (this.type == TYPE_LABEL) {
type = "label";
result = "label";
} else if (this.type == TYPE_TEXT_AREA) {
type = "textarea";
result = "textarea";
} else if (this.type == TYPE_TEXT_FIELD) {
type = "textfield";
result = "textfield";
} else if (this.type == TYPE_TABLE) {
type = "table";
result = "table";
} else if (this.type == TYPE_TABBED_UI) {
type = "tabs";
result = "tabs";
} else if (this.type == TYPE_TREE) {
type = "tree";
result = "tree";
} else if (this.type == TYPE_BUTTON) {
type = "button";
result = "button";
} else if (this.type == TYPE_BUTTON_WITH_CONTEXT) {
type = "button with context";
result = "button with context";
} else if (this.type == TYPE_BUTTON_CANCEL) {
type = "cancel button";
result = "cancel button";
} else if (this.type == TYPE_COMBOBOX_ELEMENT) {
type = "combo element";
result = "combo element";
} else if (this.type == TYPE_BUTTON_WITH_SELECTION_CONTEXT) {
type = "button with selection context";
result = "button with selection context";
} else if (this.type == TYPE_FILE_UPLOAD_WITH_SELECTION) {
type = "file upload with selection";
result = "file upload with selection";
} else if (this.type == TYPE_FRAME) {
type = "frame";
result = "frame";
} else if (this.type == TYPE_DROPDOWN_BUTTON) {
type = "drop down button";
result = "drop down button";
} else if (this.type == TYPE_IMAGE) {
type = "image";
result = "image";
} else if (this.type == TYPE_LIST) {
type = "list";
result = "list";
} else if (this.type == TYPE_RAW_HTML) {
type = "raw html";
result = "raw html";
} else if (this.type == TYPE_SLIDER) {
type = "slider";
result = "slider";
} else if (this.type == TYPE_PICTURE_UPLOAD) {
type = "picture upload";
result = "picture upload";
} else if (this.type == TYPE_FILE_UPLOAD) {
type = "file upload";
result = "file upload";
}
 
return type;
return result;
}
 
public String getClassName() {
781,8 → 798,6
return this.getClass().getName();
}
 
public abstract JSONToLightUIConvertor getConvertor();
 
/**
* { return new JSONToLightUIConvertor() {
*
851,8 → 866,12
 
@Override
public String toString() {
if (!destroyed) {
return super.toString() + " " + this.id;
} else {
return super.toString() + " " + this.id + " DESTROYED";
}
}
 
@Override
public JSONObject toJSON() {
878,10 → 897,15
if (this.weightX != DEFAULT_WEIGHT_X) {
result.put("weight-x", this.weightX);
}
 
if (this.weightY != DEFAULT_WEIGHT_Y) {
result.put("weight-y", this.weightY);
}
if (this.commitMode != null) {
result.put("commit-mode", this.commitMode);
}
if (this.width != null) {
result.put("width", this.width);
}
if (this.height != null) {
result.put("height", this.height);
}
928,9 → 952,6
if (this.valueType != null) {
result.put("value-type", this.valueType);
}
if (this.width != null) {
result.put("width", this.width);
}
 
if (!this.enabled) {
result.put("enabled", false);
1040,10 → 1061,12
this.horizontalAlignment = JSONConverter.getParameterFromJSON(json, "horizontal-alignment", Integer.class, HALIGN_LEFT);
this.verticalAlignment = JSONConverter.getParameterFromJSON(json, "vertical-alignment", Integer.class, VALIGN_TOP);
this.weightX = JSONConverter.getParameterFromJSON(json, "weight-x", Integer.class, DEFAULT_WEIGHT_X);
this.weightY = JSONConverter.getParameterFromJSON(json, "weight-y", Integer.class, DEFAULT_WEIGHT_Y);
this.minInputSize = JSONConverter.getParameterFromJSON(json, "min-input-size", Integer.class);
this.type = JSONConverter.getParameterFromJSON(json, "type", Integer.class);
this.valueType = JSONConverter.getParameterFromJSON(json, "value-type", Integer.class);
this.width = JSONConverter.getParameterFromJSON(json, "width", Integer.class);
this.height = JSONConverter.getParameterFromJSON(json, "height", Integer.class);
this.marginTop = JSONConverter.getParameterFromJSON(json, "m-top", Integer.class);
this.marginBottom = JSONConverter.getParameterFromJSON(json, "m-bottom", Integer.class);
this.marginLeft = JSONConverter.getParameterFromJSON(json, "m-left", Integer.class);
1050,7 → 1073,7
this.marginRight = JSONConverter.getParameterFromJSON(json, "m-right", Integer.class);
this.maxWidth = JSONConverter.getParameterFromJSON(json, "max-width", Integer.class);
this.minWidth = JSONConverter.getParameterFromJSON(json, "min-width", Integer.class);
this.height = JSONConverter.getParameterFromJSON(json, "height", Integer.class);
 
this.maxHeight = JSONConverter.getParameterFromJSON(json, "max-height", Integer.class);
this.minHeight = JSONConverter.getParameterFromJSON(json, "min-height", Integer.class);
this.paddingTop = JSONConverter.getParameterFromJSON(json, "p-top", Integer.class);
1081,5 → 1104,241
 
public void destroy() {
this.setValue(null);
this.parent = null;
this.destroyed = true;
}
 
public boolean isDestroyed() {
return destroyed;
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(this.type);
if (this.id == null) {
throw new IllegalStateException("null id");
}
out.writeUTF(this.id);
if (this.UUID == null) {
throw new IllegalStateException("UUID");
}
out.writeUTF(this.UUID);
 
writeIfNotNull(out, this.label);
writeIfNotNull(out, this.value);
 
out.writeInt(this.fontSize);
out.writeInt(this.gridWidth);
out.writeInt(this.gridHeight);
 
out.writeByte(this.horizontalAlignment);
out.writeByte(this.verticalAlignment);
out.writeByte(this.weightX);
out.writeByte(this.weightY);
 
writeIfNotNull(out, this.commitMode);
writeIfNotNull(out, this.width);
writeIfNotNull(out, this.height);
 
// Margins
writeIfNotNull(out, this.marginBottom);
writeIfNotNull(out, this.marginLeft);
writeIfNotNull(out, this.marginRight);
writeIfNotNull(out, this.marginTop);
//
writeIfNotNull(out, this.maxHeight);
writeIfNotNull(out, this.maxWidth);
 
writeIfNotNull(out, this.minInputSize);
writeIfNotNull(out, this.minHeight);
writeIfNotNull(out, this.minWidth);
 
// Paddings
writeIfNotNull(out, this.paddingBottom);
writeIfNotNull(out, this.paddingLeft);
writeIfNotNull(out, this.paddingRight);
writeIfNotNull(out, this.paddingTop);
 
writeIfNotNull(out, this.valueType);
 
out.writeBoolean(this.enabled);
out.writeBoolean(this.fillWidth);
out.writeBoolean(this.fillHeight);
out.writeBoolean(this.foldable);
out.writeBoolean(this.folded);
out.writeBoolean(this.fontBold);
out.writeBoolean(this.fontItalic);
out.writeBoolean(this.horizontallyResizable);
out.writeBoolean(this.horizontallyScrollable);
out.writeBoolean(this.required);
out.writeBoolean(this.readOnly);
out.writeBoolean(this.verticallyResizable);
out.writeBoolean(this.verticallyScrollable);
 
out.writeBoolean(this.visible);
out.writeBoolean(this.notSaved);
 
writeIfNotNull(out, this.displayPrecision);
writeIfNotNull(out, this.icon);
writeIfNotNull(out, this.toolTip);
writeIfNotNull(out, this.valuePrecision);
writeIfNotNull(out, this.valueRange);
 
// Colors
writeIfNotNull(out, this.backgroundColor);
writeIfNotNull(out, this.borderColor);
writeIfNotNull(out, this.cellBackgroundColor);
writeIfNotNull(out, this.foreColor);
}
 
void writeIfNotNull(ObjectOutput out, String s) throws IOException {
if (s != null) {
out.writeBoolean(true);
out.writeUTF(s);
} else {
out.writeBoolean(false);
}
}
 
void writeIfNotNull(ObjectOutput out, Integer s) throws IOException {
if (s != null) {
out.writeBoolean(true);
out.writeInt(s);
} else {
out.writeBoolean(false);
}
}
 
void writeIfNotNull(ObjectOutput out, Color s) throws IOException {
if (s != null) {
out.writeBoolean(true);
out.writeInt(s.getRGB());
} else {
out.writeBoolean(false);
}
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.type = in.readInt();
this.id = in.readUTF();
this.UUID = in.readUTF();
if (in.readBoolean()) {
this.label = in.readUTF();
}
if (in.readBoolean()) {
this.value = in.readUTF();
}
this.fontSize = in.readInt();
this.gridWidth = in.readInt();
this.gridHeight = in.readInt();
this.horizontalAlignment = in.readByte();
this.verticalAlignment = in.readByte();
this.weightX = in.readByte();
this.weightY = in.readByte();
 
if (in.readBoolean()) {
this.commitMode = in.readInt();
}
if (in.readBoolean()) {
this.width = in.readInt();
}
if (in.readBoolean()) {
this.height = in.readInt();
}
// Margins
if (in.readBoolean()) {
this.marginBottom = in.readInt();
}
if (in.readBoolean()) {
this.marginLeft = in.readInt();
}
if (in.readBoolean()) {
this.marginRight = in.readInt();
}
if (in.readBoolean()) {
this.marginTop = in.readInt();
}
 
//
if (in.readBoolean()) {
this.maxHeight = in.readInt();
}
if (in.readBoolean()) {
this.maxWidth = in.readInt();
}
 
if (in.readBoolean()) {
this.minInputSize = in.readInt();
}
if (in.readBoolean()) {
this.minHeight = in.readInt();
}
if (in.readBoolean()) {
this.minWidth = in.readInt();
}
 
// Paddings
if (in.readBoolean()) {
this.paddingBottom = in.readInt();
}
if (in.readBoolean()) {
this.paddingLeft = in.readInt();
}
if (in.readBoolean()) {
this.paddingRight = in.readInt();
}
if (in.readBoolean()) {
this.paddingTop = in.readInt();
}
if (in.readBoolean()) {
this.valueType = in.readInt();
}
 
this.enabled = in.readBoolean();
this.fillWidth = in.readBoolean();
this.fillHeight = in.readBoolean();
this.foldable = in.readBoolean();
this.folded = in.readBoolean();
this.fontBold = in.readBoolean();
this.fontItalic = in.readBoolean();
this.horizontallyResizable = in.readBoolean();
this.horizontallyScrollable = in.readBoolean();
this.required = in.readBoolean();
this.readOnly = in.readBoolean();
this.verticallyResizable = in.readBoolean();
this.verticallyScrollable = in.readBoolean();
 
//
this.visible = in.readBoolean();
this.notSaved = in.readBoolean();
if (in.readBoolean()) {
this.displayPrecision = in.readUTF();
}
if (in.readBoolean()) {
this.icon = in.readUTF();
}
if (in.readBoolean()) {
this.toolTip = in.readUTF();
}
if (in.readBoolean()) {
this.valuePrecision = in.readUTF();
}
if (in.readBoolean()) {
this.valueRange = in.readUTF();
}
// Colors
if (in.readBoolean()) {
this.backgroundColor = new Color(in.readInt());
}
if (in.readBoolean()) {
this.borderColor = new Color(in.readInt());
}
if (in.readBoolean()) {
this.cellBackgroundColor = new Color(in.readInt());
}
if (in.readBoolean()) {
this.foreColor = new Color(in.readInt());
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIColorPicker.java
55,13 → 55,4
return this.getValue();
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(JSONObject json) {
return new LightUIColorPicker(json);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIDate.java
18,11 → 18,18
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
 
import net.minidev.json.JSONObject;
 
public class LightUIDate extends LightUserControl {
 
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.S";
 
public LightUIDate() {
// Serialization
}
 
public LightUIDate(final JSONObject json) {
super(json);
}
39,7 → 46,7
 
public Timestamp getValueAsDate() {
if (this.getValue() != null && !this.getValue().isEmpty()) {
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");
SimpleDateFormat df2 = new SimpleDateFormat(DATE_FORMAT);
try {
return new Timestamp(df2.parse(this.getValue()).getTime());
} catch (final ParseException ex) {
49,15 → 56,10
return null;
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIDate(json);
public void setDate(Date date) {
SimpleDateFormat df2 = new SimpleDateFormat(DATE_FORMAT);
this.setValue(df2.format(date));
}
};
}
 
@Override
public Object getValueForContext() {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/Row.java
30,7 → 30,7
public class Row implements Externalizable, JSONAble {
 
private Number id;
private String extendId;
private String extendId = "";// writeExternal crash if not set
private List<Object> values;
 
private Boolean fillWidth = false;
47,7 → 47,7
 
public Row(final Number id, int valueCount) {
this.id = id;
this.values = new ArrayList<Object>();
this.values = new ArrayList<>(valueCount);
if (valueCount > 0) {
for (int i = 0; i < valueCount; i++) {
this.values.add(null);
57,6 → 57,7
 
public Row(final Number id) {
this.id = id;
this.values = new ArrayList<>();
}
 
public final void setValues(List<Object> values) {
76,6 → 77,9
}
 
public final void setExtendId(final String extendId) {
if (extendId == null) {
throw new IllegalArgumentException("extendId cannot be null");
}
this.extendId = extendId;
}
 
182,6 → 186,8
objValue = JSONConverter.getObjectFromJSON(objValue, Long.class);
} else if (objValue instanceof Boolean) {
objValue = JSONConverter.getObjectFromJSON(objValue, Boolean.class);
} else if (objValue instanceof Double) {
objValue = JSONConverter.getObjectFromJSON(objValue, Double.class);
} else if (objValue != null) {
throw new IllegalArgumentException("unknow type: " + objValue.getClass().getName());
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIImage.java
31,14 → 31,4
super(image);
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIImage(json);
}
};
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ColumnSpec.java
45,7 → 45,7
// Default value (to add a new line)
private Object defaultValue;
 
private Integer horizontalAlignment = null;
private Integer horizontalAlignment = LightUIElement.HALIGN_LEFT;
 
private double width;
private double maxWidth;
119,6 → 119,11
return this.horizontalAlignment;
}
 
/**
*
* @param horizontalAlignment LightUIElement.HALIGN_LEFT, LightUIElement.HALIGN_RIGHT or
* LightUIElement.HALIGN_CENTER
*/
public void setHorizontalAlignment(final int horizontalAlignment) {
this.horizontalAlignment = horizontalAlignment;
}
184,6 → 189,7
this.width = 200;
this.maxWidth = 500;
this.minWidth = 50;
this.horizontalAlignment = LightUIElement.HALIGN_LEFT;
}
 
public Element createXmlColumnPref() {
243,7 → 249,7
}
result.put(VALUE_CLASS, JSONConverter.getJSON(this.valueClass));
 
if (this.horizontalAlignment != null) {
if (this.horizontalAlignment != LightUIElement.HALIGN_LEFT) {
result.put(HORIZONTAL_ALIGNMENT, this.horizontalAlignment);
}
return result;
271,7 → 277,9
 
this.editable = JSONConverter.getParameterFromJSON(json, EDITABLE, Boolean.class, Boolean.FALSE);
this.horizontalAlignment = JSONConverter.getParameterFromJSON(json, HORIZONTAL_ALIGNMENT, Integer.class);
 
if (this.horizontalAlignment == null) {
this.horizontalAlignment = LightUIElement.HALIGN_LEFT;
}
final JSONObject jsonDefaultValue = JSONConverter.getParameterFromJSON(json, DEFAULT_VALUE, JSONObject.class);
// TODO: implement default value
 
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIComboBoxElement.java
16,9 → 16,14
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
 
import net.minidev.json.JSONObject;
 
public class LightUIComboBoxElement implements Transferable {
public class LightUIComboBoxElement implements Transferable, Externalizable {
/**
* ID of row, must be unique for a LightUIComboBox. It's represent the SQLRow ID when the
* LightUICombo is attach to a field in database
29,6 → 34,10
private String value2 = null;
private String icon = null;
 
public LightUIComboBoxElement() {
// Serialization
}
 
public LightUIComboBoxElement(final JSONObject json) {
this.fromJSON(json);
}
108,9 → 117,38
 
@Override
public void fromJSON(final JSONObject json) {
this.id = (Integer) JSONConverter.getParameterFromJSON(json, "id", Integer.class);
this.value1 = (String) JSONConverter.getParameterFromJSON(json, "value1", String.class);
this.value2 = (String) JSONConverter.getParameterFromJSON(json, "value2", String.class);
this.icon = (String) JSONConverter.getParameterFromJSON(json, "icon", String.class);
this.id = JSONConverter.getParameterFromJSON(json, "id", Integer.class);
this.value1 = JSONConverter.getParameterFromJSON(json, "value1", String.class);
this.value2 = JSONConverter.getParameterFromJSON(json, "value2", String.class);
this.icon = JSONConverter.getParameterFromJSON(json, "icon", String.class);
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO : value1,value2 et icon -> "" par défaut
if (value1 == null)
value1 = "";
if (value2 == null)
value2 = "";
if (icon == null)
icon = "";
out.writeInt(id);
out.writeUTF(value1);
out.writeUTF(value2);
out.writeUTF(icon);
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.value1 = in.readUTF();
this.value2 = in.readUTF();
this.icon = in.readUTF();
 
}
 
@Override
public String toString() {
return id + ":" + value1 + ":" + value2;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIText.java
32,14 → 32,4
 
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIText(json);
}
};
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFileUpload.java
22,8 → 22,7
 
private String sendFileUrl;
 
public LightUIFileUpload(final JSONObject json) {
super(json);
public LightUIFileUpload() {
}
 
public LightUIFileUpload(final LightUIFileUpload file) {
38,16 → 37,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUIFileUpload(json);
}
};
}
 
@Override
protected void copy(LightUIElement element) {
super.copy(element);
if (!(element instanceof LightUIFileUpload)) {
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUserControlContainer.java
16,6 → 16,11
import net.minidev.json.JSONObject;
 
public abstract class LightUserControlContainer extends LightUIContainer {
 
public LightUserControlContainer() {
// Serialization
}
 
public LightUserControlContainer(final String id) {
super(id);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITable.java
18,6 → 18,10
 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.List;
 
29,7 → 33,7
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
 
public class LightUITable extends LightUserControlContainer {
public class LightUITable extends LightUserControlContainer implements Externalizable {
 
public static final int DEFAULT_LINE_HEIGHT = 40;
 
52,6 → 56,10
 
private int lineHeight = DEFAULT_LINE_HEIGHT;
 
public LightUITable() {
// Serialization
}
 
// Init from json constructor
public LightUITable(final JSONObject json) {
super(json);
186,6 → 194,10
return this.getTableSpec().getContent().setRow(index, row);
}
 
public final void insertRow(final int index, final Row row) {
this.getTableSpec().getContent().insertRow(index, row);
}
 
public final boolean addRow(final Row row) {
return this.getTableSpec().getContent().addRow(row);
}
224,7 → 236,7
}
 
public final void clearSelection(final boolean fire) {
this.getTableSpec().getSelection().getIds().clear();
this.getTableSpec().getSelection().clear();
if (fire) {
this.fireSelectionChange();
}
491,23 → 503,13
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
@Override
public LightUIElement convert(final JSONObject json) {
return new LightUITable(json);
}
};
}
 
@Override
public void _setValueFromContext(final Object value) {
if (value != null) {
final JSONArray jsonContext = (JSONArray) JSONConverter.getObjectFromJSON(value, JSONArray.class);
final JSONArray jsonContext = JSONConverter.getObjectFromJSON(value, JSONArray.class);
final ColumnsSpec columnsSpec = this.getTableSpec().getColumns();
final int columnsCount = columnsSpec.getColumnCount();
 
final List<Integer> editorsIndex = new ArrayList<Integer>();
final List<Integer> editorsIndex = new ArrayList<>();
 
for (int i = 0; i < columnsCount; i++) {
final ColumnSpec columnSpec = columnsSpec.getColumn(i);
609,6 → 611,29
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
 
out.writeBoolean(dynamicLoad);
out.writeBoolean(allowSelection);
out.writeBoolean(allowMultiSelection);
out.writeBoolean(autoSelectFirstLine);
tableSpec.writeExternal(out);
 
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.dynamicLoad = in.readBoolean();
this.allowSelection = in.readBoolean();
this.allowMultiSelection = in.readBoolean();
this.autoSelectFirstLine = in.readBoolean();
tableSpec = new TableSpec();
tableSpec.readExternal(in);
}
 
@Override
public void destroy() {
super.destroy();
this.selectionListeners.clear();
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUILine.java
16,9 → 16,14
import org.openconcerto.utils.io.JSONConverter;
import org.openconcerto.utils.io.Transferable;
 
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
 
import net.minidev.json.JSONObject;
 
public class LightUILine extends LightUIContainer implements Transferable {
public class LightUILine extends LightUIContainer implements Transferable, Externalizable {
private static final long serialVersionUID = 4132718509484530435L;
 
public static final int ALIGN_GRID = 0;
27,8 → 32,8
 
private int gridAlignment = ALIGN_GRID;
 
private Integer elementPadding;
private Integer elementMargin;
private int elementPadding = 0;
private int elementMargin = 0;
 
public LightUILine() {
// Id will be set when this line will be added into a panel, or set manually.
108,10 → 113,10
public JSONObject toJSON() {
final JSONObject result = super.toJSON();
result.put("class", "LightUILine");
if (this.elementPadding != null) {
if (this.elementPadding != 0) {
result.put("element-padding", this.elementPadding);
}
if (this.elementMargin != null) {
if (this.elementMargin != 0) {
result.put("element-margin", this.elementMargin);
}
if (this.gridAlignment != ALIGN_GRID) {
123,8 → 128,32
@Override
public void fromJSON(final JSONObject json) {
super.fromJSON(json);
this.elementPadding = JSONConverter.getParameterFromJSON(json, "element-padding", Integer.class);
this.elementMargin = JSONConverter.getParameterFromJSON(json, "element-margin", Integer.class);
this.elementPadding = JSONConverter.getParameterFromJSON(json, "element-padding", Integer.class, 0);
this.elementMargin = JSONConverter.getParameterFromJSON(json, "element-margin", Integer.class, 0);
this.gridAlignment = JSONConverter.getParameterFromJSON(json, "grid-alignment", Integer.class, ALIGN_GRID);
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeInt(this.elementMargin);
out.writeInt(this.elementPadding);
out.writeByte(this.gridAlignment);
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
this.elementMargin = in.readInt();
this.elementPadding = in.readInt();
this.gridAlignment = in.readByte();
}
 
@Override
public void addChild(LightUIElement child) {
if (child instanceof LightUILine) {
throw new IllegalArgumentException("child is a LightUILine");
}
super.addChild(child);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TreeItem.java
18,6 → 18,8
import java.util.ArrayList;
import java.util.List;
 
import net.minidev.json.JSONObject;
 
public class TreeItem implements Serializable {
/**
*
34,6 → 36,10
public TreeItem() {
}
 
public TreeItem(JSONObject o) {
// TODO json..
}
 
public TreeItem(String id, String label) {
this.id = id;
this.label = label;
/trunk/OpenConcerto/src/org/openconcerto/ui/TimeTextField.java
136,8 → 136,10
final int stop = text.length();
for (int i = 0; i < stop; i++) {
int position = i + offset;
if (position < te.length) {
te[position] = text.charAt(i);
}
}
for (int i = 0; i < stop; i++) {
int position = i + offset;
final char c = text.charAt(i);
156,6 → 158,7
});
// Move cusor to not be on ':'
this.setNavigationFilter(new NavigationFilter() {
 
@Override
public int getNextVisualPositionFrom(JTextComponent text, int pos, Bias bias, int direction, Bias[] biasRet) throws BadLocationException {
if (pos == 1 && direction == SwingConstants.EAST) {
/trunk/OpenConcerto/src/org/openconcerto/ui/group/Group.java
41,6 → 41,8
private int order;
private final List<Tuple2<Item, Integer>> list;
 
private String tabId;
 
public Group(final String id) {
this(id, LayoutHints.DEFAULT_GROUP_HINTS);
}
296,4 → 298,12
}
return true;
}
 
public void setTabId(String tabId) {
this.tabId = tabId;
}
 
public String getTabId() {
return this.tabId;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/TextAreaTableCellEditor.java
14,8 → 14,8
package org.openconcerto.ui;
 
import org.openconcerto.utils.text.DocumentFilterList;
import org.openconcerto.utils.text.DocumentFilterList.FilterType;
import org.openconcerto.utils.text.LimitedSizeDocumentFilter;
import org.openconcerto.utils.text.DocumentFilterList.FilterType;
 
import java.awt.Color;
import java.awt.Component;
177,7 → 177,9
Rectangle r = null;
try {
r = textArea.modelToView(s.length());
} catch (BadLocationException e) {
} catch (BadLocationException | IllegalArgumentException e2) {
// java.lang.IllegalArgumentException: TextHitInfo is out of range
// from java.awt.font.TextLayout.checkTextHit(Unknown Source)
return -1;
}
int h = 0;
186,7 → 188,6
final int newHeight = r.y + r.height + 2;
h = Math.max(textArea.getMinimumSize().height, newHeight);
}
// System.out.println("TextAreaTableCellEditor.getHeightFor() h:" + h);
return h;
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/state/JTableStateManager.java
18,6 → 18,7
import org.openconcerto.ui.table.XTableColumnModel;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.TableSorter;
import org.openconcerto.utils.TableSorter.Directive;
 
import java.io.File;
import java.io.IOException;
24,6 → 25,7
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
 
import javax.swing.JTable;
import javax.swing.event.AncestorEvent;
31,9 → 33,11
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
54,6 → 58,9
public class JTableStateManager extends ListenerXMLStateManager<JTable, AncestorListener> {
 
private static final String VERSION = "20100810";
private static final String IDENTIFIER_ATTR = "identifier";
private static final String MODEL_INDEX_ATTR = "modelIndex";
private static final String SORT_ATTR = "sort";
 
public JTableStateManager(JTable table) {
this(table, null);
72,9 → 79,11
return new AncestorListener() {
 
public void ancestorAdded(AncestorEvent event) {
// nothing
}
 
public void ancestorMoved(AncestorEvent event) {
// nothing
}
 
public void ancestorRemoved(AncestorEvent event) {
113,9 → 122,9
doc.appendChild(elem);
 
final TableColumnModel model = this.getSrc().getColumnModel();
final XTableColumnModel visibilityModel = model instanceof XTableColumnModel ? (XTableColumnModel) model : null;
final TableModel tModel = this.getSrc().getModel();
if (model instanceof XTableColumnModel) {
final XTableColumnModel visibilityModel = (XTableColumnModel) model;
if (visibilityModel != null) {
for (final TableColumn col : visibilityModel.getColumns(false)) {
writeCol(elem, col, tModel).setAttribute("visible", String.valueOf(visibilityModel.isColumnVisible(col)));
}
127,10 → 136,31
}
}
 
if (tModel instanceof TableSorter) {
TableSorter sorter = (TableSorter) tModel;
final Element sortingColsElem = doc.createElement("sortingColumns");
elem.appendChild(sortingColsElem);
for (final Directive d : sorter.getSortingColumns()) {
final Element colElem = doc.createElement("sortCol");
sortingColsElem.appendChild(colElem);
final TableColumn col;
if (visibilityModel != null) {
col = visibilityModel.getColumnByModelIndex(d.getColumn());
} else {
col = model.getColumn(getSrc().convertColumnIndexToView(d.getColumn()));
}
colElem.setAttribute(IDENTIFIER_ATTR, String.valueOf(col.getIdentifier()));
final int status = d.getDirection();
setSortAttribute(colElem, status);
}
}
 
// Use a Transformer for output
final TransformerFactory tFactory = TransformerFactory.newInstance();
try {
tFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
final Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(elem), new StreamResult(out));
} catch (TransformerException e) {
throw new IOException("Couldn't output " + doc, e);
146,19 → 176,33
res.setAttribute("min", String.valueOf(min));
res.setAttribute("max", String.valueOf(max));
res.setAttribute("width", String.valueOf(width));
res.setAttribute("identifier", String.valueOf(col.getIdentifier()));
res.setAttribute("modelIndex", String.valueOf(col.getModelIndex()));
if (tModel instanceof TableSorter) {
TableSorter sorter = (TableSorter) tModel;
int status = sorter.getSortingStatus(col.getModelIndex());
res.setAttribute(IDENTIFIER_ATTR, String.valueOf(col.getIdentifier()));
res.setAttribute(MODEL_INDEX_ATTR, String.valueOf(col.getModelIndex()));
return res;
}
 
protected final void setSortAttribute(final Element res, final int status) {
if (status == TableSorter.ASCENDING) {
res.setAttribute("sort", "ascending");
res.setAttribute(SORT_ATTR, "ascending");
} else if (status == TableSorter.DESCENDING) {
res.setAttribute("sort", "descending");
res.setAttribute(SORT_ATTR, "descending");
}
}
return res;
 
protected final int getSortAttribute(final NamedNodeMap attrs) {
final Node sortNode = attrs.getNamedItem(SORT_ATTR);
if (sortNode != null) {
final String sort = sortNode.getNodeValue();
if (sort.equals("ascending")) {
return TableSorter.ASCENDING;
} else if (sort.equals("descending")) {
return TableSorter.DESCENDING;
} else {
Log.get().log(Level.INFO, "ignore unknown sort value : {0}", sort);
}
}
return TableSorter.NOT_SORTED;
}
 
/**
* Met les colonnes comme spécifier dans <code>file</code>. Ne fait rien si <code>file</code>
195,11 → 239,11
}
}
final TableModel tModel = this.getSrc().getModel();
final List<TableColumn> invisibleCols = new ArrayList<TableColumn>();
final List<TableColumn> invisibleCols = new ArrayList<>();
for (int i = 0; i < colsCount; i++) {
final NamedNodeMap attrs = listOfCol.item(i).getAttributes();
// index
final int modelIndex = Integer.parseInt(attrs.getNamedItem("modelIndex").getNodeValue());
final int modelIndex = Integer.parseInt(attrs.getNamedItem(MODEL_INDEX_ATTR).getNodeValue());
// move from the current index to the final view index
model.moveColumn(this.getSrc().convertColumnIndexToView(modelIndex), i);
 
234,26 → 278,37
if (visible != null && !Boolean.parseBoolean(visible.getNodeValue()))
invisibleCols.add(modelCol);
 
// Better not to restore sorting at all, than to restore wrong sorting. So remove
// the code that was here since it didn't restore the order of the sorting columns
// (e.g. first sort by country, then by age).
}
 
// Sorting
final NodeList listOfSortCol = doc.getElementsByTagName("sortCol");
final int sortColCount = listOfSortCol.getLength();
if (tModel instanceof TableSorter && sortColCount > 0) {
final List<Directive> sortingCols = new ArrayList<>();
for (int i = 0; i < sortColCount; i++) {
final NamedNodeMap attrs = listOfSortCol.item(i).getAttributes();
 
if (tModel instanceof TableSorter) {
final TableSorter sorter = (TableSorter) tModel;
final Node sortNode = attrs.getNamedItem("sort");
if (sortNode != null) {
String sort = sortNode.getNodeValue();
if (sort != null) {
if (sort.equals("ascending")) {
sorter.setSortingStatus(modelIndex, TableSorter.ASCENDING);
} else if (sort.equals("descending")) {
sorter.setSortingStatus(modelIndex, TableSorter.DESCENDING);
} else {
sorter.setSortingStatus(modelIndex, TableSorter.NOT_SORTED);
final String colID = attrs.getNamedItem(IDENTIFIER_ATTR).getNodeValue();
final int colIndex;
try {
colIndex = model.getColumnIndex(colID);
} catch (Exception e) {
Log.get().log(Level.INFO, "ignore unknown identifier : " + colID, e);
continue;
}
final int modelIndex = model.getColumn(colIndex).getModelIndex();
final int direction = getSortAttribute(attrs);
if (direction == TableSorter.NOT_SORTED) {
Log.get().info("ignore sort value for column " + colID);
continue;
}
sortingCols.add(new Directive(modelIndex, direction));
}
((TableSorter) tModel).setSortingColumns(sortingCols);
}
 
}
if (visibilityModel != null) {
for (final TableColumn toRm : invisibleCols) {
visibilityModel.setColumnVisible(toRm, false);
271,8 → 326,8
final int colsCount = listOfCol.getLength();
for (int i = 0; i < colsCount; i++) {
final NamedNodeMap attrs = listOfCol.item(i).getAttributes();
final int modelIndex = Integer.parseInt(attrs.getNamedItem("modelIndex").getNodeValue());
final String xmlID = attrs.getNamedItem("identifier").getNodeValue();
final int modelIndex = Integer.parseInt(attrs.getNamedItem(MODEL_INDEX_ATTR).getNodeValue());
final String xmlID = attrs.getNamedItem(IDENTIFIER_ATTR).getNodeValue();
final String uiID = String.valueOf(uiCols.get(modelIndex).getIdentifier());
if (!uiID.equals(xmlID))
return false;
/trunk/OpenConcerto/src/org/openconcerto/ui/table/IconTableCellRenderer.java
21,8 → 21,8
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
 
import javax.swing.AbstractCellEditor;
import javax.swing.JTable;
33,7 → 33,7
public class IconTableCellRenderer extends AbstractCellEditor implements TableCellEditor, TableCellRenderer, ItemListener {
 
private int va;
private final List<JImage> images = new Vector<JImage>();
private final List<JImage> images = new ArrayList<>();
IconCellRenderer renderer;
 
/**
42,20 → 42,17
public IconTableCellRenderer(List<URL> icons) {
for (int i = 0; i < icons.size(); i++) {
URL filenameUrl = icons.get(i);
// System.out.println("Chargement de l'image " + filename);
 
JImage img = new JImage(filenameUrl);
img.setCenterImage(true);
img.check();
img.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
System.out.println(e);
IconTableCellRenderer.this.va++;
if (IconTableCellRenderer.this.va >= IconTableCellRenderer.this.images.size()) {
IconTableCellRenderer.this.va = 0;
}
 
stopCellEditing();
}
});
70,12 → 67,11
value = Integer.valueOf(0);
}
this.va = ((Integer) value).intValue();
final JImage image = this.images.get(this.va);
return image;
return this.images.get(this.va);
}
 
public Object getCellEditorValue() {
return new Integer(this.va);
return Integer.valueOf(this.va);
}
 
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
83,13 → 79,13
}
 
public void itemStateChanged(ItemEvent e) {
System.out.println("IconTableCellRenderer.itemStateChanged()");
// nothing
}
 
}
 
class IconCellRenderer extends DefaultTableCellRenderer {
List<JImage> images;
private List<JImage> images;
 
public IconCellRenderer(List<JImage> images) {
super();
101,6 → 97,10
}
 
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) {
// Bug remonté sur Linux
value = Integer.valueOf(0);
}
int val = ((Integer) value).intValue();
final JImage image = this.images.get(val);
this.setIcon(image.getImageIcon());
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ReOrder.java
13,11 → 13,13
package org.openconcerto.sql.utils;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.FieldRef;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLSystem;
24,6 → 26,9
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple2.List2;
import org.openconcerto.utils.convertor.NumberConvertor;
 
import java.math.BigDecimal;
30,9 → 35,13
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
 
import net.jcip.annotations.GuardedBy;
 
/**
* Reorder some or all rows of a table.
*
40,6 → 49,161
*/
public abstract class ReOrder {
 
@GuardedBy("this")
private static boolean AUTO_FIX_NULLS = false;
 
public static synchronized void setAutoFixNulls(boolean b) {
AUTO_FIX_NULLS = b;
}
 
public static synchronized boolean isAutoFixNulls() {
return AUTO_FIX_NULLS;
}
 
public static BigDecimal makeRoom(final SQLTable t, final BigDecimal roomNeeded, final boolean after, final BigDecimal destOrder) throws SQLException {
return makeRoom(t, roomNeeded, after, destOrder, 100);
}
 
/**
* Make sure that there's no rows with order in the passed range. This method accomplishes this
* by re-ordering an increasing number of rows. This method only changes orders greater than or
* equal to <code>destOrder</code> and the first row re-ordered (<code>destOrder</code> if
* <code>!after</code> the next one otherwise) always has <code>destOrder + roomNeeded</code> as
* order :
*
* <pre>
* "row foo" 1.0
* "row bar" 2.0
* "row baz" 3.0
* "row qux" 4.0
* If <code>roomNeeded</code> is 2 after order 2.0, then the new values will be :
* "row foo" 1.0
* "row bar" 2.0
* "row baz" 4.0
* "row qux" 5.0
* If on the other hand, one wants the room before 2.0, then :
* "row foo" 1.0
* "row bar" 4.0
* "row baz" 5.0
* "row qux" 6.0
* </pre>
*
* @param t the table.
* @param roomNeeded the size of the requested free range, e.g 10.
* @param after <code>true</code> if the free range should begin after <code>destOrder</code>,
* <code>false</code> if it should end before <code>destOrder</code>.
* @param destOrder the start or end of the range.
* @param initialCount the initial size of the range to re-order if there's no room.
* @return the smallest possibly used order <code>>=</code> destOrder.
* @throws SQLException if an error occurs.
*/
public static BigDecimal makeRoom(final SQLTable t, final BigDecimal roomNeeded, final boolean after, final BigDecimal destOrder, final int initialCount) throws SQLException {
if (roomNeeded.signum() <= 0)
throw new IllegalArgumentException("Negative roomNeeded");
if (initialCount < 1)
throw new IllegalArgumentException("Initial count too small");
final BigDecimal newFirst = destOrder.add(roomNeeded);
// reorder to squeeze rows upwards
// since we keep increasing count, we will eventually reorder all rows afterwards
// NOTE since we only go in one direction (from destOrder and upwards), there shouldn't be
// any DB deadlocks
int count = Math.max(initialCount, roomNeeded.intValue() + 1);
final int tableRowCount = t.getRowCount();
boolean reordered = false;
while (!reordered) {
// only push destRow upwards if we want to add before
reordered = ReOrder.create(t, destOrder, !after, count, newFirst).exec();
if (!reordered && count > tableRowCount)
throw new IllegalStateException("Unable to reorder " + count + " rows in " + t);
count *= 10;
}
return after ? destOrder : newFirst;
}
 
/**
* Get a number of free order values after/before the passed row,
* {@link #makeRoom(SQLTable, BigDecimal, boolean, BigDecimal, int) making room} if needed.
*
* @param rowCount the number of order values needed.
* @param after <code>true</code> if the free values should begin after <code>r</code>,
* <code>false</code> if they should end before <code>r</code>.
* @param r the row that is before or after the returned orders.
* @return a list of <code>rowCount</code> free orders and the new order for the passed row
* (only changed if there was not enough free values).
* @throws SQLException if an error occurs.
*/
public static Tuple2<List<BigDecimal>, BigDecimal> getFreeOrderValuesFor(final int rowCount, final boolean after, final SQLRow r) throws SQLException {
return getFreeOrderValuesFor(rowCount, after, r, isAutoFixNulls());
}
 
public static Tuple2<List<BigDecimal>, BigDecimal> getFreeOrderValuesFor(final int rowCount, final boolean after, final SQLRow r, final boolean autoFixNulls) throws SQLException {
if (rowCount == 0)
return Tuple2.<List<BigDecimal>, BigDecimal> create(Collections.<BigDecimal> emptyList(), null);
// both rows are locked FOR UPDATE, so there shouldn't be any row that can get between them
// in this transaction, as the only way to do that is to call fetchThisAndSequentialRow()
List2<SQLRow> seqRows = r.fetchThisAndSequentialRow(after);
if (seqRows == null)
throw new IllegalStateException("Couldn't find " + r);
assert seqRows.get0().equals(r) : "fetchThisAndSequentialRow() failed";
if (seqRows.get0().getOrder() == null) {
if (autoFixNulls)
Log.get().log(Level.WARNING, "Re-order table with null orders : " + r);
else
throw new IllegalStateException("Row with null order : " + r);
if (!ReOrder.create(r.getTable()).exec())
throw new IllegalStateException("Couldn't re-order table with null orders : " + r.getTable());
seqRows = r.fetchThisAndSequentialRow(after);
if (seqRows == null || seqRows.get0().getOrder() == null)
throw new IllegalStateException("Re-order table with null orders failed : " + seqRows);
}
final BigDecimal destOrder = seqRows.get0().getOrder();
if (destOrder.compareTo(ReOrder.MIN_ORDER) < 0)
throw new IllegalStateException(seqRows.get0() + " has invalid order : " + destOrder);
BigDecimal newRowOrder = destOrder;
final SQLRow otherRow = seqRows.get1();
final BigDecimal inc;
BigDecimal newOrder;
if (after && otherRow == null) {
// dernière ligne de la table
inc = ReOrder.DISTANCE;
newOrder = destOrder.add(inc);
} else {
final BigDecimal otherOrder;
if (otherRow != null) {
otherOrder = otherRow.getOrder();
} else {
// première ligne
otherOrder = ReOrder.MIN_ORDER;
}
if (otherOrder.compareTo(ReOrder.MIN_ORDER) < 0)
throw new IllegalStateException(otherRow + " has invalid order : " + otherOrder);
 
// ULP * 10 to give a little breathing room
final BigDecimal minDistance = r.getTable().getOrderULP().scaleByPowerOfTen(1);
final BigDecimal places = BigDecimal.valueOf(rowCount + 1);
// the minimum room to fit rowCount
final BigDecimal roomNeeded = minDistance.multiply(places);
final BigDecimal roomAvailable = otherOrder.subtract(destOrder).abs();
 
if (roomAvailable.compareTo(roomNeeded) < 0) {
newRowOrder = makeRoom(r.getTable(), roomNeeded, after, destOrder);
inc = minDistance;
newOrder = after ? destOrder.add(inc) : destOrder;
} else {
inc = roomAvailable.divide(places, DecimalUtils.HIGH_PRECISION);
newOrder = (after ? destOrder : otherOrder).add(inc);
}
}
assert inc.signum() > 0;
final List<BigDecimal> orders = new ArrayList<>(rowCount);
for (int i = 0; i < rowCount; i++) {
orders.add(DecimalUtils.round(newOrder, r.getTable().getOrderDecimalDigits()));
newOrder = newOrder.add(inc);
}
assert after && newRowOrder.compareTo(orders.get(0)) < 0 || !after && orders.get(rowCount - 1).compareTo(newRowOrder) < 0;
return Tuple2.create(orders, newRowOrder);
}
 
// must be zero so that we can work on negative numbers without breaking the unique constraint
public static final BigDecimal MIN_ORDER = BigDecimal.ZERO;
// preferred distance
123,15 → 287,16
 
// MAYBE return affected IDs
public final boolean exec() throws SQLException {
final UpdateBuilder updateUndef = new UpdateBuilder(this.t).setObject(this.t.getOrderField(), MIN_ORDER);
updateUndef.setWhere(new Where(this.t.getKey(), "=", this.t.getUndefinedID()));
return (Boolean) SQLUtils.executeAtomic(this.t.getBase().getDataSource(), new ConnectionHandlerNoSetup<Object, SQLException>() {
final SQLTable t = this.t;
return SQLUtils.executeAtomic(this.t.getBase().getDataSource(), new ConnectionHandlerNoSetup<Boolean, SQLException>() {
@Override
public Object handle(SQLDataSource ds) throws SQLException, SQLException {
public Boolean handle(SQLDataSource ds) throws SQLException, SQLException {
final Connection conn = ds.getConnection();
final Statement stmt = conn.createStatement();
if (isAll()) {
// reorder all, undef must be at 0
if (isAll() && t.getUndefinedIDNumber() != null) {
final UpdateBuilder updateUndef = new UpdateBuilder(t).setObject(t.getOrderField(), MIN_ORDER);
updateUndef.setWhere(new Where(t.getKey(), "=", t.getUndefinedID()));
stmt.execute(updateUndef.asString());
}
stmt.execute("SELECT " + ReOrder.this.spec.getInc());
138,13 → 303,13
final BigDecimal inc = NumberConvertor.toBigDecimal((Number) SQLDataSource.SCALAR_HANDLER.handle(stmt.getResultSet()));
// needed since the cast in getInc() rounds so if the real increment is 0.006 it
// might get rounded to 0.01 and thus the last rows will overlap non moved rows
if (inc.compareTo(ReOrder.this.t.getOrderULP().scaleByPowerOfTen(1)) < 0)
if (inc.compareTo(t.getOrderULP().scaleByPowerOfTen(1)) < 0)
return false;
for (final String s : getSQL(conn, inc)) {
stmt.execute(s);
}
// MAYBE fire only changed IDs
ReOrder.this.t.fireTableModified(-1, Collections.singletonList(ReOrder.this.t.getOrderField().getName()));
t.fireTableModified(SQLRow.NONEXISTANT_ID, Collections.singletonList(t.getOrderField().getName()));
return true;
}
});
174,7 → 339,7
if (first.compareTo(MIN_ORDER) <= 0) {
this.firstToReorder = MIN_ORDER;
this.firstToReorderInclusive = false;
// make some room before the first non MIN_ORDER row so that another on can came
// make some room before the first non MIN_ORDER row so that another one can came
// before it
this.first = MIN_ORDER.add(DISTANCE).max(newFirst);
// try to keep asked value
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
872,11 → 872,38
*
* @return the key, <code>null</code> for a simple field.
*/
public final SQLKey getKey() {
public final SQLKey getRawKey() {
return this.key;
}
 
/**
* The key for this group.
*
* @return the key, never <code>null</code>.
* @throws IllegalStateException for a simple field.
*/
public final SQLKey getKey() throws IllegalStateException {
if (this.key == null)
throw new IllegalStateException("Not a key : " + this);
return this.key;
}
 
/**
* The foreign link for this group.
*
* @return the foreign link, never <code>null</code>.
* @throws IllegalStateException for a simple field or a primary key.
*/
public final Link getForeignLink() throws IllegalStateException {
if (this.key != null) {
final Link foreignLink = this.key.getForeignLink();
if (foreignLink != null)
return foreignLink;
}
throw new IllegalStateException("Not a foreign key : " + this);
}
 
/**
* The one and only field of this group.
*
* @return the only field of this group, only <code>null</code> if this group is a
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntax.java
710,8 → 710,9
sqlType = type + "(" + size + ")";
} else {
Log.get().warning("Unbounded varchar for " + f.getSQLName());
if (this.getSystem() == SQLSystem.MYSQL)
throw new IllegalStateException("MySQL doesn't support unbounded varchar and might truncate data if reducing size of " + f.getSQLName());
// if (this.getSystem() == SQLSystem.MYSQL)
// throw new IllegalStateException("MySQL doesn't support unbounded varchar and
// might truncate data if reducing size of " + f.getSQLName());
// don't specify size
sqlType = type;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowAccessor.java
402,9 → 402,13
}
 
public final <T> T getObjectAs(String field, Class<T> clazz) {
return this.getObjectAs(field, false, clazz);
}
 
public final <T> T getObjectAs(final String field, final boolean mustBePresent, final Class<T> clazz) {
T res = null;
try {
res = clazz.cast(this.getObject(field));
res = clazz.cast(this.getObject(field, mustBePresent));
} catch (ClassCastException e) {
throw new IllegalArgumentException("Impossible d'accéder au champ " + field + " de la ligne " + this + " en tant que " + clazz.getSimpleName(), e);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/OrderComparator.java
15,6 → 15,7
 
import org.openconcerto.utils.CompareUtils;
 
import java.math.BigDecimal;
import java.util.Comparator;
 
/**
24,11 → 25,14
*/
public class OrderComparator implements Comparator<SQLRowAccessor> {
 
public static final Comparator<BigDecimal> BD_NULLS_FIRST = Comparator.nullsFirst(Comparator.naturalOrder());
public static final Comparator<BigDecimal> BD_NULLS_LAST = Comparator.nullsLast(Comparator.naturalOrder());
 
/**
* Order rows by {@link SQLTable#getOrderField()}.
*/
public static final OrderComparator INSTANCE = new OrderComparator(false);
private static final OrderComparator INSTANCE_FALLBACK_TO_PK = new OrderComparator(true);
public static final OrderComparator INSTANCE = new OrderComparator(false, BD_NULLS_LAST);
private static final OrderComparator INSTANCE_FALLBACK_TO_PK = new OrderComparator(true, BD_NULLS_LAST);
 
/**
* Order rows by {@link SQLTable#getOrderField()}, or if the table is not
41,11 → 45,12
}
 
private final boolean fallbackToPK;
private final Comparator<BigDecimal> bdComparator;
 
// singleton
private OrderComparator(boolean fallbackToPK) {
public OrderComparator(final boolean fallbackToPK, final Comparator<BigDecimal> bdComparator) {
super();
this.fallbackToPK = fallbackToPK;
this.bdComparator = bdComparator;
}
 
@Override
57,8 → 62,11
final SQLTable t = r1.getTable();
if (!t.equals(r2.getTable()))
throw new IllegalArgumentException(r1 + " and " + r2 + " are not of the same table");
if (t.isOrdered()) {
return r1.getOrder().compareTo(r2.getOrder());
final SQLField orderField = t.getTable().getOrderField();
if (orderField != null) {
final BigDecimal order1 = r1.getObjectAs(orderField.getName(), true, BigDecimal.class);
final BigDecimal order2 = r2.getObjectAs(orderField.getName(), true, BigDecimal.class);
return this.bdComparator.compare(order1, order2);
} else if (this.fallbackToPK) {
if (!t.isRowable())
throw new IllegalArgumentException(t + " neither ordered nor rowable");
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLField.java
391,7 → 391,7
* @see #getFieldGroup()
*/
public boolean isForeignKey() {
final FieldGroup fieldGroup = getFieldGroup();
final FieldGroup fieldGroup = getContainingFieldGroup();
return fieldGroup.getKeyType() == Type.FOREIGN_KEY && fieldGroup.getSingleField() != null;
}
 
401,10 → 401,23
* @return the group of this field.
* @see SQLTable#getFieldGroups()
*/
public FieldGroup getFieldGroup() {
public FieldGroup getContainingFieldGroup() {
return this.getTable().getFieldGroups().get(this.getName());
}
 
/**
* The group consisting of this single field.
*
* @return the group consisting of this single field.
* @throws IllegalStateException if this field is part of a multi-field group.
*/
public FieldGroup getFieldGroup() throws IllegalStateException {
final FieldGroup fg = this.getTable().getFieldGroups().get(this.getName());
if (fg.getSingleField() == null)
throw new IllegalStateException(this + " is part of a group with others : " + fg);
return fg;
}
 
public final SQLTable getForeignTable() {
return this.getDBSystemRoot().getGraph().getForeignTable(this);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java
23,12 → 23,10
import org.openconcerto.sql.model.graph.Link;
import org.openconcerto.sql.model.graph.Link.Direction;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.utils.ReOrder;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.Tuple2.List2;
 
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
298,10 → 296,26
this.fetchValues(true);
}
 
/**
* Fetch up-to-date values from the DB.
*
* @param useCache <code>true</code> to use the {@link SQLDataSource#isCacheEnabled() cache}.
* @return this.
*/
public final SQLRow fetchValues(final boolean useCache) {
return this.fetchValues(useCache, useCache);
}
 
/**
* Return a new instance with up-to-date values.
*
* @param useCache <code>true</code> to use the {@link SQLDataSource#isCacheEnabled() cache}.
* @return a new instance.
*/
public final SQLRow fetchNew(final boolean useCache) {
return new SQLRow(this.getTable(), this.getIDNumber()).fetchValues(useCache);
}
 
@SuppressWarnings("unchecked")
SQLRow fetchValues(final boolean readCache, final boolean writeCache) {
final IResultSetHandler handler = new IResultSetHandler(SQLDataSource.MAP_HANDLER, readCache, writeCache) {
397,14 → 411,44
return this.getValues().get(field);
}
 
public final SQLRow getRow(boolean after) {
/**
* Fetch from the DB this row and the next/previous one. ATTN the rows are locked
* {@link LockStrength#UPDATE for update}, but if this method is not called from within a
* transaction, they will immediately be obsolete.
*
* @param after <code>true</code> to return the next row, <code>false</code> to return the
* previous.
* @return {@link List2#get0() this row} and the next/previous one with only
* {@link SQLTable#getOrderField()} and {@link SQLTable#getArchiveField()} fetched,
* <code>null</code> if this row doesn't exist, the {@link List2#get1() next/previous
* row} is <code>null</code> if this is the last/first row of the table or has
* <code>null</code> order.
* @throws IllegalStateException if this is the {@link #isUndefined() undefined} row.
*/
public final List2<SQLRow> fetchThisAndSequentialRow(boolean after) throws IllegalStateException {
if (this.isUndefined())
throw new IllegalStateException("Cannot order against the undefined");
final SQLTable t = this.getTable();
final BigDecimal destOrder = this.getOrder();
final int diff = (!after) ? -1 : 1;
 
// this is one statement (subquery included) and thus atomic : the inner FOR UPDATE ensures
// that the ORDER doesn't change by the time the outer query is executed
// SELECT * FROM "test"."BATIMENT"
// WHERE "ORDRE" >= (SELECT "ORDRE" FROM "test"."BATIMENT" WHERE "ID" = 3 FOR UPDATE)
// ORDER BY "ORDRE"
// LIMIT 2
// FOR UPDATE;
 
final SQLSelect selOrder = new SQLSelect();
// OK to order against an archived
selOrder.setArchivedPolicy(SQLSelect.BOTH);
selOrder.addSelect(t.getOrderField());
selOrder.setWhere(this.getWhere());
selOrder.setLockStrength(LockStrength.UPDATE);
 
final SQLSelect sel = new SQLSelect();
// undefined must not move
sel.setExcludeUndefined(true);
// don't ignore undefined or the caller might want to use its order
sel.setExcludeUndefined(false);
// unique index prend aussi en compte les archivés
sel.setArchivedPolicy(SQLSelect.BOTH);
sel.addSelect(t.getKey());
411,50 → 455,22
sel.addSelect(t.getOrderField());
if (t.isArchivable())
sel.addSelect(t.getArchiveField());
sel.setWhere(new Where(t.getOrderField(), diff < 0 ? "<" : ">", destOrder));
final Where orderWhere = Where.createRaw(t.getOrderField().getFieldRef() + (diff < 0 ? "<=" : ">=") + "(" + selOrder + ")", t.getOrderField());
// this.getWhere() needed when ORDER is null
sel.setWhere(orderWhere.or(this.getWhere()));
sel.addFieldOrder(t.getOrderField(), diff < 0 ? Order.desc() : Order.asc());
sel.setLimit(1);
sel.setLimit(2);
sel.setLockStrength(LockStrength.UPDATE);
 
final SQLDataSource ds = t.getBase().getDataSource();
@SuppressWarnings("unchecked")
final Map<String, Object> otherMap = ds.execute1(sel.asString());
if (otherMap != null) {
return new SQLRow(t, otherMap);
} else {
final List<SQLRow> rows = SQLRowListRSH.execute(sel);
assert rows.size() <= 2;
if (rows.isEmpty()) {
return null;
}
}
 
/**
* The free order just after or before this row.
*
* @param after whether to look before or after this row.
* @return a free order, or <code>null</code> if there's no room left.
*/
public final BigDecimal getOrder(boolean after) {
final BigDecimal destOrder = this.getOrder();
final SQLRow otherRow = this.getRow(after);
final BigDecimal otherOrder;
if (otherRow != null) {
otherOrder = otherRow.getOrder();
} else if (after) {
// dernière ligne de la table
otherOrder = destOrder.add(ReOrder.DISTANCE);
} else {
// première ligne
otherOrder = ReOrder.MIN_ORDER;
assert rows.get(0).equals(this);
return new List2<>(rows.get(0), rows.size() == 1 ? null : rows.get(1));
}
 
final int decDigits = this.getTable().getOrderDecimalDigits();
final BigDecimal least = BigDecimal.ONE.scaleByPowerOfTen(-decDigits);
final BigDecimal distance = destOrder.subtract(otherOrder).abs();
if (distance.compareTo(least) <= 0)
return null;
else {
final BigDecimal mean = destOrder.add(otherOrder).divide(BigDecimal.valueOf(2));
return DecimalUtils.round(mean, decDigits);
}
}
 
@Override
public SQLRow getForeign(String fieldName) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxPG.java
107,7 → 107,9
this.typeNames.addAll(java.sql.Date.class, "date");
this.typeNames.addAll(java.sql.Time.class, "time", "time without time zone");
this.typeNames.addAll(Blob.class, "bytea");
this.typeNames.addAll(Clob.class, "varchar", "char", "character varying", "character", "text");
// even though PG treats all Character Types equally, unbounded varchar is not standard, so
// prefer "text" which is supported by all systems
this.typeNames.addAll(Clob.class, "text", "varchar", "char", "character varying", "character");
this.typeNames.addAll(String.class, "varchar", "char", "character varying", "character", "text");
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValues.java
1218,25 → 1218,21
* @return this.
*/
public SQLRowValues setOrder(SQLRow r, boolean after) {
return this.setOrder(r, after, ReOrder.DISTANCE.movePointRight(2).intValue(), 0);
setOrder(Collections.singletonList(this), r, after);
return this;
}
 
private SQLRowValues setOrder(SQLRow r, boolean after, int nbToReOrder, int nbReOrdered) {
final BigDecimal freeOrder = r.getOrder(after);
final String orderName = this.getTable().getOrderField().getName();
if (freeOrder != null)
return this.put(orderName, freeOrder);
else if (nbReOrdered > r.getTable().getRowCount()) {
throw new IllegalStateException("cannot reorder " + r.getTable().getSQLName());
} else {
// make room
public static void setOrder(final List<SQLRowValues> values, final SQLRow r, boolean after) {
final int valuesCount = values.size();
final List<BigDecimal> orders;
try {
ReOrder.create(this.getTable(), r.getOrder().intValue() - (nbToReOrder / 2), nbToReOrder).exec();
orders = ReOrder.getFreeOrderValuesFor(valuesCount, after, r).get0();
} catch (SQLException e) {
throw ExceptionUtils.createExn(IllegalStateException.class, "reorder failed for " + this.getTable() + " at " + r.getOrder(), e);
throw ExceptionUtils.createExn(IllegalStateException.class, "reorder failed for " + r.getTable() + " at " + r.getOrder(), e);
}
r.fetchValues();
return this.setOrder(r, after, nbToReOrder * 10, nbToReOrder);
final String orderName = r.getTable().getOrderField().getName();
for (int i = 0; i < valuesCount; i++) {
values.get(i).put(orderName, orders.get(i));
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/users/CompanyAccessSQLElement.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightsManager.java
289,7 → 289,7
};
this.javaRights = new JavaRights();
this.table = t;
this.toUserLink = t.getFieldGroups().get("ID_USER_COMMON").getKey().getForeignLink();
this.toUserLink = t.getField("ID_USER_COMMON").getFieldGroup().getForeignLink();
defaultRegister();
this.userRights = new HashMap<Integer, UserRights>();
this.exec = Executors.newSingleThreadExecutor(new ThreadFactory(this.getClass().getSimpleName() + " executor for " + t.getSQLName(), true).setPriority(Thread.MIN_PRIORITY));
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightSQLElement.java
14,14 → 14,13
package org.openconcerto.sql.users.rights;
 
import static java.util.Arrays.asList;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.ConfSQLElement;
 
import org.openconcerto.sql.element.GlobalMapper;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.utils.i18n.I18nUtils;
 
import java.util.ArrayList;
import java.util.Collections;
28,7 → 27,7
import java.util.List;
import java.util.Set;
 
public class UserRightSQLElement extends ConfSQLElement {
public class UserRightSQLElement extends SQLElement {
public static final String TABLE_NAME = "USER_RIGHT";
 
static public List<SQLCreateTable> getCreateTables(final SQLTable userT) {
56,9 → 55,8
return res;
}
 
public UserRightSQLElement() {
super(TABLE_NAME);
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
public UserRightSQLElement(final DBRoot r) {
super(r.findTable(TABLE_NAME), null, "sql.user-right");
final UserRightGroup group = new UserRightGroup();
GlobalMapper.getInstance().map(UserRightSQLComponent.ID, group);
setDefaultGroup(group);
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/RightSQLElement.java
13,20 → 13,18
package org.openconcerto.sql.users.rights;
 
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.utils.SQLCreateTable;
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.i18n.I18nUtils;
 
import java.util.Arrays;
import java.util.List;
 
public class RightSQLElement extends ConfSQLElement {
public class RightSQLElement extends SQLElement {
 
public static final String TABLE_NAME = "RIGHT";
 
38,9 → 36,8
return res;
}
 
public RightSQLElement() {
super(TABLE_NAME);
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
public RightSQLElement(final DBRoot root) {
super(root.findTable(TABLE_NAME), null, "sql.right");
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java
16,7 → 16,6
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.DBRoot;
47,7 → 46,6
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.i18n.I18nUtils;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.Component;
75,7 → 73,7
import javax.swing.table.DefaultTableCellRenderer;
 
// FIXME Login user unique ?
public class UserCommonSQLElement extends ConfSQLElement {
public class UserCommonSQLElement extends SQLElement {
 
/**
* Set this system property to "true" if this should generate old style passwords.
82,19 → 80,15
*/
public static final String LEGACY_PASSWORDS = "org.openconcerto.sql.legacyPasswords";
 
{
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
}
 
private final boolean familyNameFirst;
 
public UserCommonSQLElement() {
super("USER_COMMON");
this.familyNameFirst = false;
public UserCommonSQLElement(final DBRoot root) {
this(root, false);
}
 
public UserCommonSQLElement(final DBRoot root, final boolean familyNameFirst) {
super(root.findTable("USER_COMMON"));
// allow subclass to keep same code
super(root.findTable("USER_COMMON"), null, "sql.user");
this.familyNameFirst = familyNameFirst;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/search/TextSearchSpec.java
85,6 → 85,18
return res;
}
 
private final String format(final Format fmt, final Object cell) {
try {
return fmt.format(cell);
} catch (Exception e) {
throw new IllegalStateException("Couldn't format " + cell + '(' + getClass(cell) + ") with " + fmt, e);
}
}
 
static private String getClass(Object cell) {
return cell == null ? "<null>" : cell.getClass().getName();
}
 
private final Double getDouble() {
if (!this.parsedFilterD_tried) {
try {
131,7 → 143,7
// which is better achieved with contains)
// PS: the date format is useful for parsing since "> 25/12/2010" means
// "> 25/12/2010 00:00" which is understandable and concise.
if (isContains && containsOrEquals(fmt.format(cell)))
if (isContains && containsOrEquals(format(fmt, cell)))
return true;
// e.g. test if "01/01/2006" is before "25 déc. 2010"
else if (!isContains && test(getParsed(fmt), cell))
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ListSQLLine.java
275,8 → 275,8
}
if (toRemove != null)
toRemove.remove(lastField.getName());
// attach updated values
if (vals != null && vals.getLong(lastField.getName()) == target.getIDNumber().longValue())
// attach updated values, foreign ID is always present but can be null
if (vals != null && target.getIDNumber().equals(vals.getForeignIDNumberValue(lastField.getName()).getValue()))
vals.deepCopy().put(lastField.getName(), target);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/MoveQueue.java
18,17 → 18,19
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelect.LockStrength;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.ReOrder;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.NumberUtils;
import org.openconcerto.utils.SleepingQueue;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
131,20 → 133,13
// if only some rows are moved, update one by one (avoids refreshing the whole list)
// (getRowCount() is not thread-safe, so use getTotalRowCount())
if (rowCount < 5 && rowCount < (this.tableModel.getTotalRowCount() / 3)) {
final List<?> l;
if (after) {
// If we want to put X,Y after A in the list A,B,C
// we need to pass first Y : A,Y,B,C then X :
// A,X,Y,B,C
l = new ArrayList<Object>(srcRows);
Collections.reverse(l);
} else {
l = srcRows;
}
final SQLTable t = getTable();
final String orderName = t.getOrderField().getName();
final SQLRowValues vals = new SQLRowValues(t);
for (final Object src : l) {
vals.setOrder(destRow, after).update(getID(src, t).intValue());
final List<BigDecimal> orders = ReOrder.getFreeOrderValuesFor(rowCount, after, destRow).get0();
for (int i = 0; i < rowCount; i++) {
final Object src = srcRows.get(i);
vals.put(orderName, orders.get(i)).update(getID(src, t).intValue());
}
} else {
// update all rows at once and refresh the whole list
184,75 → 179,64
moveAtOnce(srcRows, srcRows.size(), after, destRow);
}
 
/**
* Move the passed rows just before or just after the destination row if needed.
*
* @param ids rows to order.
* @param after <code>true</code> if the rows should be placed after <code>destRow</code>,
* <code>false</code> otherwise.
* @param destRow <code>srcRows</code> will be placed relative to the order of this row.
* @param checkBefore if <code>true</code> the current DB order will be checked and if it
* matched the passed rows, no change will be made to the DB, <code>false</code> to
* always change the orders in the DB.
* @return if the DB was changed.
* @throws SQLException if an error occurs.
*/
static public boolean moveIDsAtOnce(final List<? extends Number> ids, final boolean after, final SQLRow destRow, final boolean checkBefore) throws SQLException {
final int size = ids.size();
if (checkBefore) {
final SQLTable table = destRow.getTable();
final SQLSelect sel = new SQLSelect(true);
sel.addSelect(table.getKey());
sel.addOrder(table);
sel.setWhere(new Where(table.getKey(), ids));
// needed since we might update them just after in moveAtOnce(), and it's safer to lock
// with the most restrictive mode first.
sel.setLockStrength(LockStrength.UPDATE);
final List<?> dbOrderedIDs = table.getDBSystemRoot().getDataSource().executeCol(sel.asString());
if (dbOrderedIDs.size() != size)
throw new IllegalStateException("Missing rows");
boolean orderOK = true;
for (int i = 0; i < size && orderOK; i++) {
final Number passedID = ids.get(i);
final Number dbID = (Number) dbOrderedIDs.get(i);
orderOK = NumberUtils.areNumericallyEqual(passedID, dbID);
}
if (orderOK)
return false;
}
moveAtOnce(ids, size, after, destRow);
return true;
}
 
static private void moveAtOnce(final List<?> srcRows, final int rowCount, final boolean after, final SQLRow destRow) throws SQLException {
if (rowCount == 0)
return;
final SQLTable t = destRow.getTable();
 
// ULP * 10 to give a little breathing room
final BigDecimal minDistance = t.getOrderULP().scaleByPowerOfTen(1);
assert minDistance.signum() > 0;
final BigDecimal places = BigDecimal.valueOf(rowCount + 1);
// the minimum room so that we can move all rows
final BigDecimal room = minDistance.multiply(places);
final List<BigDecimal> freeOrderValues = ReOrder.getFreeOrderValuesFor(rowCount, after, destRow).get0();
 
final BigDecimal destOrder = destRow.getOrder();
final SQLRow nextRow = destRow.getRow(true);
final BigDecimal inc;
final boolean destRowReordered;
if (nextRow == null) {
// if destRow is the last row, we can choose whatever increment we want
inc = ReOrder.DISTANCE;
// but we need to move destRow if we want to add before it
destRowReordered = false;
} else {
final BigDecimal nextOrder = nextRow.getOrder();
assert nextOrder.compareTo(destOrder) > 0;
final BigDecimal diff = nextOrder.subtract(destOrder);
assert diff.signum() > 0;
if (diff.compareTo(room) < 0) {
// if there's not enough room, reorder to squeeze rows upwards
// since we keep increasing count, we will eventually reorder all rows afterwards
int count = 100;
final int tableRowCount = t.getRowCount();
boolean reordered = false;
while (!reordered) {
// only push destRow upwards if we want to add before
reordered = ReOrder.create(t, destOrder, !after, count, destOrder.add(room)).exec();
if (!reordered && count > tableRowCount)
throw new IllegalStateException("Unable to reorder " + count + " rows in " + t);
count *= 10;
}
inc = minDistance;
destRowReordered = true;
} else {
// truncate
inc = DecimalUtils.round(diff.divide(places, DecimalUtils.HIGH_PRECISION), t.getOrderDecimalDigits(), RoundingMode.DOWN);
destRowReordered = false;
}
}
// i.e. inc > 0
assert inc.compareTo(minDistance) >= 0;
 
BigDecimal newOrder = destOrder;
// by definition if we want to add after, destOrder should remain unchanged
if (after) {
newOrder = newOrder.add(inc);
}
final List<List<String>> newOrdersAndIDs = new ArrayList<List<String>>(rowCount);
int i = 0;
final List<Number> ids = rowCount < 10 ? new ArrayList<Number>(rowCount) : null;
// we go from newOrder and up, so that the passed rows are in ascending order
for (final Object src : srcRows) {
final Number srcID = getID(src, t);
if (ids != null)
ids.add(srcID);
final BigDecimal newOrder = freeOrderValues.get(i++);
newOrdersAndIDs.add(Arrays.asList(srcID.toString(), newOrder.toPlainString()));
newOrder = newOrder.add(inc);
}
// move out before general request as most DB systems haven't got DEFERRABLE constraints
if (!after && !destRowReordered) {
final UpdateBuilder updateDestRow = new UpdateBuilder(t);
updateDestRow.setObject(t.getOrderField(), newOrder);
updateDestRow.setWhere(destRow.getWhere());
t.getDBSystemRoot().getDataSource().execute(updateDestRow.asString());
}
 
final SQLSyntax syntax = SQLSyntax.get(t);
final UpdateBuilder update = new UpdateBuilder(t);
261,6 → 245,12
update.setFromVirtualJoinField(t.getOrderField().getName(), constantTableAlias, "newOrder");
t.getDBSystemRoot().getDataSource().execute(update.asString());
 
t.fireTableModified(SQLRow.NONEXISTANT_ID, Collections.singletonList(t.getOrderField().getName()));
final List<String> fieldsChanged = Collections.singletonList(t.getOrderField().getName());
if (ids == null) {
t.fireTableModified(SQLRow.NONEXISTANT_ID, fieldsChanged);
} else {
for (final Number id : ids)
t.fireTableModified(id.intValue(), fieldsChanged);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/UpdateQueue.java
140,7 → 140,7
this.put(new SetStateRunnable() {
@Override
public void run() {
getModel().getSearchQueue().start();
getModel().startSearchQueue();
}
});
}
244,7 → 244,8
}
// if the modified row isn't in the existing line, it might still affect it
// if it's a referent row insertion
if (!put && lastReferentField != null && r.exists()) {
if (!put && lastReferentField != null && r.exists() && !r.isForeignEmpty(lastReferentField)) {
// no NPE, even without an undefined ID since we tested isForeignEmpty()
final int foreignID = r.getInt(lastReferentField);
for (final SQLRowValues current : line.getRow().followPath(p.minusLast(), CreateMode.CREATE_NONE, false)) {
if (current.getID() == foreignID) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/TextTableCellEditorWithCompletion.java
17,6 → 17,8
import org.openconcerto.ui.TextAreaTableCellEditor;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
 
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
56,7 → 58,17
 
this.textWithCompl.hidePopup();
if (!getValidState().isValid()) {
JOptionPane.showMessageDialog(SwingUtilities.getRoot(this.getTextArea()), getValidState().getValidationText());
final Component root = SwingUtilities.getRoot(TextTableCellEditorWithCompletion.this.getTextArea());
final String validationText = getValidState().getValidationText();
// JOptionPane dans invokeLater pour éviter une boucle avec notre listener sur le focus
// de la table qui stoppe
// l'édition
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(root, validationText);
}
});
return false;
} else {
return super.stopCellEditing();
63,7 → 75,7
}
}
 
@Override
public void setLimitedSize(int nbChar) {
this.textWithCompl.setLimitedSize(nbChar);
}
73,5 → 85,3
}
 
}
 
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTextComboTableCellEditor.java
25,6 → 25,7
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.ui.list.selection.BaseListStateModel;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.convertor.NumberConvertor;
 
import java.awt.Color;
import java.awt.Component;
48,7 → 49,7
 
private Where w;
// Stock Value of Combo to fix problem with undefined
int val = 1;
Integer val = 1;
 
boolean addUndefined;
 
123,18 → 124,19
}
 
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value != null) {
 
this.val = (Integer) value;
this.comboBox.setValue(this.val);
}
 
this.comboBox.grabFocus();
 
this.comboBox.addModelListener("wantedID", new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
SQLTextComboTableCellEditor.this.val = comboBox.getWantedID();
SQLTextComboTableCellEditor.this.val = NumberConvertor.convertExact((Number) evt.getNewValue(), Integer.class);
}
});
 
// Filtre sur une valeur specifique
if (this.fieldWhere != null && table instanceof RowValuesTable) {
RowValuesTable rowVals = (RowValuesTable) table;
160,7 → 162,7
}
 
public int getComboSelectedId() {
return SQLTextComboTableCellEditor.this.comboBox.getSelectedId();
return SQLTextComboTableCellEditor.this.comboBox.getWantedID();
}
 
private SQLField fieldWhere;
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/SQLTableModelLinesSourceOnline.java
49,7 → 49,7
assert SwingUtilities.isEventDispatchThread();
if (this.moveQ == null) {
this.moveQ = new MoveQueue(getModel());
this.moveQ.start();
getModel().startQueue(this.moveQ);
}
return this.moveQ;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableControlPanel.java
99,8 → 99,12
this.buttonInserer = new JButton(TM.tr("insertNewLine"));
this.buttonInserer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
RowValuesTableControlPanel.this.model.addNewRowAt(table.getSelectedRow());
int index = table.getSelectedRow();
if (index < 0 || index > table.getRowCount()) {
index = table.getRowCount();
}
RowValuesTableControlPanel.this.model.addNewRowAt(index);
}
});
this.buttonInserer.setEnabled(false);
c.gridx++;
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ITableModel.java
38,6 → 38,7
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
67,6 → 68,7
* addTableModelListener()) it dies and cannot be used again.
*
* @author Sylvain CUAZ
* @see #start()
*/
public class ITableModel extends AbstractTableModel {
public static enum SleepState {
169,6 → 171,8
private boolean cellsEditable, orderEditable;
private boolean debug;
 
@GuardedBy("this")
private UncaughtExceptionHandler uncaughtExnHandler = null;
private DyingQueueExceptionHandler dyingQueueHandler = null;
 
public ITableModel(SQLTableModelSource src) {
880,7 → 884,14
super.addTableModelListener(l);
}
 
// TODO no longer leak this in our constructor
public synchronized final void setUncaughtExceptionHandler(UncaughtExceptionHandler uncaughtExnHandler) {
this.uncaughtExnHandler = uncaughtExnHandler;
}
 
public synchronized final UncaughtExceptionHandler getUncaughtExceptionHandler() {
return this.uncaughtExnHandler;
}
 
public final void start() {
final RunningState state = this.updateQ.getRunningState();
if (state.compareTo(RunningState.RUNNING) > 0)
888,10 → 899,20
if (state == RunningState.NEW) {
print("starting");
this.getLinesSource().live();
this.updateQ.start();
this.startQueue(this.updateQ);
}
}
 
final void startSearchQueue() {
this.startQueue(this.getSearchQueue());
}
 
final void startQueue(final SleepingQueue q) {
q.start((thr) -> {
thr.setUncaughtExceptionHandler(getUncaughtExceptionHandler());
});
}
 
@Override
public void removeTableModelListener(TableModelListener l) {
assert SwingUtilities.isEventDispatchThread();
928,6 → 949,7
* {@link SleepingQueue#die()}, <code>null</code> to reset default behavior.
*/
public void setDyingQueueExceptionHandler(final DyingQueueExceptionHandler h) {
assert SwingUtilities.isEventDispatchThread();
this.dyingQueueHandler = h;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
370,7 → 370,7
 
public String getLine(final boolean created, final SQLRowValues row, final SQLField userF, final SQLField dateF) {
final Calendar date = dateF == null ? null : row.getDate(dateF.getName());
final SQLRowAccessor user = userF == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName());
final SQLRowAccessor user = userF == null || row.getObject(userF.getName()) == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName());
if (user == null && date == null)
return null;
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/SQLMenuItemHelper.java
18,6 → 18,7
import org.openconcerto.utils.cc.IClosure;
 
import java.awt.event.ActionEvent;
import java.util.Objects;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
149,15 → 150,15
return menuItemAction;
}
 
public static abstract class AbstractSQLMenuItemAction extends AbstractAction {
public static abstract class AbstractSQLMenuItemAction<E extends SQLElement> extends AbstractAction {
 
private final SQLElement elem;
private final E elem;
private JFrame frame;
private boolean cacheFrame;
 
public AbstractSQLMenuItemAction(SQLElement elem, String name) {
public AbstractSQLMenuItemAction(E elem, String name) {
super(name);
this.elem = elem;
this.elem = Objects.requireNonNull(elem, "SQLElement");
this.frame = null;
this.cacheFrame = true;
this.putValue(Action.ACTION_COMMAND_KEY, getClass().getName() + " with " + getElem().getCode());
188,7 → 189,7
 
protected abstract JFrame createFrame();
 
public final SQLElement getElem() {
public final E getElem() {
return this.elem;
}
 
198,7 → 199,7
}
}
 
static abstract class GenericSQLElementAction<F extends JFrame> extends AbstractSQLMenuItemAction {
static abstract class GenericSQLElementAction<F extends JFrame> extends AbstractSQLMenuItemAction<SQLElement> {
 
public GenericSQLElementAction(SQLElement elem, String name) {
super(elem, name);
/trunk/OpenConcerto/src/org/openconcerto/sql/PropsConfiguration.java
14,6 → 14,7
package org.openconcerto.sql;
 
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.element.SQLElementNamesFromXML;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItem;
import org.openconcerto.sql.model.DBSystemRoot;
36,6 → 37,7
import org.openconcerto.utils.NetUtils;
import org.openconcerto.utils.ProductInfo;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.ReflectUtils;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Value;
372,6 → 374,13
return rootIsBase ? this.getRootName() : this.getSystemRootName();
}
 
private final String toClassName(final String rsrcName) {
if (rsrcName.charAt(0) == '/')
return rsrcName.substring(1).replace('/', '.');
else
return this.getResourceWD().getPackage().getName() + '.' + rsrcName.replace('/', '.');
}
 
/**
* Return the correct stream depending on file mode. If file mode is
* {@link FileMode#NORMAL_FILE} it will first check if a file named <code>name</code> exists,
383,7 → 392,7
public final InputStream getStream(final String name) {
final File f = getFile(name);
if (mustUseClassloader(f)) {
return this.getClass().getResourceAsStream(name);
return getResourceWD().getResourceAsStream(name);
} else
try {
return new FileInputStream(f);
392,6 → 401,11
}
}
 
// the "working directory" where relative names are resolved
protected Class<? extends PropsConfiguration> getResourceWD() {
return this.getClass();
}
 
private File getFile(final String name) {
return new File(name.startsWith("/") ? name.substring(1) : name);
}
403,7 → 417,7
public final String getResource(final String name) {
final File f = getFile(name);
if (mustUseClassloader(f)) {
return this.getClass().getResource(name).toExternalForm();
return this.getResourceWD().getResource(name).toExternalForm();
} else {
return f.getAbsolutePath();
}
967,7 → 981,8
return new SQLElementDirectory();
}
 
// items will be passed to #getStream(String)
// Use resource name to be able to use absolute (beginning with /) or relative path (to this
// class)
protected List<String> getMappings() {
return Arrays.asList("mapping", "mapping-" + this.getProperty("customer"));
}
977,7 → 992,7
if (mappings.size() == 0)
throw new IllegalStateException("empty mappings");
 
final SQLFieldTranslator trns = new SQLFieldTranslator(this.getRoot(), null, dir);
final SQLFieldTranslator trns = new SQLFieldTranslator(this.getRoot(), dir);
// perhaps listen to UserProps (as in TM)
return loadTranslations(trns, this.getRoot(), mappings);
}
995,20 → 1010,47
final ListIterator<Locale> listIterator = CollectionUtils.getListIterator(langs, true);
while (listIterator.hasNext()) {
final Locale lang = listIterator.next();
found |= loadTranslations(trns, PropsConfiguration.class.getResourceAsStream(cntrl.toBundleName("mapping", lang) + ".xml"), root);
final SQLElementNamesFromXML elemNames = new SQLElementNamesFromXML(lang);
found |= loadTranslations(trns, PropsConfiguration.class.getResourceAsStream(cntrl.toBundleName("mapping", lang) + ".xml"), root, elemNames);
for (final String m : mappings) {
found |= loadTranslations(trns, this.getStream(cntrl.toBundleName(m, lang) + ".xml"), root);
final String bundleName = cntrl.toBundleName(m, lang);
found |= loadTranslations(trns, this.getStream(bundleName + ".xml"), root, elemNames);
final Class<? extends TranslatorFiller> loadedClass = ReflectUtils.getSubclass(toClassName(bundleName), TranslatorFiller.class);
if (loadedClass != null) {
try {
ReflectUtils.createInstance(loadedClass, this).fill(trns);
} catch (Exception e) {
Log.get().log(Level.WARNING, "Couldn't use " + loadedClass, e);
}
}
}
}
}
return trns;
}
 
private final boolean loadTranslations(final SQLFieldTranslator trns, final InputStream in, final DBRoot root) {
@FunctionalInterface
static public interface TranslatorFiller {
void fill(final SQLFieldTranslator t);
}
 
static public abstract class AbstractTranslatorFiller implements TranslatorFiller {
private final PropsConfiguration conf;
 
public AbstractTranslatorFiller(final PropsConfiguration conf) {
this.conf = conf;
}
 
protected final PropsConfiguration getConf() {
return this.conf;
}
}
 
private final boolean loadTranslations(final SQLFieldTranslator trns, final InputStream in, final DBRoot root, final SQLElementNamesFromXML elemNames) {
final boolean res = in != null;
// do not force to have one mapping for each client and each locale
if (res)
trns.load(root, in);
trns.load(root, in, elemNames);
return res;
}
 
1294,11 → 1336,6
}
 
@Override
public final SQLFieldTranslator getTranslator() {
return this.getDirectory().getTranslator();
}
 
@Override
public final SQLElementDirectory getDirectory() {
return this.directory.get();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_en.xml
1,6 → 1,7
<?xml version="1.0" encoding="UTF-8" ?>
<ROOT>
<TABLE name="USER_COMMON">
<translations>
<element refid="sql.user">
<name base="user" />
<FIELD name="NOM" label="Last Name" />
<FIELD name="PRENOM" label="First name" />
<FIELD name="PASSWORD" label="Password" />
12,17 → 13,21
<FIELD name="MAIL" label="E-Mail" />
<FIELD name="DISABLED" label="Account disabled" />
<FIELD name="TEL" label="Phone" titlelabel="Phone" />
</TABLE>
<TABLE name="RIGHT">
</element>
<element refid="sql.right">
<name base="right" />
<FIELD name="CODE" label="Code" />
<FIELD name="NOM" label="Name" titlelabel="Name of right" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</TABLE>
<TABLE name="USER_RIGHT">
</element>
<element refid="sql.user-right">
<name base="user right">
<variant refids="plural" value="users rights" />
</name>
<FIELD name="ID_USER_COMMON" label="User" />
<FIELD name="ID_RIGHT" label="Right" />
<FIELD name="OBJECT" label="Object" />
<FIELD name="user.right.parameters.editor" label="Object" />
<FIELD name="HAVE_RIGHT" label="Right granted" titlelabel="Granted" />
</TABLE>
</ROOT>
</element>
</translations>
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightAutoCompleteComboBox.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/GroupToLightUIConvertor.java
13,7 → 13,6
package org.openconcerto.sql.ui.light;
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldMapper;
25,6 → 24,7
import org.openconcerto.ui.group.Item;
import org.openconcerto.ui.group.LayoutHints;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.LightUIAutoCompleteComboBox;
import org.openconcerto.ui.light.LightUICheckBox;
import org.openconcerto.ui.light.LightUIDate;
import org.openconcerto.ui.light.LightUIElement;
32,8 → 32,9
import org.openconcerto.ui.light.LightUILabel;
import org.openconcerto.ui.light.LightUILine;
import org.openconcerto.ui.light.LightUIPanel;
import org.openconcerto.ui.light.LightUITextArea;
import org.openconcerto.ui.light.LightUITabbed;
import org.openconcerto.ui.light.LightUITextField;
import org.openconcerto.utils.Log;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.awt.Color;
78,8 → 79,10
 
final LightEditFrame editFrame = new LightEditFrame(this.configuration, group, defaultRow.asRowValues(), parentFrame, editMode);
final LightUIPanel framePanel = editFrame.getContentPanel();
append(sqlElement, framePanel, group);
 
Map<String, LightUITabbed> tabbedMap = new HashMap<>();
append(sqlElement, framePanel, group, tabbedMap);
 
String frameTitle = TranslationManager.getInstance().getTranslationForItem(group.getId());
if (frameTitle == null) {
frameTitle = group.getId();
91,11 → 94,12
return editFrame;
}
 
private void append(final SQLElement sqlElement, final LightUIPanel panel, final Item item) {
private void append(final SQLElement sqlElement, final LightUIPanel panel, final Item item, Map<String, LightUITabbed> tabbedMap) {
if (item instanceof Group) {
final Group gr = (Group) item;
int size = gr.getSize();
 
if (gr.getTabId() == null) {
final String groupTitle = TranslationManager.getInstance().getTranslationForItem(gr.getId());
final LightUIPanel childPanel = new LightUIPanel(gr.getId());
childPanel.setFillWidth(true);
120,7 → 124,7
}
 
for (int i = 0; i < size; i++) {
this.append(sqlElement, childPanel, gr.getItem(i));
this.append(sqlElement, childPanel, gr.getItem(i), tabbedMap);
}
 
final LightUILine line = new LightUILine();
127,6 → 131,36
line.addChild(childPanel);
panel.addChild(line);
} else {
String tabId = gr.getTabId();
LightUITabbed tabbed = tabbedMap.get(tabId);
if (tabbed == null) {
tabbed = new LightUITabbed(tabId) {
 
@Override
public void loadTab(String tabId) {
// TODO Auto-generated method stub
 
}
};
final LightUILine line = new LightUILine();
line.addChild(tabbed);
panel.addChild(line);
tabbedMap.put(tabId, tabbed);
}
// add the group in the tabbed
final LightUIPanel childPanel = new LightUIPanel(gr.getId());
childPanel.setFillWidth(true);
childPanel.setGridWidth(4);
String title = TranslationManager.getInstance().getTranslationForItem(gr.getId());
childPanel.setTitle(title);
for (int i = 0; i < size; i++) {
this.append(sqlElement, childPanel, gr.getItem(i), tabbedMap);
}
 
tabbed.addChild(childPanel);
 
}
} else {
final LayoutHints localHint = item.getLocalHint();
LightUILine currentLine = panel.getLastLine();
 
156,7 → 190,10
panel.addChild(currentLine);
}
 
final SQLField field = this.mapper.getSQLFieldForItem(item.getId());
SQLField field = this.mapper.getSQLFieldForItem(item.getId());
if (field == null) {
field = sqlElement.getTable().getFieldRaw(item.getId());
}
LightUILabel elementLabel = null;
 
String label = this.getLabelForItem(field, item);
191,19 → 228,13
if (field != null) {
Class<?> javaType = field.getType().getJavaType();
if (field.isKey()) {
elementEditor = new LightAutoCompleteComboBox(item.getId());
elementEditor = new LightUIAutoCompleteComboBox(item.getId());
elementEditor.setMinInputSize(20);
elementEditor.setValueType(LightUIElement.VALUE_TYPE_REF);
} else if (javaType.equals(String.class)) {
if (field.getType().getSize() > 1000) {
elementEditor = new LightUITextArea(item.getId());
elementEditor.setValue("");
elementEditor.setMinInputSize(10);
} else {
elementEditor = new LightUITextField(item.getId());
elementEditor.setValue("");
elementEditor.setMinInputSize(10);
}
elementEditor.setValueType(LightUIElement.VALUE_TYPE_STRING);
} else if (javaType.equals(Boolean.class)) {
elementEditor = new LightUICheckBox(item.getId(), "");
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTable.java
51,12 → 51,16
 
private int offset = 0;
 
private ITableModel model;
private transient ITableModel model;
 
private final ITransformer<SQLSelect, SQLSelect> orginTransformer;
private transient ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
private List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
private transient List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>();
 
public LightRowValuesTable() {
// Serialization
}
 
public LightRowValuesTable(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(id);
 
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java
27,7 → 27,6
import org.openconcerto.ui.group.Group;
import org.openconcerto.ui.group.Item;
import org.openconcerto.ui.light.CustomEditorProvider;
import org.openconcerto.ui.light.JSONToLightUIConvertor;
import org.openconcerto.ui.light.LightUICheckBox;
import org.openconcerto.ui.light.LightUIComboBox;
import org.openconcerto.ui.light.LightUIDate;
35,6 → 34,9
import org.openconcerto.ui.light.LightUIFrame;
import org.openconcerto.utils.io.JSONConverter;
 
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
52,6 → 54,10
 
private EditMode editMode = EditMode.READONLY;
 
public LightEditFrame() {
// Serialization
}
 
// Init from json constructor
public LightEditFrame(final JSONObject json) {
super(json);
176,18 → 182,20
}
}
 
final protected void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
protected final void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement,
final Map<String, CustomEditorProvider> customEditors) {
if (!uiElement.isNotSaved()) {
boolean useElementValue = true;
final Class<?> fieldType = sqlField.getType().getJavaType();
if (customEditors.containsKey(uiElement.getId())) {
final CustomEditorProvider customEditor = customEditors.get(uiElement.getId());
if (customEditor instanceof SavableCustomEditorProvider) {
((SavableCustomEditorProvider) customEditor).save(this.sqlRow, sqlField, uiElement);
} else {
throw new IllegalStateException(customEditor + " must implement SavableCustomEditorProvider for field " + sqlField.getFieldName() + " of tye " + fieldType);
useElementValue = false;
}
} else {
}
 
if (useElementValue) {
final String fieldName = sqlField.getFieldName();
if (sqlField.isKey()) {
if (!(uiElement instanceof LightUIComboBox)) {
297,13 → 305,17
final SQLTable sqlTable = this.sqlRow.getTable();
final Date now = new Date();
// FIXME only set those fields at insertion time
if (sqlTable.getCreationUserField() != null) {
if (this.sqlRow.getObject(sqlTable.getCreationUserField().getName()) == null || this.sqlRow.getObject(sqlTable.getCreationDateField().getName()) == null) {
setFieldValue(this.sqlRow, sqlTable.getCreationUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getCreationDateField(), false, now);
}
}
if (sqlTable.getModifUserField() != null) {
setFieldValue(this.sqlRow, sqlTable.getModifUserField(), false, userId);
setFieldValue(this.sqlRow, sqlTable.getModifDateField(), false, now);
}
}
 
static private boolean setFieldValue(final SQLRowValues vals, final SQLField f, final boolean remove, final Object val) {
if (f == null)
321,17 → 333,6
}
 
@Override
public JSONToLightUIConvertor getConvertor() {
return new JSONToLightUIConvertor() {
 
@Override
public LightUIElement convert(JSONObject json) {
return new LightEditFrame(json);
}
};
}
 
@Override
public LightUIElement clone() {
return new LightEditFrame(this);
}
362,4 → 363,33
this.editMode = EditMode.READONLY;
}
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
if (this.editMode.equals(EditMode.CREATION)) {
out.writeByte(0);
} else if (this.editMode.equals(EditMode.MODIFICATION)) {
out.writeByte(1);
} else if (this.editMode.equals(EditMode.READONLY)) {
out.writeByte(2);
} else {
throw new IllegalStateException("unknown mode " + this.editMode);
}
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
int mode = in.readByte();
if (mode == 0) {
this.editMode = EditMode.CREATION;
} else if (mode == 1) {
this.editMode = EditMode.MODIFICATION;
} else if (mode == 2) {
this.editMode = EditMode.READONLY;
} else {
throw new IllegalStateException("unknown mode " + mode);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java
40,8 → 40,12
import net.minidev.json.JSONObject;
 
public class LightRowValuesTableOnline extends LightRowValuesTable {
private final ITransformer<SQLSelect, SQLSelect> orginTransformer;
private ITransformer<SQLSelect, SQLSelect> orginTransformer;
 
public LightRowValuesTableOnline() {
// Serialization
}
 
public LightRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model) {
super(configuration, userId, id, model);
 
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightUISQLComboRequest.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.sql.ui.light;
 
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.IComboSelectionItem;
import org.openconcerto.ui.light.LightUIComboBoxElement;
import org.openconcerto.ui.light.LightUIComboRequest;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Pattern;
 
public class LightUISQLComboRequest implements LightUIComboRequest {
 
private final static Pattern QUERY_SPLIT_PATTERN = Pattern.compile("\\s+");
 
private final ComboSQLRequest request;
 
public LightUISQLComboRequest(ComboSQLRequest request) {
super();
this.request = request;
}
 
@Override
public List<LightUIComboBoxElement> getItems(String filter, Optional<LightUIComboBoxElement> selection) {
final Where where = selection.isPresent() ? new Where(this.request.getPrimaryTable().getKey(), "=", selection.get().getId()) : null;
final List<IComboSelectionItem> items = this.request.getComboItems(true, Arrays.asList(QUERY_SPLIT_PATTERN.split(filter)), Locale.getDefault(), where);
final List<LightUIComboBoxElement> res = new ArrayList<>(items.size());
for (final IComboSelectionItem item : items) {
res.add(new LightUIComboBoxElement(item.getId(), item.getLabel()));
}
return res;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_fr.xml
1,6 → 1,7
<?xml version="1.0" encoding="UTF-8" ?>
<ROOT>
<TABLE name="USER_COMMON">
<translations>
<element refid="sql.user">
<name base="utilisateur" nounClass="masculine" />
<FIELD name="NOM" label="Nom" titlelabel="Nom" />
<FIELD name="PRENOM" label="Prénom" titlelabel="Prénom" />
<FIELD name="PASSWORD" label="Mot de passe" titlelabel="Mot de passe" />
12,17 → 13,21
<FIELD name="MAIL" label="E-Mail" titlelabel="E-Mail" />
<FIELD name="DISABLED" label="Compte désactivé" />
<FIELD name="TEL" label="Téléphone" titlelabel="Téléphone" />
</TABLE>
<TABLE name="RIGHT">
</element>
<element refid="sql.right">
<name base="droit" nounClass="masculine" />
<FIELD name="CODE" label="Code" titlelabel="Code" />
<FIELD name="NOM" label="Nom" titlelabel="Nom du droit" />
<FIELD name="DESCRIPTION" label="Description" titlelabel="Desc." />
</TABLE>
<TABLE name="USER_RIGHT">
</element>
<element refid="sql.user-right">
<name base="droit utilisateur" nounClass="masculine">
<variant refids="plural" value="droits utilisateurs" />
</name>
<FIELD name="ID_USER_COMMON" label="Utilisateur" titlelabel="Utilis." />
<FIELD name="ID_RIGHT" label="Droit" />
<FIELD name="OBJECT" label="Objet" />
<FIELD name="user.right.parameters.editor" label="Objet" />
<FIELD name="HAVE_RIGHT" label="Droit accordé" titlelabel="Accordé" />
</TABLE>
</ROOT>
</element>
</translations>
/trunk/OpenConcerto/src/org/openconcerto/sql/mapping_es.xml
New file
0,0 → 1,14
<?xml version="1.0" encoding="UTF-8" ?>
<translations>
<element refid="sql.user">
<name base="usuario" nounClass="masculine" />
</element>
<element refid="sql.right">
<name base="derecho" nounClass="masculine" />
</element>
<element refid="sql.user-right">
<name base="derecho de usuario" nounClass="masculine">
<variant refids="plural" value="derechos de usuarios" />
</name>
</element>
</translations>
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextArticleWithCompletionCellEditor.java
13,6 → 13,12
package org.openconcerto.sql.sqlobject;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.Component;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
23,12 → 29,6
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellEditor;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;
 
public class ITextArticleWithCompletionCellEditor extends AbstractCellEditor implements TableCellEditor {
 
private final ITextArticleWithCompletion text;
37,6 → 37,7
public ITextArticleWithCompletionCellEditor(SQLTable tableArticle, SQLTable tableARticleFournisseur) {
this.text = new ITextArticleWithCompletion(tableArticle, tableARticleFournisseur);
this.text.setBorder(BorderFactory.createEmptyBorder());
this.text.getTextComp().setBorder(BorderFactory.createEmptyBorder());
}
 
private void initListener(final JTable t) {
/trunk/OpenConcerto/src/org/openconcerto/sql/Configuration.java
126,7 → 126,9
 
public abstract SQLFilter getFilter();
 
public abstract SQLFieldTranslator getTranslator();
public final SQLFieldTranslator getTranslator() {
return this.getDirectory().getTranslator();
}
 
public abstract SQLElementDirectory getDirectory();
 
207,15 → 209,13
}
 
/**
* Add the translator and directory of <code>o</code> to this.
* Add the directory of <code>o</code> to this.
*
* @param o the configuration to add.
* @return this.
* @see SQLFieldTranslator#putAll(SQLFieldTranslator)
* @see SQLElementDirectory#putAll(SQLElementDirectory)
*/
public Configuration add(Configuration o) {
this.getTranslator().putAll(o.getTranslator());
this.getDirectory().putAll(o.getDirectory());
return this;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLFieldTranslator.java
17,6 → 17,7
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.element.SQLElementDirectory.DirectoryListener;
import org.openconcerto.sql.element.SQLElementNamesFromXML;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
34,10 → 35,10
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.i18n.Phrase;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
49,6 → 50,7
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.prefs.Preferences;
 
139,6 → 141,9
// { SQLTable -> { compCode, variant, item -> RowItemDesc }}
@GuardedBy("this")
private final Map<SQLTable, Map<List<String>, RowItemDesc>> translation;
// { element code -> { variant -> name }}
@GuardedBy("this")
private final Map<String, Map<String, Phrase>> elementNames;
private final SQLTable table;
private final SQLElementDirectory dir;
@GuardedBy("this")
146,6 → 151,7
 
{
this.translation = new HashMap<SQLTable, Map<List<String>, RowItemDesc>>();
this.elementNames = new HashMap<>();
this.unknownCodes = new HashSet<String>();
}
 
153,10 → 159,9
* Create a new instance.
*
* @param root the default root for tables.
* @param inputStream the XML, can be <code>null</code>.
* @param dir the directory where to look for tables not in <code>root</code>.
*/
public SQLFieldTranslator(DBRoot root, InputStream inputStream, SQLElementDirectory dir) {
public SQLFieldTranslator(DBRoot root, SQLElementDirectory dir) {
try {
this.table = getMetaTable(root);
} catch (SQLException e) {
180,8 → 185,6
}
}
});
if (inputStream != null)
this.load(root, inputStream);
fetchAndPut(this.table, null);
}
 
217,10 → 220,10
}
}
 
public void load(DBRoot b, File file) {
try {
load(b, new FileInputStream(file));
} catch (FileNotFoundException e) {
public void load(DBRoot b, File file, final SQLElementNamesFromXML elemNames) {
try (final InputStream ins = new FileInputStream(file)) {
this.load(b, ins, elemNames);
} catch (IOException e) {
e.printStackTrace();
}
}
229,14 → 232,8
return elem.getChildren();
}
 
/**
* Load more translations.
*
* @param b the default root for tables.
* @param inputStream the XML.
*/
public void load(DBRoot b, InputStream inputStream) {
this.load(b, CORE_VARIANT, inputStream);
public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, InputStream inputStream, final SQLElementNamesFromXML elemNames) {
return this.load(b, CORE_VARIANT, inputStream, elemNames);
}
 
/**
245,9 → 242,10
* @param b the default root for tables.
* @param variant the variant to use.
* @param inputStream the XML.
* @param elemNames how to load element names.
* @return the loaded tables and the names not found (and thus not loaded).
*/
public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, final String variant, InputStream inputStream) {
public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, final String variant, InputStream inputStream, final SQLElementNamesFromXML elemNames) {
if (inputStream == null)
throw new NullPointerException("inputStream is null");
final Set<SQLTable> res = new HashSet<SQLTable>();
259,19 → 257,19
final String elemName = elem.getName().toLowerCase();
final DBRoot root;
final List<Element> tableElems;
if (elemName.equals("table")) {
if (elemName.equals("table") || elemName.equals("element")) {
root = b;
tableElems = Collections.singletonList(elem);
} else if (elemName.equals("root")) {
root = b.getDBSystemRoot().getRoot(elem.getAttributeValue("name"));
tableElems = getChildren(elem);
} else {
if (elemName.equals("root")) {
Log.get().warning("Ignoring deprecated <root> element, use element code to refer to tables outside the default root");
}
root = null;
tableElems = null;
}
if (tableElems != null) {
for (final Element tableElem : tableElems) {
final Tuple2<String, SQLTable> t = load(root, variant, tableElem, true);
final Tuple2<String, SQLTable> t = load(root, variant, tableElem, elemNames, true);
if (t.get1() == null) {
notFound.add(t.get0());
} else {
290,11 → 288,19
return Tuple2.create(res, notFound);
}
 
private Tuple2<String, SQLTable> load(DBRoot b, final String variant, final Element tableElem, final boolean lenient) {
private Tuple2<String, SQLTable> load(DBRoot b, final String variant, final Element tableElem, final SQLElementNamesFromXML elemNames, final boolean lenient) {
final String tableName = tableElem.getAttributeValue("name");
SQLTable table = this.dir == null || this.dir.getElement(tableName) == null ? b.getTable(tableName) : this.dir.getElement(tableName).getTable();
if (table == null && this.dir != null && this.dir.getElementForCode(tableName) != null)
table = this.dir.getElementForCode(tableName).getTable();
String elemCode = tableElem.getAttributeValue("refid");
SQLTable table = null;
// compatibility mode for files without element names
final boolean compatMode = tableElem.getName().toLowerCase().equals("table");
if (compatMode) {
table = this.dir == null || this.dir.getElement(tableName) == null ? b.getTable(tableName) : this.dir.getElement(tableName).getTable();
if (elemCode == null)
elemCode = tableName;
}
if (table == null && this.dir != null && this.dir.getElementForCode(elemCode) != null)
table = this.dir.getElementForCode(elemCode).getTable();
if (table != null) {
for (final Element elem : getChildren(tableElem)) {
final String elemName = elem.getName().toLowerCase();
307,6 → 313,15
}
}
}
try {
if (!compatMode) {
final Entry<String, Phrase> phrase = elemNames.createPhrase(tableElem);
if (phrase != null)
this.putElementName(this.dir.getElement(table), phrase.getValue(), variant);
}
} catch (IOException e) {
throw new IllegalStateException("Couldn't parse phrase for " + table, e);
}
} else if (lenient) {
// allow to supply the union all tables and ignore those that aren't in a given base
Log.get().config("Ignore loading of inexistent table " + tableName);
568,4 → 583,45
}
this.removeTranslation(elemTable, componentCode, DB_VARIANT, name);
}
 
// ** element names
 
public final Phrase putElementName(final Class<? extends SQLElement> elemCl, final Phrase phr) {
return this.putElementName(this.getDirectory().getElement(elemCl), phr);
}
 
public final Phrase putElementName(final SQLElement elem, final Phrase phr) {
return this.putElementName(elem, phr, CORE_VARIANT);
}
 
public synchronized final Phrase putElementName(final SQLElement elem, final Phrase phr, final String variant) {
return this.getElementNameMap(elem, true).put(variant, phr);
}
 
private synchronized final Map<String, Phrase> getElementNameMap(final SQLElement elem, final boolean create) {
Map<String, Phrase> elemMap = this.elementNames.get(elem.getCode());
if (elemMap == null && create) {
elemMap = new HashMap<>();
this.elementNames.put(elem.getCode(), elemMap);
}
return elemMap;
}
 
public final Phrase getElementName(final SQLElement elem) {
return this.getElementName(elem, elem.getMDPath());
}
 
public final Phrase getElementName(final SQLElement elem, final List<String> variantPath) {
for (final String variant : variantPath) {
final Phrase res = this.getElementName(elem, variant);
if (res != null)
return res;
}
return this.getElementName(elem, CORE_VARIANT);
}
 
private synchronized final Phrase getElementName(final SQLElement elem, final String variant) {
final Map<String, Phrase> map = this.getElementNameMap(elem, false);
return map == null ? null : map.get(variant);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementNamesMap.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementNames.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
15,7 → 15,6
 
import org.openconcerto.sql.Log;
import org.openconcerto.sql.ShowAs;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItemNotFound;
import org.openconcerto.sql.model.SQLName;
25,12 → 24,7
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.SetMap;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.i18n.LocalizedInstances;
import org.openconcerto.utils.i18n.Phrase;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
37,13 → 31,10
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
 
import org.jdom2.JDOMException;
 
import net.jcip.annotations.GuardedBy;
 
/**
53,29 → 44,6
*/
public final class SQLElementDirectory {
 
public static final String BASENAME = SQLElementNames.class.getSimpleName();
private static final LocalizedInstances<SQLElementNames> LOCALIZED_INSTANCES = new LocalizedInstances<SQLElementNames>(SQLElementNames.class, TranslationManager.getControl()) {
@Override
protected SQLElementNames createInstance(String bundleName, Locale candidate, Class<?> cl) throws IOException {
final InputStream ins = cl.getResourceAsStream('/' + getControl().toResourceName(bundleName, "xml"));
if (ins == null)
return null;
final SQLElementNamesFromXML res = new SQLElementNamesFromXML(candidate);
try {
res.load(ins);
} catch (JDOMException e) {
throw new IOException("Invalid XML", e);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
} finally {
ins.close();
}
return res;
}
};
 
private final Map<SQLTable, SQLElement> elements;
private final SetMap<String, SQLTable> tableNames;
private final SetMap<String, SQLTable> byCode;
83,7 → 51,6
private final List<DirectoryListener> listeners;
 
private String phrasesPkgName;
private final Map<String, SQLElementNames> elementNames;
 
@GuardedBy("this")
private SQLFieldTranslator translator;
100,7 → 67,6
this.listeners = new ArrayList<DirectoryListener>();
 
this.phrasesPkgName = null;
this.elementNames = new HashMap<String, SQLElementNames>();
 
this.showAs = new ShowAs((DBRoot) null);
}
152,17 → 118,26
* @param element the element to add.
*/
public final void addSQLElement(final Class<? extends SQLElement> element) {
this.addSQLElement(element, null);
}
 
public final void addSQLElement(final Class<? extends SQLElement> element, final DBRoot root) {
final SQLElement newInstance;
try {
this.addSQLElement(element.getConstructor().newInstance());
if (root == null)
newInstance = element.getConstructor().newInstance();
else
newInstance = element.getConstructor(DBRoot.class).newInstance(root);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof DBStructureItemNotFound) {
Log.get().config("ignore inexistent tables: " + e.getCause().getLocalizedMessage());
return;
}
throw new IllegalArgumentException("ctor failed", e);
throw new IllegalArgumentException("Constructor failed", e);
} catch (Exception e) {
throw new IllegalArgumentException("no-arg ctor failed", e);
throw new IllegalArgumentException("Couldn't use constructor", e);
}
this.addSQLElement(newInstance);
}
 
/**
293,43 → 268,6
return this.phrasesPkgName;
}
 
protected synchronized final SQLElementNames getElementNames(final String pkgName, final Locale locale, final Class<?> cl) {
if (pkgName == null)
return null;
final char sep = ' ';
final String key = pkgName + sep + locale.toString();
assert pkgName.indexOf(sep) < 0 : "ambiguous key : " + key;
SQLElementNames res = this.elementNames.get(key);
if (res == null) {
final List<SQLElementNames> l = LOCALIZED_INSTANCES.createInstances(pkgName + "." + BASENAME, locale, cl).get1();
if (!l.isEmpty()) {
for (int i = 1; i < l.size(); i++) {
l.get(i - 1).setParent(l.get(i));
}
res = l.get(0);
}
this.elementNames.put(key, res);
}
return res;
}
 
/**
* Search a name for the passed instance and the {@link TM#getTranslationsLocale() current
* locale}. Search for {@link SQLElementNames} using {@link LocalizedInstances} and
* {@link SQLElementNamesFromXML} first in {@link SQLElement#getL18nPackageName()} then in
* {@link #getL18nPackageName()}. E.g. this could load SQLElementNames_en.class and
* SQLElementNames_en_UK.xml.
*
* @param elem the element.
* @return the name if found, <code>null</code> otherwise.
*/
public final Phrase getName(final SQLElement elem) {
final String elemBaseName = elem.getL18nPackageName();
final String pkgName = elemBaseName == null ? getL18nPackageName() : elemBaseName;
final SQLElementNames elementNames = getElementNames(pkgName, TM.getInstance().getTranslationsLocale(), elem.getL18nClass());
return elementNames == null ? null : elementNames.getName(elem);
}
 
public synchronized final void addListener(DirectoryListener dl) {
this.listeners.add(dl);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SharedSQLElement.java
13,6 → 13,7
package org.openconcerto.sql.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLTable;
 
/**
26,10 → 27,18
super(tableName);
}
 
public SharedSQLElement(final Configuration conf, String tableName, final String code) {
super(conf, tableName, null, code);
}
 
public SharedSQLElement(SQLTable table) {
super(table);
this(table, null);
}
 
public SharedSQLElement(final SQLTable table, final String code) {
super(table, null, code);
}
 
@Override
public final boolean isShared() {
return true;
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementNamesFromXML.java
23,8 → 23,13
import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Pattern;
 
import org.jdom2.Document;
50,27 → 55,61
*
*/
@ThreadSafe
public class SQLElementNamesFromXML extends SQLElementNamesMap.ByCode {
public class SQLElementNamesFromXML {
 
static public final Pattern SPLIT_PATTERN = Pattern.compile("\\s*,\\s*");
static private final Set<Object> SHORT_VARIANTS = Collections.singleton(Grammar.PLURAL);
 
private static final String ELEMENT_ELEM_NAME = "element";
private static final String NAME_ID_ATTR = "refid";
private static final String VARIANT_ATTR = "variant";
private static final String VARIANT_REFIDS_ATTR = "refids";
private static final String VARIANT_VALUE_ATTR = "value";
private static final String NAME_PLURAL_ATTR = "namePlural";
 
static private final String getNounClassAttrName(final boolean shortForm) {
return shortForm ? "nameClass" : "nounClass";
}
 
// <element nameClass="masculine" name="contact fournisseur">
// <name nounClass="masculine" base="droit utilisateur">
static final private void setNounClassAndBase(final Element elem, final Phrase phrase, final boolean shortForm) {
elem.setAttribute(getNounClassAttrName(shortForm), phrase.getNounClass().getName());
elem.setAttribute(shortForm ? "name" : "base", phrase.getBase());
}
 
private final Locale locale;
 
public SQLElementNamesFromXML(Locale locale) {
super(locale);
this.locale = locale;
}
 
public final void load(final InputStream ins) throws JDOMException, IOException {
final Grammar gr = Grammar.getInstance(getLocale());
public final Locale getLocale() {
return this.locale;
}
 
public final Map<String, Phrase> load(final InputStream ins) throws JDOMException, IOException {
final Document doc = new SAXBuilder().build(ins);
for (final Element elem : doc.getRootElement().getChildren("element"))
this.load(gr, elem);
return load(doc.getRootElement());
}
 
public final Map<String, Phrase> load(final Element root) throws IOException {
final Grammar gr = Grammar.getInstance(getLocale());
final Map<String, Phrase> res = new HashMap<>();
for (final Element elem : root.getChildren(ELEMENT_ELEM_NAME)) {
final Entry<String, Phrase> e = this.createPhrase(gr, elem);
if (e != null)
res.put(e.getKey(), e.getValue());
}
return res;
}
 
public final Entry<String, Phrase> createPhrase(final Element elem) throws IOException {
return this.createPhrase(Grammar.getInstance(getLocale()), elem);
}
 
private Entry<String, Phrase> createPhrase(final Grammar gr, final Element elem) throws IOException {
final String refid = elem.getAttributeValue("refid");
final String refid = elem.getAttributeValue(NAME_ID_ATTR);
if (refid == null)
throw new IOException("No refid attribute");
 
78,7 → 117,8
final boolean hasChild = nameElem != null;
final String nameAttr = elem.getAttributeValue("name");
if (!hasChild && nameAttr == null) {
Log.get().warning("No name for code : " + refid);
// perhaps elem is just used to change item names
Log.get().log(Level.FINER, "No name for code : {0}", refid);
return null;
}
if (hasChild && nameAttr != null) {
88,23 → 128,23
final String base = hasChild ? nameElem.getAttributeValue("base") : nameAttr;
if (base == null)
throw new IOException("No base for the name of " + refid);
final String nounClassName = hasChild ? nameElem.getAttributeValue("nounClass") : elem.getAttributeValue("nameClass");
final String nounClassName = (hasChild ? nameElem : elem).getAttributeValue(getNounClassAttrName(!hasChild));
final NounClass nounClass = nounClassName == null ? null : gr.getNounClass(nounClassName);
 
final Phrase res = new Phrase(gr, base, nounClass);
if (!hasChild) {
// most languages have at most 2 grammatical number
final String plural = elem.getAttributeValue("namePlural");
final String plural = elem.getAttributeValue(NAME_PLURAL_ATTR);
if (plural != null)
res.putVariant(Grammar.PLURAL, plural);
} else {
for (final Element variantElem : nameElem.getChildren("variant")) {
final String value = variantElem.getAttributeValue("value");
for (final Element variantElem : nameElem.getChildren(VARIANT_ATTR)) {
final String value = variantElem.getAttributeValue(VARIANT_VALUE_ATTR);
if (value == null) {
warning(refid, variantElem, "No value");
continue;
}
final String variantIDs = variantElem.getAttributeValue("refids");
final String variantIDs = variantElem.getAttributeValue(VARIANT_REFIDS_ATTR);
final String variantPattern = variantElem.getAttributeValue("idPattern");
if (variantIDs == null && variantPattern == null) {
warning(refid, variantElem, "No ID");
134,13 → 174,35
return new SimpleEntry<String, Phrase>(refid, res);
}
 
private void load(final Grammar gr, final Element elem) throws IOException {
final Entry<String, Phrase> entry = this.createPhrase(gr, elem);
if (entry != null)
this.put(entry.getKey(), entry.getValue());
}
 
private void warning(final String refid, final Element variantElem, final String msg) {
Log.get().warning(msg + " for variant of " + refid + " : " + JDOM2Utils.output(variantElem));
}
 
public final Element createElement(final String refID, final Phrase phrase) {
final Element elem = new Element(ELEMENT_ELEM_NAME);
elem.setAttribute(NAME_ID_ATTR, refID);
final Set<VariantKey> explicitVariants = phrase.getExplicitVariants();
final boolean shortForm = SHORT_VARIANTS.containsAll(explicitVariants);
final Element nameElem;
if (shortForm) {
nameElem = elem;
} else {
nameElem = new Element("name");
elem.addContent(nameElem);
}
setNounClassAndBase(nameElem, phrase, shortForm);
if (!shortForm) {
// <variant refids="plural" value="droits utilisateurs"
for (final VariantKey explicitVariant : explicitVariants) {
final Element variantElem = new Element(VARIANT_ATTR);
variantElem.setAttribute(VARIANT_REFIDS_ATTR, explicitVariant.getID());
variantElem.setAttribute(VARIANT_VALUE_ATTR, phrase.getVariant(explicitVariant));
nameElem.addContent(variantElem);
}
} else if (explicitVariants.contains(Grammar.PLURAL)) {
elem.setAttribute(NAME_PLURAL_ATTR, phrase.getVariant(Grammar.PLURAL));
}
return elem;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
159,8 → 159,8
}
final Phrase res = new Phrase(Grammar_fr.getInstance(), base, nounClass);
if (nounClass != null)
res.putVariant(Grammar.INDEFINITE_ARTICLE_SINGULAR, singular);
res.putVariant(Grammar.PLURAL, plural);
res.putVariantIfDifferent(Grammar.INDEFINITE_ARTICLE_SINGULAR, singular);
res.putVariantIfDifferent(Grammar.PLURAL, plural);
return res;
}
 
184,9 → 184,7
 
@GuardedBy("this")
private SQLElementDirectory directory;
private String l18nPkgName;
private Class<?> l18nClass;
private Phrase name;
private Phrase defaultName;
private final SQLTable primaryTable;
// used as a key in SQLElementDirectory so it should be immutable
private String code;
233,7 → 231,6
throw new DBStructureItemNotFound("table is null for " + this.getClass());
}
this.primaryTable = primaryTable;
this.setL18nPackageName(null);
this.setDefaultName(name);
this.code = code == null ? createCode() : code;
this.combo = null;
256,7 → 253,11
 
/**
* Should return the code for this element. This method is only called if the <code>code</code>
* parameter of the constructor is <code>null</code>.
* parameter of the constructor is <code>null</code>. This implementation returns a string
* containing the {@link Class#getName() full name} of the class and the {@link #getTable()
* table} name to handle a single class being used for multiple tables. NOTE: this method is
* also needed, since a subclass constructor cannot pass <code>this.getClass().getName()</code>
* as the code parameter to <code>super</code>.
*
* @return the default code for this element.
*/
598,7 → 599,10
 
// return Path from owner to owned
private final Set<Path> createPaths(final boolean wantedOwned) {
assert !(this instanceof JoinSQLElement) : "joins cannot have SQLElementLink : " + this;
// joins cannot have SQLElementLink
if (this instanceof JoinSQLElement)
return Collections.emptySet();
 
final SQLTable thisTable = this.getTable();
final Set<Link> allLinks = thisTable.getDBSystemRoot().getGraph().getAllLinks(getTable());
final Set<Path> res = new HashSet<Path>();
754,7 → 758,11
private synchronized void initRF() {
if (this.otherLinks != null)
return;
 
final Set<Path> otherPaths = this.createPaths(false);
if (otherPaths.isEmpty()) {
this.otherLinks = SQLElementLinks.empty();
} else {
final SetMap<LinkType, SQLElementLink> tmp = new SetMap<LinkType, SQLElementLink>();
for (final Path p : otherPaths) {
final SQLElement refElem = this.getElementLenient(p.getFirst());
770,6 → 778,7
}
this.otherLinks = new SQLElementLinks(tmp);
}
}
 
final void setDirectory(final SQLElementDirectory directory) {
// since this method should only be called at the end of SQLElementDirectory.addSQLElement()
812,36 → 821,7
return this.getTable().getBase().getGraph().getForeignTable(this.getTable().getField(foreignField));
}
 
public final synchronized String getL18nPackageName() {
return this.l18nPkgName;
}
 
public final synchronized Class<?> getL18nClass() {
return this.l18nClass;
}
 
public final void setL18nLocation(Class<?> clazz) {
this.setL18nLocation(clazz.getPackage().getName(), clazz);
}
 
public final void setL18nPackageName(String name) {
this.setL18nLocation(name, null);
}
 
/**
* Set the location for the localized name.
*
* @param name a package name, can be <code>null</code> :
* {@link SQLElementDirectory#getL18nPackageName()} will be used.
* @param ctxt the class loader to load the resource, <code>null</code> meaning this class.
* @see SQLElementDirectory#getName(SQLElement)
*/
public final synchronized void setL18nLocation(final String name, final Class<?> ctxt) {
this.l18nPkgName = name;
this.l18nClass = ctxt == null ? this.getClass() : ctxt;
}
 
/**
* Set the default name, used if no translations could be found.
*
* @param name the default name, if <code>null</code> the {@link #getTable() table} name will be
848,7 → 828,7
* used.
*/
public final synchronized void setDefaultName(Phrase name) {
this.name = name != null ? name : Phrase.getInvariant(getTable().getName());
this.defaultName = name != null ? name : Phrase.getInvariant(getTable().getName());
}
 
/**
857,7 → 837,7
* @return the default name, never <code>null</code>.
*/
public final synchronized Phrase getDefaultName() {
return this.name;
return this.defaultName;
}
 
/**
869,7 → 849,8
*/
public final Phrase getName() {
final SQLElementDirectory dir = this.getDirectory();
final Phrase res = dir == null ? null : dir.getName(this);
final SQLFieldTranslator trns = dir == null ? null : dir.getTranslator();
final Phrase res = trns == null ? null : trns.getElementName(this);
return res == null ? this.getDefaultName() : res;
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/ConfSQLElement.java
25,21 → 25,6
*/
public class ConfSQLElement extends SQLElement {
 
@Deprecated
public ConfSQLElement(String tableName, String singular, String plural) {
this(Configuration.getInstance(), tableName, singular, plural);
}
 
@Deprecated
public ConfSQLElement(Configuration conf, String tableName, String singular, String plural) {
this(conf.getRoot().findTable(tableName), singular, plural);
}
 
@Deprecated
public ConfSQLElement(SQLTable table, String singular, String plural) {
super(singular, plural, table);
}
 
public ConfSQLElement(String tableName) {
this(tableName, null);
}
48,22 → 33,30
this(conf, tableName, null);
}
 
public ConfSQLElement(SQLTable table) {
this(table, null);
}
 
public ConfSQLElement(String tableName, final Phrase name) {
this(Configuration.getInstance(), tableName, name);
}
 
public ConfSQLElement(Configuration conf, String tableName, final Phrase name) {
this(conf.getRoot().findTable(tableName), name);
this(conf, tableName, name, null);
}
 
public ConfSQLElement(Configuration conf, String tableName, final Phrase name, final String code) {
this(conf.getRoot().findTable(tableName), name, code);
}
 
public ConfSQLElement(final SQLTable table) {
this(table, null);
}
 
public ConfSQLElement(final SQLTable primaryTable, final Phrase name) {
super(primaryTable, name);
this(primaryTable, name, null);
}
 
public ConfSQLElement(final SQLTable primaryTable, final Phrase name, final String code) {
super(primaryTable, name, code);
}
 
@Override
protected List<String> getComboFields() {
return Collections.emptyList();
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/SQLElementNames_fr.xml
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/SQLElementNames_en.xml
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_es.properties
New file
0,0 → 1,199
init.error=Error de inicialización
add=Añadir
saveModifications=Guardar cambios
display=Ver
modify=Editar
delete=Limpiar
remove=Borrar
close=Cerrar
cancel=Cancelar
search=Buscar
open=Abrir
save=Guardar
backup=Hacer la copia de seguridad
export=Exportar
noSelection=Sin selección
duplicate=Duplicar
duplication=Duplicación
location=Ubicación
choose=Elige
toApply=Aplicar
 
all=Todo
toReverse=Revertir
 
contains=Contiene
contains.exactly=Contiene exactamente
isLessThan=Es menos de
isLessThanOrEqualTo=Es menor o igual a
isEqualTo=Es igual a
isExactlyEqualTo=Es exactamente igual a
isGreaterThan=Es más de
isGreaterThanOrEqualTo=Es más o igual a
isEmpty=Esta vacio
 
clone.newPlace=Nueva ubicación (opcional) :
 
saveError=Error al guardar
 
loginPanel.storePass=Almacenar contraseña
loginPanel.loginAction=Iniciar sesión
loginPanel.adminLogin=Administrador
loginPanel.loginLabel=Nombre de usuario
loginPanel.passLabel=Contraseña
loginPanel.companyLabel=Empresa
loginPanel.disabledUser=Cuenta de usuario deshabilitada
loginPanel.unknownUser=Usuario desconocido
loginPanel.multipleUser=Múltiples usuarios nombrados "{0}"
loginPanel.wrongPass=Contraseña incorrecta
 
noRightToAdd=No puedes agregar
noRightToModify=No puedes editar
noRightToDel=No puedes borrar
noRightToClone=No puedes duplicar
noRightToReorder=No puedes cambiar la orden
 
 
editPanel.keepOpen=No cerrar ventana
editPanel.readOnlySelection=This row is read only
editPanel.localPrivateSelection=This row is used by another item
editPanel.inexistentElement=this item doesn't exist
editPanel.cancelError=Error while canceling
editPanel.modifyError=Error while modifying
editPanel.addError=Error while adding
editPanel.deleteError=Error while deleting
editPanel.invalidContent=Input fields aren''t filled correctly.\n\nYou cannot save modifications :
editPanel.invalidContent.unknownReason= they aren''t valid
 
editAction.name=Crear {element__singularIndefiniteArticle}
editFrame.create=Crear {element__singularIndefiniteArticle}
editFrame.modify=Modificar {element__singularIndefiniteArticle}
editFrame.look=Detalles de {element__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html>
listPanel.cloneRows=listPanel.cloneRows=Do you want to clone {rec, select,\
true {\
{rowCount, plural,\
one {this row and its content ?}\
other {these # rows and their content ?}\
}}\
other {\
{rowCount, plural,\
one {this row ?}\
other {these # rows ?}\
}}\
}
listPanel.clone.collectingData=Collecting data for {0,plural,one{# row} other{# rows}}\u2026
listPanel.clone.storingData=Storing {0,plural,one{# row} other{# rows}}\u2026
listPanel.noSelectionOrSort=No selection or list sorted
listPanel.export=List export
listPanel.save=Save the list
listPanel.wholeList=the whole list
listPanel.selection=the selection
listPanel.duplicationError=Couldn''t duplicate {0}
 
listAction.name=Manage {element__pluralDefiniteArticle}
element.list=Lista de {element__plural}
 
ilist.setColumnsWidth=Ajustar ancho columnas
ilist.showAllColumns=Ver todas las columnas
ilist.lastCol=Cannot hide the last column
ilist.lockRows=Lock rows
ilist.unlockRows=Unlock rows
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}}
 
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}}
sqlComp.bdTooHigh=Number too high, {0, plural,\
one {it must have at most # digit before the decimal point ({1} after)}\
other {it must have at most # digits before the decimal point ({1} after)}}
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} is empty
sqlComp.insertError=Error while inserting
sqlComp.insertCancelled=Insertion cancelled
sqlComp.selectError=Error while displaying {0}
sqlComp.updateError=Error while updating
sqlComp.updateCancelled=Update cancelled
sqlComp.updateCancelled.archived=The row was archived
sqlComp.updateCancelled.moreArchivedRows=The database was modified (there are more rows to be archived)
sqlComp.rowsToArchiveError=Error while searching data to archive {0}
sqlComp.archiveError=Error while archiving
sqlComp.archiveCancelled=Archive cancelled
sqlComp.saveDocError=Error while saving documentation of {0}
sqlComp.modifyDoc=Modify the documentation
sqlComp.deletedRow=The row is no longer in the database : {0}
 
sqlElement.archive.computingRows=Computing rows to archive\u2026
sqlElement.archiveError=Error while archiving {0} IDs {1}
sqlElement.confirmDelete=Confirm deletion
sqlElement.deleteNoRef=Do you want to delete {rowCount, plural, one {this row} other {these # rows}} ?
sqlElement.deleteRef.details= {descsSize, plural, =0 {} other\
{{rowCount, plural, one {This row is used} other {These rows are used}} by :\n\
{descs}}}\
{externsSize, plural, =0 {} other {{descsSize, plural, =0 {The} other {\n\nFurther the}} following links will be IRRETRIEVABLY cut : \n\
{externs}}}\n\n
sqlElement.deleteRef.details2=The following links will be IRRETRIEVABLY cut, they couldn\u2019t be 'unarchived' :\n\
{externs}\n\n
sqlElement.deleteRef=Do you{times, select, once {} other { REALLY}} want to delete {rowCount, plural, one {this row} other {these # rows}} and all linked ones ?
sqlElement.noLinesDeleted=No lines deleted.
sqlElement.noLinesDeletedTitle=Information
sqlElement.linksWillBeCut=- {elementName__indefiniteNumeral} {count, plural, one {will lose its} other {will lose their}} "{linkName}"
sqlElement.linkCantBeCut={rowDesc} cannot lose its field "{fieldLabel}"
 
sqlElement.deletePrivateNoRef={elementName__indefiniteNumeral} {elementNameCount, plural, one {is to be deleted} other {are to be deleted}}.
 
sqlElement.deletePrivateRef.details=The removal of {elementName__indefiniteNumeral} will cause :\n\
{descsSize, plural, =0 {} other {{descs}\n}}\
{externs}
sqlElement.deletePrivateRef.desc=- the removal of {elementName__indefiniteNumeral}
sqlElement.deletePrivateRef.linksWillBeCut=- the permanent deletion of the field "{linkName}" for {elementName__indefiniteNumeral}
 
sqlElement.modify.deletePrivate=\n\nModify {elementName__singularDemonstrative} and delete the informations listed above ?
 
user.passwordsDontMatch=Passwords don\u2019t match
user.passwordsDontMatch.short=Passwords don\u2019t match
 
infoPanel.rights=Rights enabled
infoPanel.appName=Application name
infoPanel.noAppName=unknown
infoPanel.version=Application version
infoPanel.noVersion=unknown
infoPanel.secureLink=Secure link
infoPanel.dbURL=Database URL
infoPanel.dirs=Folders
infoPanel.logs=Logs
infoPanel.docs=Documents
infoPanel.dataDir=Data
infoPanel.prefsDir=Preferences
infoPanel.cacheDir=Cache
 
infoPanel.softwareTitle=Software
infoPanel.systemTitle=System information
infoPanel.refresh=Click to refresh
 
backupPanel.backup=Backup
backupPanel.createFolderError=Couldn't create destination folder. Backup canceled !
backupPanel.folderRightsError=Insufficient rights on destination folder. Backup canceled !
backupPanel.errorsOnLastBackup=Errors occurred on last backup. Please contact IT.
backupPanel.lastBackup=Last backup {date, date, long} at {date, time, short}\non {destination}
backupPanel.differentDisks=Please backup on different disks !
backupPanel.progress=Backup progress
backupPanel.inProgress=Backup in progress
backupPanel.closingIn=Closing in {0}s
backupPanel.endFail=Backup ended with errors !
backupPanel.endSuccess=Backup ended successfully
backupPanel.failed=Backup failed
 
rights=Rights
rightsPanel.defaultRights=Default rights
rights.allTables=All tables
 
combo.list=List {element__pluralDefiniteArticle}
 
joinComp.usedBy=Cannot delete selection, it is used by "{0}"
 
browserCol.content=Content of {element__pluralDefiniteArticle}
 
addNewLine=Añadir nueva línea
insertNewLine=Insertar línea
duplicateLine=Duplicar líneas seleccionadas
deleteLine=Eliminar líneas seleccionadas
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_fr.properties
69,8 → 69,18
editFrame.look=Détail {element__de__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Permet de dupliquer une ligne.<br>Maintenir CTRL enfoncé pour dupliquer également le contenu<br>Maintenir Maj. enfoncé pour changer d'emplacement.</html>
listPanel.cloneRows=Voulez-vous cloner {rowCount, plural, one {cette ligne{rec, select, true { et son contenu} other {}}}\
other {ces # lignes{rec, select, true { et leurs contenus} other {}}}} ?
listPanel.cloneRows=Voulez-vous cloner {rec, select,\
true {\
{rowCount, plural,\
one {cette ligne et son contenu ?}\
other {ces # lignes et leurs contenus ?}\
}}\
other {\
{rowCount, plural,\
one {cette ligne ?}\
other {ces # lignes ?}\
}}\
}
listPanel.noSelectionOrSort=Pas de sélection ou liste triée
listPanel.export=Export de la liste
listPanel.save=Sauver la liste
88,8 → 98,10
ilist.unlockRows=Déverrouiller les lignes
ilist.metadata={0,choice,0#Modifiée|1#Créée}{1,choice,0#|1# par {2} {3}}{4,choice,0#|1# le {5,date,long} à {5,time,medium}}
 
sqlComp.stringValueTooLong=La valeur fait {0} caractère{0,choice,1#|1<s} de trop
sqlComp.bdTooHigh=Nombre trop grand, il doit faire moins de {0} chiffre{0,choice,1#|1<s} avant la virgule ({1} après)
sqlComp.stringValueTooLong=La valeur fait {0, plural, one {# caractère de trop} other {# caractères de trop}}
sqlComp.bdTooHigh=Nombre trop grand, {0, plural,\
one {il doit faire moins d\u2019un chiffre avant la virgule ({1} après)}\
other {il doit faire moins de # chiffres avant la virgule ({1} après)}}
sqlComp.invalidItem={0} n''est pas valide{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} est vide
sqlComp.insertError=Impossible d''insérer
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_pl.properties
New file
0,0 → 1,198
init.error=Initialization error
add=Add
saveModifications=Save modifications
display=Display
modify=Modify
delete=Delete
remove=Remove
close=Close
cancel=Cancel
search=Search
open=Open
save=Save
backup=Backup
export=Export
noSelection=No selection
duplicate=Duplicate
duplication=Duplication
location=Location
choose=Choose
toApply=Apply
 
all=All
toReverse=Reverse
 
contains=Contains
contains.exactly=Contains exactly
isLessThan=Is less than
isLessThanOrEqualTo=Is less than or equal to
isEqualTo=Is equal to
isExactlyEqualTo=Is exactly equal to
isGreaterThan=Is greater than
isGreaterThanOrEqualTo=Is greater than or equal to
isEmpty=Is empty
 
clone.newPlace=New location (optional) :
 
saveError=Error while saving
 
loginPanel.storePass=Store password
loginPanel.loginAction=Log in
loginPanel.adminLogin=Administrator
loginPanel.loginLabel=Login
loginPanel.passLabel=Password
loginPanel.companyLabel=Company
loginPanel.disabledUser=Disabled user account
loginPanel.unknownUser=Unknown user
loginPanel.multipleUser=Multiple users named "{0}"
loginPanel.wrongPass=Wrong password
 
noRightToAdd=You''re not allowed to add
noRightToModify=You''re not allowed to modify
noRightToDel=You''re not allowed to delete
noRightToClone=You''re not allowed to duplicate
noRightToReorder=You''re not allowed to change order
 
editPanel.keepOpen=don''t close the window
editPanel.readOnlySelection=This row is read only
editPanel.localPrivateSelection=This row is used by another item
editPanel.inexistentElement=this item doesn't exist
editPanel.cancelError=Error while canceling
editPanel.modifyError=Error while modifying
editPanel.addError=Error while adding
editPanel.deleteError=Error while deleting
editPanel.invalidContent=Input fields aren''t filled correctly.\n\nYou cannot save modifications :
editPanel.invalidContent.unknownReason= they aren''t valid
 
editAction.name=Create {element__singularIndefiniteArticle}
editFrame.create=Create {element__singularIndefiniteArticle}
editFrame.modify=Modify {element__singularIndefiniteArticle}
editFrame.look=Details of {element__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html>
listPanel.cloneRows=Do you want to clone {rec, select,\
true {\
{rowCount, plural,\
one {this row and its content ?}\
other {these # rows and their content ?}\
}}\
other {\
{rowCount, plural,\
one {this row ?}\
other {these # rows ?}\
}}\
}
listPanel.clone.collectingData=Collecting data for {0,plural,one{# row} other{# rows}}\u2026
listPanel.clone.storingData=Storing {0,plural,one{# row} other{# rows}}\u2026
listPanel.noSelectionOrSort=No selection or list sorted
listPanel.export=List export
listPanel.save=Save the list
listPanel.wholeList=the whole list
listPanel.selection=the selection
listPanel.duplicationError=Couldn''t duplicate {0}
 
listAction.name=Manage {element__pluralDefiniteArticle}
element.list=List of {element__plural}
 
ilist.setColumnsWidth=Adjust columns widths
ilist.showAllColumns=Show all columns
ilist.lastCol=Cannot hide the last column
ilist.lockRows=Lock rows
ilist.unlockRows=Unlock rows
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}}
 
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}}
sqlComp.bdTooHigh=Number too high, {0, plural,\
one {it must have at most # digit before the decimal point ({1} after)}\
other {it must have at most # digits before the decimal point ({1} after)}}
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} is empty
sqlComp.insertError=Error while inserting
sqlComp.insertCancelled=Insertion cancelled
sqlComp.selectError=Error while displaying {0}
sqlComp.updateError=Error while updating
sqlComp.updateCancelled=Update cancelled
sqlComp.updateCancelled.archived=The row was archived
sqlComp.updateCancelled.moreArchivedRows=The database was modified (there are more rows to be archived)
sqlComp.rowsToArchiveError=Error while searching data to archive {0}
sqlComp.archiveError=Error while archiving
sqlComp.archiveCancelled=Archive cancelled
sqlComp.saveDocError=Error while saving documentation of {0}
sqlComp.modifyDoc=Modify the documentation
sqlComp.deletedRow=The row is no longer in the database : {0}
 
sqlElement.archive.computingRows=Computing rows to archive\u2026
sqlElement.archiveError=Error while archiving {0} IDs {1}
sqlElement.confirmDelete=Confirm deletion
sqlElement.deleteNoRef=Do you want to delete {rowCount, plural, one {this row} other {these # rows}} ?
sqlElement.deleteRef.details= {descsSize, plural, =0 {} other\
{{rowCount, plural, one {This row is used} other {These rows are used}} by :\n\
{descs}}}\
{externsSize, plural, =0 {} other {{descsSize, plural, =0 {The} other {\n\nFurther the}} following links will be IRRETRIEVABLY cut : \n\
{externs}}}\n\n
sqlElement.deleteRef.details2=The following links will be IRRETRIEVABLY cut, they couldn\u2019t be 'unarchived' :\n\
{externs}\n\n
sqlElement.deleteRef=Do you{times, select, once {} other { REALLY}} want to delete {rowCount, plural, one {this row} other {these # rows}} and all linked ones ?
sqlElement.noLinesDeleted=No lines deleted.
sqlElement.noLinesDeletedTitle=Information
sqlElement.linksWillBeCut=- {elementName__indefiniteNumeral} {count, plural, one {will lose its} other {will lose their}} "{linkName}"
sqlElement.linkCantBeCut={rowDesc} cannot lose its field "{fieldLabel}"
 
sqlElement.deletePrivateNoRef={elementName__indefiniteNumeral} {elementNameCount, plural, one {is to be deleted} other {are to be deleted}}.
 
sqlElement.deletePrivateRef.details=The removal of {elementName__indefiniteNumeral} will cause :\n\
{descsSize, plural, =0 {} other {{descs}\n}}\
{externs}
sqlElement.deletePrivateRef.desc=- the removal of {elementName__indefiniteNumeral}
sqlElement.deletePrivateRef.linksWillBeCut=- the permanent deletion of the field "{linkName}" for {elementName__indefiniteNumeral}
 
sqlElement.modify.deletePrivate=\n\nModify {elementName__singularDemonstrative} and delete the informations listed above ?
 
user.passwordsDontMatch=Passwords don\u2019t match
user.passwordsDontMatch.short=Passwords don\u2019t match
 
infoPanel.rights=Rights enabled
infoPanel.appName=Application name
infoPanel.noAppName=unknown
infoPanel.version=Application version
infoPanel.noVersion=unknown
infoPanel.secureLink=Secure link
infoPanel.dbURL=Database URL
infoPanel.dirs=Folders
infoPanel.logs=Logs
infoPanel.docs=Documents
infoPanel.dataDir=Data
infoPanel.prefsDir=Preferences
infoPanel.cacheDir=Cache
 
infoPanel.softwareTitle=Software
infoPanel.systemTitle=System information
infoPanel.refresh=Click to refresh
 
backupPanel.backup=Backup
backupPanel.createFolderError=Couldn't create destination folder. Backup canceled !
backupPanel.folderRightsError=Insufficient rights on destination folder. Backup canceled !
backupPanel.errorsOnLastBackup=Errors occurred on last backup. Please contact IT.
backupPanel.lastBackup=Last backup {date, date, long} at {date, time, short}\non {destination}
backupPanel.differentDisks=Please backup on different disks !
backupPanel.progress=Backup progress
backupPanel.inProgress=Backup in progress
backupPanel.closingIn=Closing in {0}s
backupPanel.endFail=Backup ended with errors !
backupPanel.endSuccess=Backup ended successfully
backupPanel.failed=Backup failed
 
rights=Rights
rightsPanel.defaultRights=Default rights
rights.allTables=All tables
 
combo.list=List {element__pluralDefiniteArticle}
 
joinComp.usedBy=Cannot delete selection, it is used by "{0}"
 
browserCol.content=Content of {element__pluralDefiniteArticle}
 
addNewLine=Add a new line
insertNewLine=Insert a line
duplicateLine=Duplicate selected lines
deleteLine=Remove selected lines
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_en.properties
69,7 → 69,18
editFrame.look=Details of {element__singularIndefiniteArticle}
 
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html>
listPanel.cloneRows=Do you want to clone {rowCount, plural, one {this row{rec, select, true { and its content} other {}}} other {these # rows{rec, select, true { and their contents} other {}}}} ?
listPanel.cloneRows=Do you want to clone {rec, select,\
true {\
{rowCount, plural,\
one {this row and its content ?}\
other {these # rows and their content ?}\
}}\
other {\
{rowCount, plural,\
one {this row ?}\
other {these # rows ?}\
}}\
}
listPanel.noSelectionOrSort=No selection or list sorted
listPanel.export=List export
listPanel.save=Save the list
87,8 → 98,10
ilist.unlockRows=Unlock rows
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}}
 
sqlComp.stringValueTooLong=The value is {0} character{0,choice,1#|1<s} too long
sqlComp.bdTooHigh=Number too high, it must have at most {0} digit{0,choice,1#|1<s} before the decimal point ({1} after)
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}}
sqlComp.bdTooHigh=Number too high, {0, plural,\
one {it must have at most # digit before the decimal point ({1} after)}\
other {it must have at most # digits before the decimal point ({1} after)}}
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})}
sqlComp.emptyItem={0} is empty
sqlComp.insertError=Error while inserting
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/MessageArgs.java
13,15 → 13,15
package org.openconcerto.utils.i18n;
 
import java.util.HashMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeSet;
 
import com.ibm.icu.text.MessageFormat;
 
import net.jcip.annotations.ThreadSafe;
 
import com.ibm.icu.text.MessageFormat;
 
/**
* {@link MessageFormat} can take numbered or named arguments, this class unifies both. This class
* is thread safe if the array or map isn't modified.
33,6 → 33,16
return m instanceof LinkedHashMap;
}
 
static private final MessageArgs EMPTY = new MessageArgs(new Object[0]);
 
public final static MessageArgs getEmpty() {
return EMPTY;
}
 
public final static MessageArgs create(final String key, final Object value) {
return new MessageArgs(Collections.singletonMap(key, value));
}
 
private final boolean mapPrimary;
private Object[] array;
private Map<String, ?> map;
82,12 → 92,16
protected synchronized Map<String, ?> getMap() {
if (this.map == null) {
final int stop = this.array.length;
final Map<String, Object> res = new HashMap<String, Object>(stop);
if (stop == 0) {
this.map = Collections.emptyMap();
} else {
final Map<String, Object> res = new LinkedHashMap<>(stop);
for (int i = 0; i < stop; i++) {
res.put(String.valueOf(i), this.array[i]);
}
this.map = res;
this.map = Collections.unmodifiableMap(res);
}
}
return this.map;
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Grammar_es.java
New file
0,0 → 1,123
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.i18n;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
 
import net.jcip.annotations.Immutable;
 
@Immutable
public class Grammar_es extends Grammar {
 
static private final Grammar_es INSTANCE = new Grammar_es();
 
public static Grammar_es getInstance() {
return INSTANCE;
}
 
private Grammar_es() {
this(Locale.forLanguageTag("es"));
}
 
protected Grammar_es(final Locale l) {
super(l);
}
 
@Override
protected Collection<? extends VariantKey> createVariantKeys() {
return Arrays.asList(SINGULAR, PLURAL, INDEFINITE_ARTICLE_SINGULAR, INDEFINITE_ARTICLE_PLURAL, DEFINITE_ARTICLE_SINGULAR, DEFINITE_ARTICLE_PLURAL, DEMONSTRATIVE_SINGULAR, DEMONSTRATIVE_PLURAL,
INDEFINITE_NUMERAL, DEFINITE_NUMERAL, DEMONSTRATIVE_NUMERAL, INDEFINITE_ORDINAL, DEFINITE_ORDINAL);
}
 
@Override
protected Collection<? extends NounClass> createNounClasses() {
return Arrays.asList(NounClass.FEMININE, NounClass.MASCULINE);
}
 
public final Phrase createPhrase(final String singular) {
return this.createPhrase(singular, null);
}
 
public final Phrase createPhrase(final String singular, final String plural) {
final Phrase res = new Phrase(this, singular, null);
if (plural != null)
res.putVariant(PLURAL, plural);
return res;
}
 
@Override
public String getVariant(Phrase noun, VariantKey key) {
final String res;
if (key.equals(SINGULAR)) {
res = noun.getBase();
} else if (key.equals(INDEFINITE_ARTICLE_SINGULAR)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "una " : "un ") + getSingular(noun);
} else if (key.equals(DEFINITE_ARTICLE_SINGULAR)) {
res = getDefiniteArticle(noun) + getSingular(noun);
} else if (key.equals(DEMONSTRATIVE_SINGULAR)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "esta " : "este ") + getSingular(noun);
} else if (key.equals(PLURAL)) {
res = getPlural(noun.getBase());
} else if (key.equals(INDEFINITE_ARTICLE_PLURAL)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "unas " : "unos ") + getPlural(noun);
} else if (key.equals(DEFINITE_ARTICLE_PLURAL)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "las " : "los ") + getPlural(noun);
} else if (key.equals(DEMONSTRATIVE_PLURAL)) {
res = (noun.getNounClass() == NounClass.FEMININE ? "estas " : "estos ") + getPlural(noun);
} else if (key.equals(INDEFINITE_NUMERAL)) {
res = "{0, plural, =0 {" + getZero(noun) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_NUMERAL)) {
res = "{0, plural, =0 {" + getZero(noun) + "} one {" + getVariant(noun, DEFINITE_ARTICLE_SINGULAR) + "} other {" + (noun.getNounClass() == NounClass.FEMININE ? "las " : "los ") + " # "
+ getPlural(noun) + "}}";
} else if (key.equals(DEMONSTRATIVE_NUMERAL)) {
res = "{0, plural, =0 {" + getZero(noun) + "} one {" + getVariant(noun, DEMONSTRATIVE_SINGULAR) + "} other {" + (noun.getNounClass() == NounClass.FEMININE ? "estas " : "estos ") + " # "
+ getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_ORDINAL) || key.equals(INDEFINITE_ORDINAL)) {
final boolean estFéminin = noun.getNounClass() == NounClass.FEMININE;
final String article = key.equals(DEFINITE_ORDINAL) ? (estFéminin ? "la " : "el ") : "";
res = article + "{0, ordinal, %digits-ordinal" + (estFéminin ? "-feminine" : "") + "} " + getSingular(noun);
} else {
res = null;
}
 
return res;
}
 
protected String getZero(Phrase noun) {
return (noun.getNounClass() == NounClass.MASCULINE ? "ningún " : "ninguna ") + noun.getBase();
}
 
protected String getDefiniteArticle(Phrase noun) {
if (noun.getNounClass() == NounClass.MASCULINE || noun.getBase().startsWith("a") || noun.getBase().startsWith("ha"))
return "el ";
else
return "la ";
}
 
protected String getSingular(Phrase noun) {
final String res = noun.getVariant(SINGULAR);
return res == null ? noun.getBase() : res;
}
 
protected String getPlural(Phrase noun) {
final String res = noun.getVariant(PLURAL);
return res == null ? getPlural(noun.getBase()) : res;
}
 
protected String getPlural(String noun) {
return noun + 's';
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Grammar_fr.java
84,11 → 84,11
} else if (key.equals(DEMONSTRATIVE_PLURAL)) {
res = "ces " + getPlural(noun);
} else if (key.equals(INDEFINITE_NUMERAL)) {
res = "{0, plural, =0 {auc" + getVariant(noun, INDEFINITE_ARTICLE_SINGULAR) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_NUMERAL)) {
res = "{0, plural, =0 {auc" + getVariant(noun, INDEFINITE_ARTICLE_SINGULAR) + "} one {" + getVariant(noun, DEFINITE_ARTICLE_SINGULAR) + "} other {les # " + getPlural(noun) + "}}";
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {" + noun.getVariant(DEFINITE_ARTICLE_SINGULAR) + "} other {les # " + getPlural(noun) + "}}";
} else if (key.equals(DEMONSTRATIVE_NUMERAL)) {
res = "{0, plural, =0 {auc" + getVariant(noun, INDEFINITE_ARTICLE_SINGULAR) + "} one {" + getVariant(noun, DEMONSTRATIVE_SINGULAR) + "} other {ces # " + getPlural(noun) + "}}";
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {" + noun.getVariant(DEMONSTRATIVE_SINGULAR) + "} other {ces # " + getPlural(noun) + "}}";
} else if (key.equals(DEFINITE_ORDINAL) || key.equals(INDEFINITE_ORDINAL)) {
final boolean estFéminin = noun.getNounClass() == NounClass.FEMININE;
final String article = key.equals(DEFINITE_ORDINAL) ? (estFéminin ? "la " : "le ") : "";
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_pl.properties
New file
0,0 → 1,29
true_key=prawdziwe
false_key=fa\u0142szywy
yes_key=tak
no_key=Nie
 
linkOpenError=Error while opening {0}
 
memory=pami\u0119ci
megabytes={0} MB
processors={0, plural, one { # procesora } other { # procesorów } }
os=Operating system
javaVersion=Version <b>{0}</b> of {1}
javaHome=installation directory
no.laf=No look and feel
 
user=u\u017Cytkownika
home.dir=home directory
cwd=current directory
 
network=Network
hardwareAddress=adres sprz\u0119towy
interfaceFullName=full name
interfaceState=state
interfaceStateUp=up
interfaceStateDown=down
 
cut=Wytnij
copy=Kopi\u0119
paste=Wklej
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_en.properties
7,7 → 7,7
 
memory=memory
megabytes={0} MB
processors={0} processor{0,choice,1#|1<s}
processors={0, plural, one { # processor } other { # processors } }
os=Operating system
javaVersion=Version <b>{0}</b> of {1}
javaHome=installation directory
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_fr.properties
7,7 → 7,7
 
memory=mémoire
megabytes={0} Mo
processors={0} processor{0,choice,1#|1<s}
processors={0, plural, one { # processeur } other { # processeurs } }
os=Système d''exploitation
javaVersion=Version <b>{0}</b> de {1}
javaHome=dossier d'installation
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/LocalizedInstances.java
14,6 → 14,7
package org.openconcerto.utils.i18n;
 
import org.openconcerto.utils.Log;
import org.openconcerto.utils.ReflectUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Value;
 
88,19 → 89,20
// test emptiness to not mix languages
for (Locale targetLocale = locale; targetLocale != null && l.isEmpty(); targetLocale = this.cntrl.getFallbackLocale(baseName, targetLocale)) {
localeRes = targetLocale;
// e.g. "fr_FR", "fr"
for (final Locale candidate : this.cntrl.getCandidateLocales(baseName, targetLocale)) {
// e.g. org.acme.MyClass_fr
final String bundleName = this.cntrl.toBundleName(baseName, candidate);
 
// code first
final Class<?> loadedClass = loadClass(bundleName, cl);
if (loadedClass != null && this.clazz.isAssignableFrom(loadedClass)) {
final Class<? extends T> subclazz = loadedClass.asSubclass(this.clazz);
final Class<? extends T> subclazz = ReflectUtils.getSubclass(bundleName, this.clazz, cl.getClassLoader());
if (subclazz != null) {
try {
final Value<? extends T> instance = this.getInstance(subclazz);
if (instance.hasValue())
l.add(instance.getValue());
else
Log.get().warning(loadedClass + " exists but the constructor wasn't found");
Log.get().warning(subclazz + " exists but the constructor wasn't found");
} catch (Exception e) {
Log.get().log(Level.WARNING, "Couldn't create an instance using " + subclazz, e);
}
118,14 → 120,6
return Tuple2.create(localeRes, l);
}
 
private final Class<?> loadClass(final String name, final Class<?> cl) {
try {
return Class.forName(name, true, cl.getClassLoader());
} catch (ClassNotFoundException e) {
return null;
}
}
 
/**
* The no-arg static method to use.
*
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/TM.java
21,6 → 21,7
import java.beans.Introspector;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
28,6 → 29,7
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
49,9 → 51,37
public class TM {
 
static public enum MissingMode {
EXCEPTION, NULL, STRING
EXCEPTION {
@Override
protected String returnMissing(TM tm, String key) throws MissingResourceException {
throw new MissingResourceException("Missing translation", tm.getBaseName(), key);
}
},
NULL {
@Override
protected String returnMissing(TM tm, String key) {
return null;
}
},
STRING {
@Override
protected String returnMissing(TM tm, String key) {
return '!' + key + '!';
}
};
 
protected abstract String returnMissing(final TM tm, final String key) throws MissingResourceException;
 
// method to avoid array allocation and Arrays.toString()
protected final String returnResult(final TM tm, final String res, final String key) throws MissingResourceException {
return res == null ? this.returnMissing(tm, key) : res;
}
 
protected final String returnResult(final TM tm, final String res, final String... keys) throws MissingResourceException {
return res == null ? this.returnMissing(tm, Arrays.toString(keys)) : res;
}
}
 
static public final String NOUN_CLASS_PROP = "nounClass";
static {
assert NOUN_CLASS_PROP.equals(Introspector.decapitalize(NounClass.class.getSimpleName()));
178,21 → 208,40
}
 
public final String translate(final MissingMode mode, final String key, final Object... args) throws MissingResourceException {
return translate(mode, key, new MessageArgs(args));
return translate(mode, key, args.length == 0 ? MessageArgs.getEmpty() : new MessageArgs(args));
}
 
public final String translateFirst(final MissingMode mode, final String... keys) throws MissingResourceException {
return translateFirst(mode, MessageArgs.getEmpty(), keys);
}
 
/**
* Return the first non-<code>null</code> result.
*
* @param mode what to do if all keys are <code>null</code>.
* @param args the arguments.
* @param keys the keys to search for.
* @return the first non-<code>null</code> result.
* @throws MissingResourceException if {@link MissingMode#EXCEPTION} and all keys are
* <code>null</code>.
*/
public final String translateFirst(final MissingMode mode, final MessageArgs args, final String... keys) throws MissingResourceException {
String res = null;
for (int i = 0; i < keys.length && res == null; i++) {
final String key = keys[i];
if (key != null)
res = this.translate(MissingMode.NULL, key, args);
}
return mode.returnResult(this, res, keys);
}
 
private final String translate(final MissingMode mode, final String key, MessageArgs args) throws MissingResourceException {
Objects.requireNonNull(mode, "Null mode");
Objects.requireNonNull(key, "Null key");
Objects.requireNonNull(args, "Null arguments");
final String res = this.translations.translate(key, args);
if (res == null) {
if (mode == MissingMode.STRING)
return '!' + key + '!';
else if (mode == MissingMode.NULL)
return null;
else
throw new MissingResourceException("Missing translation", this.getBaseName(), key);
return mode.returnResult(this, res, key);
}
return res;
}
 
protected MessageArgs replaceMap(final MessageArgs args, final String msg) {
final MessageArgs res;
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Grammar_pl.java
New file
0,0 → 1,55
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.i18n;
 
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
 
import net.jcip.annotations.Immutable;
 
@Immutable
public class Grammar_pl extends Grammar {
 
static private final Grammar_pl INSTANCE = new Grammar_pl();
 
public static Grammar_pl getInstance() {
return INSTANCE;
}
 
private Grammar_pl() {
this(Locale.forLanguageTag("pl"));
}
 
protected Grammar_pl(final Locale l) {
super(l);
}
 
@Override
protected Collection<? extends VariantKey> createVariantKeys() {
return Arrays.asList(SINGULAR, PLURAL, INDEFINITE_ARTICLE_SINGULAR, INDEFINITE_ARTICLE_PLURAL, DEFINITE_ARTICLE_SINGULAR, DEFINITE_ARTICLE_PLURAL, DEMONSTRATIVE_SINGULAR, DEMONSTRATIVE_PLURAL,
INDEFINITE_NUMERAL, DEFINITE_NUMERAL, DEMONSTRATIVE_NUMERAL, INDEFINITE_ORDINAL, DEFINITE_ORDINAL);
}
 
@Override
protected Collection<? extends NounClass> createNounClasses() {
return Arrays.asList(NounClass.FEMININE, NounClass.MASCULINE, NounClass.NEUTER);
}
 
@Override
public String getVariant(Phrase noun, VariantKey key) {
// TODO
return noun.getBase();
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/Phrase.java
18,17 → 18,18
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
 
import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.MessagePattern;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.MessagePattern;
 
/**
* A phrase and its declension. E.g. "light bulb or electrical outlet" and
* "light bulbs or electrical outlets".
* A phrase and its declension. E.g. "light bulb or electrical outlet" and "light bulbs or
* electrical outlets".
*
* @author Sylvain
* @see <a href="Wikipedia">http://en.wikipedia.org/wiki/Declension</a>
46,7 → 47,7
@GuardedBy("this")
private final Map<Object, String> variants;
@GuardedBy("this")
private final Set<Object> explicitVariants;
private final Set<VariantKey> explicitVariants;
 
public Phrase(Grammar grammar, String base, NounClass nounClass) {
super();
61,7 → 62,7
} else {
this.variants = new HashMap<Object, String>();
this.variants.put(null, this.getBase());
this.explicitVariants = new HashSet<Object>();
this.explicitVariants = new HashSet<>();
}
}
 
88,6 → 89,22
return this.putVariant(key, variant, true);
}
 
/**
* Put a variant only if needed, i.e. if {@link #getVariant(VariantKey)} doesn't already return
* <code>variant</code>. This is useful to keep {@link #getExplicitVariants()} to a minimum.
*
* @param key which variant, e.g. plural.
* @param variant the value, e.g. feet.
* @return <code>true</code> if the variant was put.
*/
public final synchronized boolean putVariantIfDifferent(final VariantKey key, final String variant) {
final boolean diff = !variant.equals(this.getVariant(key));
if (diff) {
this.putVariant(key, variant);
}
return diff;
}
 
private final synchronized String putVariant(final VariantKey key, final String variant, final boolean explicit) {
final String res = this.variants.put(key, variant);
if (explicit) {
99,6 → 116,16
}
 
/**
* The variants that have been explicitly set by {@link #putVariant(VariantKey, String)}, as
* opposed to variants computed automatically by the {@link #getGrammar() grammar}.
*
* @return all explicit variants.
*/
public synchronized Set<VariantKey> getExplicitVariants() {
return this.explicitVariants == null ? null : new HashSet<>(this.explicitVariants);
}
 
/**
* Get a variant. If the asked variant wasn't put by {@link #putVariant(VariantKey, String)},
* the {@link #getGrammar() grammar} is {@link Grammar#getVariant(Phrase, VariantKey) used}.
*
140,6 → 167,31
}
 
@Override
public synchronized int hashCode() {
return Objects.hash(this.base, this.explicitVariants, this.grammar, this.nounClass);
}
 
@Override
public synchronized boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Phrase o = (Phrase) obj;
final boolean fast = Objects.equals(this.base, o.base) && Objects.equals(this.explicitVariants, o.explicitVariants) && Objects.equals(this.grammar, o.grammar)
&& Objects.equals(this.nounClass, o.nounClass);
if (!fast || this.variants == null)
return fast;
for (final VariantKey e : this.explicitVariants) {
if (!Objects.equals(this.variants.get(e), o.variants.get(e)))
return false;
}
return true;
}
 
@Override
public String toString() {
final String cl = this.getNounClass() == null ? " " : " (" + this.getNounClass().getName() + ") ";
final String gr = this.getGrammar() == null ? "" : " with " + this.getGrammar();
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/MimeType.java
New file
0,0 → 1,205
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
/*
* Copyright 2007-2009 Medsea Business Solutions S.L.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.openconcerto.utils.mime;
 
import java.io.Serializable;
import java.util.regex.Pattern;
 
/**
* This class represents a simple MimeType object. A mime type is made up of two parts
* <code>&lt;media type&gt;/&lt;sub type&gt;</code>. The media type can be something like
* <code>application</code> or <code>text</code> and the the sub type can be something like
* <code>xml</code> or <code>plain</code>.
*
* Both the media type and sub type can also be the wild card <code>*</code> such as
* <code>*&#47;*</code> and <code>text&#47;*</code>. Note, if the media type is the wild card then
* the sub type must also be a wild card.
*
* @author Steven McArdle
*
*/
public class MimeType implements Serializable {
 
private static final long serialVersionUID = -1324243127744494894L;
 
private static final Pattern mimeSplitter = Pattern.compile("[/;]++");
 
protected String mediaType = "*";
protected String subType = "*";
 
// This is a estimate of how specific this mime type is
private int specificity = 1;
 
/**
* Construct a MimeType from another MimeType instance
*
* @param mimeType
*/
public MimeType(final MimeType mimeType) {
this.mediaType = mimeType.mediaType;
this.subType = mimeType.subType;
this.specificity = mimeType.specificity;
}
 
/**
* Construct a mime type from a String such as <code>text/plain</code>. It tries to ensure that
* the mime type pattern passed in is correctly formatted.
*
* @param mimeType
* @throws IllegalArgumentException
*/
public MimeType(final String mimeType) throws IllegalArgumentException {
if (mimeType == null || mimeType.trim().length() == 0) {
throw new IllegalArgumentException("Invalid MimeType [" + mimeType + "]");
}
String[] parts = mimeSplitter.split(mimeType.trim());
 
if (parts.length > 0) {
// Treat as the mediaType
mediaType = getValidMediaType(parts[0]);
}
if (parts.length > 1) {
subType = getValidSubType(parts[1]);
}
}
 
/**
* Get the media type part of the mime type.
*
* @return media type
*/
public String getMediaType() {
return mediaType;
}
 
/**
* Get the sub type of the mime type
*
* @return sub type
*/
public String getSubType() {
return subType;
}
 
/**
* See if this MimeType is the same as the passed in mime type string
*
* @param mimeType as a String
* @return true if the MimeType passed in has the same media and sub types, else returns false.
*/
private boolean match(final String mimeType) {
return toString().equals(mimeType);
}
 
/**
* Get the hashCode of this MimeType. The hashCode is calculate as (31 * mediaType.hashCode()) +
* subType.hashCode()
*
* @return calculated hashCode
* @see Object#hashCode()
*/
public int hashCode() {
return (31 * mediaType.hashCode()) + subType.hashCode();
}
 
/**
* Overrides the equals method of <code>java.lang.Object</code>. This is able to compare against
* another MimeType instance or a string representation of a mime type.
*
* @return true if the types match else false.
* @see Object#equals(Object o)
*/
public boolean equals(Object o) {
if (o instanceof MimeType) {
if (this.mediaType.equals(((MimeType) o).mediaType) && this.subType.equals(((MimeType) o).subType)) {
return true;
}
} else if (o instanceof String) {
return match((String) o);
}
return false;
}
 
/**
* Overrides the toString method of <code>java.lang.Object</code>.
*
* @return String representation i.e. <code>&lt;media type&gt;/&lt;sub type&gt;.
* @see Object#toString()
*/
public String toString() {
return mediaType + "/" + subType;
}
 
/**
* This indicates how specific the mime types is i.e. how good a match the mime type is when
* returned from the getMimeTypes(...) calls.
* <p>
* This is calculated by the number of times this MimeType would be returned if the Collection
* was not normalised. The higher the count the more MimeDetectors have matched this type. As
* this can be a false positive for types such as application/octect-stream and text/plain where
* they would be returned by multiple MimeDetector(s). These types are referred to as root mime
* types where ALL mime types derive from application/octet-stream and all text/* types derive
* from text/plan so in these cases we set the specificity to 0 no matter how many times they
* match. This ensures they are regarded as the least specific in the returned Collection.
* </p>
*
* @return how specific this MimeType is according to the rest of the MimeTypes in a Collection.
*/
public int getSpecificity() {
return specificity;
}
 
/*
* Set the value of the specificity. The higher the value the more specific a MimeType is.
*/
void setSpecificity(final int specificity) {
this.specificity = specificity;
}
 
/*
* Check the media type at least looks valid. TODO: Enforce more rigorous checking of valid
* media types.
*/
private String getValidMediaType(final String mediaType) {
if (mediaType == null || mediaType.trim().length() == 0) {
return "*";
}
return mediaType;
}
 
/*
* Check the sub type at least looks valid. TODO: Enforce more rigorous checking of valid sub
* types.
*/
private String getValidSubType(final String subType) {
if (subType == null || subType.trim().length() == 0 || "*".equals(mediaType)) {
// If the mediaType is a wild card then the sub type must also be a wild card
return "*";
}
return subType;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/mime.cache
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/mime.cache
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/FreeDesktopMimeDetector.java
New file
0,0 → 1,772
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.mime;
 
/*
* Copyright 2007-2009 Medsea Business Solutions S.L.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
 
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.Log;
import org.openconcerto.utils.OSFamily;
import org.openconcerto.utils.StreamUtils;
 
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.spi.FileTypeDetector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.regex.Pattern;
 
/**
* <p>
* The Opendesktop shared mime database contains glob rules and magic number lookup information to
* enable applications to detect the mime types of files.
* </p>
* <p>
* This class uses the mime.cache file which is one of the files created by the update-mime-database
* application. This file is a memory mapped file that enables the database to be updated and copied
* without interrupting applications.
* </p>
* <p>
* This implementation follows the memory mapped spec so it is not required to restart an
* application using this mime detector should the underlying mime.cache database change.
* </p>
* <p>
* For a complete description of the information contained in this file please see:
* http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
* </p>
* <p>
* This class also follows, where possible, the RECOMENDED order of detection as detailed in this
* spec. Thanks go to Mathias Clasen at Red Hat for pointing me to the original xdgmime
* implementation http://svn.gnome.org/viewvc/glib/trunk/
* gio/xdgmime/xdgmimecache.c?revision=7784&view=markup
* </p>
* More up to date : https://github.com/GNOME/beagle/blob/master/beagle/glue/xdgmime/xdgmimecache.c
*
* @author Steven McArdle
* @see <a
* href="http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html">Shared
* MIME-Info</a>
*/
@SuppressWarnings({ "unqualified-field-access" })
public class FreeDesktopMimeDetector extends FileTypeDetector {
 
public static enum Mode {
/**
* <a href=
* "http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html#idm140625828606432"
* >Recommended checking order</a>
*/
RECOMMENDED, DATA_ONLY, NAME_ONLY
}
 
public static final String DEFAULT_CACHE = "freeDesktop.mime.cache";
public static final String DEFAULT_MODE = "freeDesktop.mime.mode";
 
static private Mode getDefaultMode() {
final String m = System.getProperty(DEFAULT_MODE);
if (m != null) {
try {
return Mode.valueOf(m.toUpperCase());
} catch (Exception e) {
Log.get().log(Level.CONFIG, "Ignoring invalid mode : " + m, e);
}
}
return Mode.RECOMMENDED;
}
 
private static File mimeCacheFile = OSFamily.getInstance() == OSFamily.Windows ? null : new File("/usr/share/mime/mime.cache");
 
static private boolean canReadFile(final File f, final String msg) {
if (f == null)
return false;
final boolean res = f.isFile() && f.canRead();
if (!res)
Log.get().config(msg + f);
return res;
}
 
static private Object getDefaultCache() {
final String m = System.getProperty(DEFAULT_CACHE);
final File f = m != null ? new File(m) : null;
if (canReadFile(f, "Ignoring invalid passed file : ")) {
return f;
} else if (canReadFile(mimeCacheFile, "Ignoring invalid system file : ")) {
return mimeCacheFile;
} else {
final URL res = FreeDesktopMimeDetector.class.getResource("mime.cache");
if (res == null)
throw new IllegalStateException("No mime.cache found for " + FreeDesktopMimeDetector.class);
return res;
}
}
 
private final ByteBuffer content;
private final Mode mode;
 
public FreeDesktopMimeDetector() throws IOException {
this(getDefaultCache(), getDefaultMode());
}
 
public FreeDesktopMimeDetector(final File mimeCacheFile, final Mode mode) throws IOException {
this((Object) mimeCacheFile, mode);
}
 
public FreeDesktopMimeDetector(final InputStream is, final Mode mode) throws IOException {
this((Object) is, mode);
}
 
// InputStream will be closed
private FreeDesktopMimeDetector(final Object cache, final Mode mode) throws IOException {
if (cache instanceof File || cache instanceof FileInputStream) {
// Map the mime.cache file as a memory mapped file
try (final FileInputStream is = cache instanceof FileInputStream ? (FileInputStream) cache : new FileInputStream((File) cache); final FileChannel rCh = is.getChannel();) {
content = rCh.map(FileChannel.MapMode.READ_ONLY, 0, rCh.size());
}
} else {
final ByteArrayOutputStream out = new ByteArrayOutputStream(250 * 1024);
try (final InputStream is = cache instanceof URL ? ((URL) cache).openStream() : (InputStream) cache) {
StreamUtils.copy(is, out);
}
content = ByteBuffer.wrap(out.toByteArray());
}
this.mode = mode;
}
 
@Override
public String probeContentType(Path path) throws IOException {
final Collection<String> col;
switch (this.mode) {
case RECOMMENDED:
col = this.getMimeTypesFile(path.toFile());
break;
case DATA_ONLY:
try (final InputStream is = new BufferedInputStream(new FileInputStream(path.toFile()))) {
col = this.getMimeTypesInputStream(is);
}
break;
case NAME_ONLY:
col = this.getMimeTypesFileName(path.getFileName().toString());
break;
default:
throw new IllegalStateException("Unknown mode : " + this.mode);
}
return CollectionUtils.getFirst(col);
}
 
/**
* This method resolves mime types closely in accordance with the RECOMENDED order of detection
* detailed in the Opendesktop shared mime database specification
* http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html See
* the Recommended checking order.
*
* @param fileName the name to inspect.
* @return a collection of MIME types.
*/
public Collection<String> getMimeTypesFileName(String fileName) {
Collection<WeightedMimeType> mimeTypes = new ArrayList<WeightedMimeType>();
// Lookup the globbing methods first
lookupMimeTypesForGlobFileName(fileName, mimeTypes);
 
return normalizeWeightedMimeList(mimeTypes);
}
 
/**
* This method resolves mime types closely in accordance with the RECOMENDED order of detection
* detailed in the Opendesktop shared mime database specification
* http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html See
* the Recommended checking order.
*
* @param file the file to inspect.
* @return a collection of MIME types.
* @throws IOException if the file couldn't be read.
*/
public Collection<String> getMimeTypesFile(File file) throws IOException {
Collection<String> mimeTypes = getMimeTypesFileName(file.getName());
if (!file.exists()) {
return mimeTypes;
}
try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) {
return _getMimeTypes(mimeTypes, is);
}
}
 
/**
* This method is unable to perform glob matching as no name is available. This means that it
* does not follow the recommended order of detection defined in the shared mime database spec
* http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
*
* @param in the stream to inspect.s
* @return a collection of MIME types.
* @throws IOException if the stream couldn't be read.
*/
public Collection<String> getMimeTypesInputStream(InputStream in) throws IOException {
return lookupMimeTypesForMagicData(in);
}
 
/**
* This method is unable to perform glob matching as no name is available. This means that it
* does not follow the recommended order of detection defined in the shared mime database spec
* http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
*
* @param data the data to inspect.
* @return a collection of MIME types.
*/
public Collection<String> getMimeTypesByteArray(byte[] data) {
return lookupMagicData(data);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " using the mime.cache file version [" + getMajorVersion() + "." + getMinorVersion() + "].";
}
 
public String dump() {
return "{MAJOR_VERSION=" + getMajorVersion() + " MINOR_VERSION=" + getMinorVersion() + " ALIAS_LIST_OFFSET=" + getAliasListOffset() + " PARENT_LIST_OFFSET=" + getParentListOffset()
+ " LITERAL_LIST_OFFSET=" + getLiteralListOffset() + " REVERSE_SUFFIX_TREE_OFFSET=" + getReverseSuffixTreeOffset() + " GLOB_LIST_OFFSET=" + getGlobListOffset() + " MAGIC_LIST_OFFSET="
+ getMagicListOffset() + " NAMESPACE_LIST_OFFSET=" + getNameSpaceListOffset() + " ICONS_LIST_OFFSET=" + getIconListOffset() + " GENERIC_ICONS_LIST_OFFSET="
+ getGenericIconListOffset() + "}";
}
 
private Collection<String> lookupMimeTypesForMagicData(InputStream in) throws IOException {
int offset = 0;
int len = getMaxExtents();
byte[] data = new byte[len];
// Mark the input stream
in.mark(len);
 
try {
// Since an InputStream might return only some data (not all
// requested), we have to read in a loop until
// either EOF is reached or the desired number of bytes have been
// read.
int restBytesToRead = len;
while (restBytesToRead > 0) {
int bytesRead = in.read(data, offset, restBytesToRead);
if (bytesRead < 0)
break; // EOF
 
offset += bytesRead;
restBytesToRead -= bytesRead;
}
} finally {
// Reset the input stream to where it was marked.
in.reset();
}
return lookupMagicData(data);
}
 
private Collection<String> lookupMagicData(byte[] data) {
 
Collection<String> mimeTypes = new ArrayList<String>();
 
int listOffset = getMagicListOffset();
int numEntries = content.getInt(listOffset);
int offset = content.getInt(listOffset + 8);
 
for (int i = 0; i < numEntries; i++) {
final int matchOffset = offset + (16 * i);
final String mimeType = compareToMagicData(matchOffset, data);
if (mimeType != null) {
mimeTypes.add(mimeType);
} else {
final String nonMatch = getMimeType(content.getInt(matchOffset + 4));
mimeTypes.remove(nonMatch);
}
}
 
return mimeTypes;
}
 
private String compareToMagicData(int offset, byte[] data) {
// TODO
// int priority = content.getInt(offset);
int mimeOffset = content.getInt(offset + 4);
int numMatches = content.getInt(offset + 8);
int matchletOffset = content.getInt(offset + 12);
 
for (int i = 0; i < numMatches; i++) {
if (matchletMagicCompare(matchletOffset + (i * 32), data)) {
return getMimeType(mimeOffset);
}
}
return null;
}
 
private boolean matchletMagicCompare(int offset, byte[] data) {
int n_children = content.getInt(offset + 24);
int child_offset = content.getInt(offset + 28);
 
if (magic_matchlet_compare_to_data(offset, data)) {
if (n_children == 0)
return true;
 
for (int i = 0; i < n_children; i++) {
if (matchletMagicCompare(child_offset + 32 * i, data))
return true;
}
}
 
return false;
}
 
private boolean magic_matchlet_compare_to_data(int offset, byte[] data) {
int rangeStart = content.getInt(offset);
int rangeLength = content.getInt(offset + 4);
int dataLength = content.getInt(offset + 12);
int dataOffset = content.getInt(offset + 16);
int maskOffset = content.getInt(offset + 20);
 
for (int i = rangeStart; i <= rangeStart + rangeLength; i++) {
boolean validMatch = true;
if (i + dataLength > data.length) {
return false;
}
if (maskOffset != 0) {
for (int j = 0; j < dataLength; j++) {
if ((content.get(dataOffset + j) & content.get(maskOffset + j)) != (data[j + i] & content.get(maskOffset + j))) {
validMatch = false;
break;
}
}
} else {
for (int j = 0; j < dataLength; j++) {
if (content.get(dataOffset + j) != data[j + i]) {
validMatch = false;
break;
}
}
}
 
if (validMatch) {
return true;
}
}
return false;
}
 
private void lookupGlobLiteral(String fileName, Collection<WeightedMimeType> mimeTypes) {
int listOffset = getLiteralListOffset();
int numEntries = content.getInt(listOffset);
 
int min = 0;
int max = numEntries - 1;
while (max >= min) {
int mid = (min + max) / 2;
String literal = getString(content.getInt((listOffset + 4) + (12 * mid)));
int cmp = literal.compareTo(fileName);
if (cmp < 0) {
min = mid + 1;
} else if (cmp > 0) {
max = mid - 1;
} else {
String mimeType = getMimeType(content.getInt((listOffset + 4) + (12 * mid) + 4));
int weight = content.getInt((listOffset + 4) + (12 * mid) + 8);
mimeTypes.add(new WeightedMimeType(mimeType, literal, weight));
return;
}
}
}
 
private void lookupGlobFileNameMatch(String fileName, Collection<WeightedMimeType> mimeTypes) {
final int listOffset = getGlobListOffset();
final int numEntries = content.getInt(listOffset);
final int entriesOffset = listOffset + 4;
 
for (int i = 0; i < numEntries; i++) {
final int entryOffset = entriesOffset + 12 * 1;
final int offset = content.getInt(entryOffset);
final int mimeTypeOffset = content.getInt(entryOffset + 4);
final int weightNFlags = content.getInt(entryOffset + 8);
final int weight = weightNFlags & 0xFF;
final boolean cs = (weightNFlags & 0x100) != 0;
 
final Pattern pattern = Pattern.compile(getString(offset, true), !cs ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
if (pattern.matcher(fileName).matches()) {
final String mimeType = getMimeType(mimeTypeOffset);
final String globPattern = getString(offset, false);
mimeTypes.add(new WeightedMimeType(mimeType, globPattern, weight));
}
}
}
 
private Collection<String> normalizeWeightedMimeList(Collection<WeightedMimeType> weightedMimeTypes) {
if (weightedMimeTypes.isEmpty())
return Collections.emptySet();
Collection<WeightedMimeType> mimeTypes = new LinkedHashSet<WeightedMimeType>();
 
// Sort the weightedMimeTypes
Collections.sort((List<WeightedMimeType>) weightedMimeTypes, new Comparator<WeightedMimeType>() {
public int compare(WeightedMimeType obj1, WeightedMimeType obj2) {
return obj1.weight - obj2.weight;
}
});
 
// Keep only globs with the biggest weight. They are in weight order at
// this point
int weight = 0;
int patternLen = 0;
for (final WeightedMimeType mw : weightedMimeTypes) {
if (weight < mw.weight) {
weight = mw.weight;
}
if (weight >= mw.weight) {
if (mw.pattern.length() > patternLen) {
patternLen = mw.pattern.length();
}
mimeTypes.add(mw);
}
}
 
// Now keep only the longest patterns
for (final WeightedMimeType mw : weightedMimeTypes) {
if (mw.pattern.length() < patternLen) {
mimeTypes.remove(mw);
}
}
 
// Could possibly have multiple mimeTypes here with the same weight and
// pattern length. Can even have multiple entries for the same type so
// lets remove
// any duplicates by copying entries to a HashSet that can only have a
// single instance
// of each type
Collection<String> _mimeTypes = new HashSet<String>();
for (final WeightedMimeType mw : mimeTypes) {
_mimeTypes.add(mw.toString());
}
return _mimeTypes;
}
 
private void lookupMimeTypesForGlobFileName(String fileName, Collection<WeightedMimeType> mimeTypes) {
if (fileName == null) {
return;
}
 
lookupGlobLiteral(fileName, mimeTypes);
if (!mimeTypes.isEmpty()) {
return;
}
 
int len = fileName.length();
lookupGlobSuffix(fileName, false, len, mimeTypes);
if (mimeTypes.isEmpty()) {
lookupGlobSuffix(fileName, true, len, mimeTypes);
}
 
if (mimeTypes.isEmpty()) {
lookupGlobFileNameMatch(fileName, mimeTypes);
}
}
 
private void lookupGlobSuffix(String fileName, boolean ignoreCase, int len, Collection<WeightedMimeType> mimeTypes) {
int listOffset = getReverseSuffixTreeOffset();
int numEntries = content.getInt(listOffset);
int offset = content.getInt(listOffset + 4);
 
lookupGlobNodeSuffix(fileName, numEntries, offset, ignoreCase, len, mimeTypes, new StringBuffer());
}
 
private void lookupGlobNodeSuffix(final String fileName, final int numEntries, final int offset, final boolean ignoreCase, int len, Collection<WeightedMimeType> mimeTypes, StringBuffer pattern) {
final char character = ignoreCase ? fileName.toLowerCase().charAt(len - 1) : fileName.charAt(len - 1);
 
if (character == 0) {
return;
}
 
int min = 0;
int max = numEntries - 1;
while (max >= min && len >= 0) {
int mid = (min + max) / 2;
 
char matchChar = (char) content.getInt(offset + (12 * mid));
if (ignoreCase)
matchChar = Character.toLowerCase(matchChar);
if (matchChar < character) {
min = mid + 1;
} else if (matchChar > character) {
max = mid - 1;
} else {
len--;
// first leaf nodes (matchChar==0) then tree nodes
final int numChildren = content.getInt(offset + (12 * mid) + 4);
final int firstChildOffset = content.getInt(offset + (12 * mid) + 8);
if (len > 0) {
pattern.append(matchChar);
lookupGlobNodeSuffix(fileName, numChildren, firstChildOffset, ignoreCase, len, mimeTypes, pattern);
}
// if the name did not match a longer pattern, try to match this one
if (mimeTypes.isEmpty()) {
for (int i = 0; i < numChildren; i++) {
final int childOffset = firstChildOffset + (12 * i);
if (content.getInt(childOffset) != 0) {
// not a leaf node anymore
break;
}
 
final int mimeOffset = content.getInt(childOffset + 4);
final int weightNFlags = content.getInt(childOffset + 8);
final int weight = weightNFlags & 0xFF;
final boolean cs = (weightNFlags & 0x100) != 0;
 
if (!(cs && ignoreCase))
mimeTypes.add(new WeightedMimeType(getMimeType(mimeOffset), pattern.toString(), weight));
}
}
return;
}
}
}
 
static class WeightedMimeType extends MimeType {
 
private static final long serialVersionUID = 1L;
String pattern;
int weight;
 
WeightedMimeType(String mimeType, String pattern, int weight) {
super(mimeType);
this.pattern = pattern;
this.weight = weight;
}
}
 
private int getMaxExtents() {
return content.getInt(getMagicListOffset() + 4);
}
 
private String aliasLookup(String alias) {
int aliasListOffset = getAliasListOffset();
int min = 0;
int max = content.getInt(aliasListOffset) - 1;
 
while (max >= min) {
int mid = (min + max) / 2;
// content.position((aliasListOffset + 4) + (mid * 8));
 
int aliasOffset = content.getInt((aliasListOffset + 4) + (mid * 8));
int mimeOffset = content.getInt((aliasListOffset + 4) + (mid * 8) + 4);
 
int cmp = getMimeType(aliasOffset).compareTo(alias);
if (cmp < 0) {
min = mid + 1;
} else if (cmp > 0) {
max = mid - 1;
} else {
return getMimeType(mimeOffset);
}
}
return null;
}
 
private String unaliasMimeType(String mimeType) {
String lookup = aliasLookup(mimeType);
return lookup == null ? mimeType : lookup;
}
 
private boolean isMimeTypeSubclass(String mimeType, String subClass) {
String umimeType = unaliasMimeType(mimeType);
String usubClass = unaliasMimeType(subClass);
MimeType _mimeType = new MimeType(umimeType);
MimeType _subClass = new MimeType(usubClass);
 
if (umimeType.compareTo(usubClass) == 0) {
return true;
}
 
if (isSuperType(usubClass) && (_mimeType.getMediaType().equals(_subClass.getMediaType()))) {
return true;
}
 
// Handle special cases text/plain and application/octet-stream
if (usubClass.equals("text/plain") && _mimeType.getMediaType().equals("text")) {
return true;
}
 
if (usubClass.equals("application/octet-stream")) {
return true;
}
int parentListOffset = getParentListOffset();
int numParents = content.getInt(parentListOffset);
int min = 0;
int max = numParents - 1;
while (max >= min) {
int med = (min + max) / 2;
int offset = content.getInt((parentListOffset + 4) + (8 * med));
String parentMime = getMimeType(offset);
int cmp = parentMime.compareTo(umimeType);
if (cmp < 0) {
min = med + 1;
} else if (cmp > 0) {
max = med - 1;
} else {
offset = content.getInt((parentListOffset + 4) + (8 * med) + 4);
int _numParents = content.getInt(offset);
for (int i = 0; i < _numParents; i++) {
int parentOffset = content.getInt((offset + 4) + (4 * i));
if (isMimeTypeSubclass(getMimeType(parentOffset), usubClass)) {
return true;
}
}
break;
}
}
return false;
}
 
private boolean isSuperType(String mimeType) {
return mimeType.endsWith("/*");
}
 
private int getGenericIconListOffset() {
return content.getInt(36);
}
 
private int getIconListOffset() {
return content.getInt(32);
}
 
private int getNameSpaceListOffset() {
return content.getInt(28);
}
 
private int getMagicListOffset() {
return content.getInt(24);
}
 
private int getGlobListOffset() {
return content.getInt(20);
}
 
private int getReverseSuffixTreeOffset() {
return content.getInt(16);
}
 
private int getLiteralListOffset() {
return content.getInt(12);
}
 
private int getParentListOffset() {
return content.getInt(8);
}
 
private int getAliasListOffset() {
return content.getInt(4);
}
 
private short getMinorVersion() {
return content.getShort(2);
}
 
private short getMajorVersion() {
return content.getShort(0);
}
 
private String getMimeType(int offset) {
return getString(offset);
}
 
private String getString(int offset) {
return getString(offset, false);
}
 
private String getString(int offset, boolean regularExpression) {
int position = content.position();
content.position(offset);
StringBuffer buf = new StringBuffer();
char c = 0;
while ((c = (char) content.get()) != 0) {
if (regularExpression) {
switch (c) {
case '.':
buf.append("\\");
break;
case '*':
case '+':
case '?':
buf.append(".");
}
}
buf.append(c);
}
// Reset position
content.position(position);
 
if (regularExpression) {
buf.insert(0, '^');
buf.append('$');
}
return buf.toString();
}
 
private Collection<String> _getMimeTypes(Collection<String> mimeTypes, final InputStream in) throws IOException {
if (mimeTypes.isEmpty() || mimeTypes.size() > 1) {
Collection<String> _mimeTypes = getMimeTypesInputStream(in);
 
if (!_mimeTypes.isEmpty()) {
if (!mimeTypes.isEmpty()) {
// more than one glob matched
 
// Check for same mime type
for (final String mimeType : mimeTypes) {
if (_mimeTypes.contains(mimeType)) {
// mimeTypes = new ArrayList();
mimeTypes.add(mimeType);
// return mimeTypes;
}
// Check for mime type subtype
for (final String _mimeType : _mimeTypes) {
if (isMimeTypeSubclass(mimeType, _mimeType)) {
// mimeTypes = new ArrayList();
mimeTypes.add(mimeType);
// return mimeTypes;
}
}
}
} else {
// No globs matched but we have magic matches
return _mimeTypes;
}
}
}
 
return mimeTypes;
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/File.java
New file
0,0 → 1,35
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.mime;
 
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
 
public class File {
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.out.println(File.class.getName() + " file...");
System.out.println("Allow to find the MIME type of files");
System.out.println("The '" + FreeDesktopMimeDetector.DEFAULT_MODE + "' property can be set to " + Arrays.asList(FreeDesktopMimeDetector.Mode.values()));
System.out.println("\tthe default is the first one, see http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html#idm140625828606432");
System.exit(1);
}
for (final String f : args) {
final Path p = Paths.get(f);
System.out.println(f + '\t' + new FreeDesktopMimeDetector().probeContentType(p));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/mime/FileMagicMimeDetector.java
New file
0,0 → 1,39
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.mime;
 
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.spi.FileTypeDetector;
 
/**
* <p>
* The <a
* href="http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html"
* >freedesktop Shared MIME-Info</a> only contains basic magic support. In particular it misses
* indirect offset and calculations that <a href="http://www.darwinsys.com/file">file</a> supports.
* For example these features are needed for <a
* href="https://github.com/file/file/blob/master/magic/Magdir/msooxml">MS OOXML</a>.
* </p>
*
* @see <a href="https://github.com/file/file/blob/master/doc/magic.man">Magic Format</a>
*/
public class FileMagicMimeDetector extends FileTypeDetector {
 
@Override
public String probeContentType(Path path) throws IOException {
throw new UnsupportedOperationException();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CompareUtils.java
312,4 → 312,12
}
return null;
}
 
static public final <T extends Comparable<? super T>> T min(final T o1, final T o2) {
return o1.compareTo(o2) < 0 ? o1 : o2;
}
 
static public final <T extends Comparable<? super T>> T max(final T o1, final T o2) {
return o1.compareTo(o2) < 0 ? o2 : o1;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/StreamUtils.java
13,11 → 13,9
package org.openconcerto.utils;
 
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
24,6 → 22,9
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.logging.Level;
 
public class StreamUtils {
 
48,6 → 49,7
* @throws IOException if an error occurs while reading or writing.
*/
public static void copy(InputStream in, OutputStream out) throws IOException {
// TODO use in.transferTo(out) in Java 9
copy(in, out, 512 * 1024);
}
 
56,6 → 58,8
}
 
public static long copy(InputStream in, OutputStream out, final int bufferSize, final long length) throws IOException {
if (bufferSize < 1)
throw new IllegalArgumentException("Buffer size too small : " + bufferSize);
final byte[] buffer = new byte[bufferSize];
long totalCount = 0;
final boolean copyAll = length < 0;
62,10 → 66,14
while (copyAll || totalCount < length) {
final long toRead = copyAll ? buffer.length : Math.min(length - totalCount, buffer.length);
// since buffer.length is an int
assert 0 <= toRead && toRead <= Integer.MAX_VALUE;
assert 0 < toRead && toRead <= Integer.MAX_VALUE;
final int count = in.read(buffer, 0, (int) toRead);
if (count == -1)
if (count <= 0) {
// like Files.copy(InputStream, OutputStream), stop if reading 0 bytes
if (count == 0)
Log.get().log(Level.WARNING, "", new IllegalStateException("read() returned 0 for " + in));
break;
}
totalCount += count;
out.write(buffer, 0, count);
}
75,14 → 83,8
}
 
public static void copy(InputStream ins, File out) throws IOException {
// buffered since read() in copy(InputStream, OutputStream) may return 1 byte at a time
final OutputStream ous = new BufferedOutputStream(new FileOutputStream(out));
try {
copy(ins, ous);
} finally {
ous.close();
Files.copy(ins, out.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
 
/**
* Read until the end of the stream is reached. NOTE : since this method didn't create the
/trunk/OpenConcerto/src/org/openconcerto/utils/ProcessStreams.java
19,6 → 19,7
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.ProcessBuilder.Redirect;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
35,6 → 36,10
static public enum Action {
/**
* Redirect process streams to ours.
*
* @deprecated use {@link ProcessStreams#redirect(ProcessBuilder)} (or
* {@link Redirect#INHERIT} directly) as it makes sure that
* {@link Process#waitFor()} only returns once all streams are flushed.
*/
REDIRECT,
/**
52,6 → 57,10
DO_NOTHING
}
 
static public final ProcessBuilder redirect(final ProcessBuilder pb) throws IOException {
return pb.redirectErrorStream(true).redirectOutput(Redirect.INHERIT);
}
 
static public final Process handle(final Process p, final Action action) throws IOException {
if (action == Action.CLOSE) {
p.getInputStream().close();
/trunk/OpenConcerto/src/org/openconcerto/utils/TableSorter.java
37,6 → 37,8
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
45,6 → 47,8
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
 
import net.jcip.annotations.Immutable;
 
/**
* TableSorter is a decorator for TableModels; adding sorting functionality to a supplied
* TableModel. TableSorter does not store or copy the data in its TableModel; instead it maintains a
51,16 → 55,18
* map from the row indexes of the view to the row indexes of the model. As requests are made of the
* sorter (like getValueAt(row, col)) they are passed to the underlying model after the row numbers
* have been translated via the internal mapping array. This way, the TableSorter appears to hold
* another copy of the table with the rows in a different order. <p/>TableSorter registers itself as
* a listener to the underlying model, just as the JTable itself would. Events recieved from the
* model are examined, sometimes manipulated (typically widened), and then passed on to the
* TableSorter's listeners (typically the JTable). If a change to the model has invalidated the
* order of TableSorter's rows, a note of this is made and the sorter will resort the rows the next
* time a value is requested. <p/>When the tableHeader property is set, either by using the
* setTableHeader() method or the two argument constructor, the table header may be used as a
* complete UI for TableSorter. The default renderer of the tableHeader is decorated with a renderer
* that indicates the sorting status of each column. In addition, a mouse listener is installed with
* the following behavior:
* another copy of the table with the rows in a different order.
* <p/>
* TableSorter registers itself as a listener to the underlying model, just as the JTable itself
* would. Events recieved from the model are examined, sometimes manipulated (typically widened),
* and then passed on to the TableSorter's listeners (typically the JTable). If a change to the
* model has invalidated the order of TableSorter's rows, a note of this is made and the sorter will
* resort the rows the next time a value is requested.
* <p/>
* When the tableHeader property is set, either by using the setTableHeader() method or the two
* argument constructor, the table header may be used as a complete UI for TableSorter. The default
* renderer of the tableHeader is decorated with a renderer that indicates the sorting status of
* each column. In addition, a mouse listener is installed with the following behavior:
* <ul>
* <li>Mouse-click: Clears the sorting status of all other columns and advances the sorting status
* of that column through three values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to NOT_SORTED
72,8 → 78,9
* column do not cancel the statuses of columns that are already sorting - giving a way to initiate
* a compound sort.
* </ul>
* <p/>This is a long overdue rewrite of a class of the same name that first appeared in the swing
* table demos in 1997.
* <p/>
* This is a long overdue rewrite of a class of the same name that first appeared in the swing table
* demos in 1997.
*
* @author Philip Milne
* @author Brendon McLean
92,11 → 99,13
private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
 
public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((Comparable) o1).compareTo(o2);
}
};
public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
public static final Comparator<Object> LEXICAL_COMPARATOR = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
108,8 → 117,8
private JTableHeader tableHeader;
private MouseListener mouseListener;
private TableModelListener tableModelListener;
private Map columnComparators = new HashMap();
private List sortingColumns = new ArrayList();
private Map<Class<?>, Comparator<?>> columnComparators = new HashMap<>();
private final List<Directive> sortingColumns = new ArrayList<>();
 
private boolean enabled;
private boolean sorting;
144,6 → 153,9
}
 
public void setTableModel(TableModel tableModel) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (this.tableModel != null) {
this.tableModel.removeTableModelListener(tableModelListener);
}
188,6 → 200,9
}
 
public void setTableHeader(JTableHeader tableHeader) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (this.tableHeader != null) {
this.tableHeader.removeMouseListener(mouseListener);
TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
207,9 → 222,22
return sortingColumns.size() != 0;
}
 
public final List<Directive> getSortingColumns() {
return Collections.unmodifiableList(this.sortingColumns);
}
 
public void setSortingColumns(List<Directive> sortingColumns) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
this.sortingColumns.clear();
this.sortingColumns.addAll(sortingColumns);
sortingStatusChanged();
}
 
private Directive getDirective(int column) {
for (int i = 0; i < sortingColumns.size(); i++) {
Directive directive = (Directive) sortingColumns.get(i);
Directive directive = sortingColumns.get(i);
if (directive.column == column) {
return directive;
}
234,6 → 262,9
}
 
private synchronized void sortingStatusChanged() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
this.sortingStatusChanged(true);
}
 
271,7 → 302,7
sortingStatusChanged(fire);
}
 
public void setColumnComparator(Class type, Comparator comparator) {
public void setColumnComparator(Class<?> type, Comparator<?> comparator) {
if (comparator == null) {
columnComparators.remove(type);
} else {
280,8 → 311,8
}
 
protected Comparator getComparator(int column) {
Class columnType = tableModel.getColumnClass(column);
Comparator comparator = (Comparator) columnComparators.get(columnType);
Class<?> columnType = tableModel.getColumnClass(column);
Comparator<?> comparator = columnComparators.get(columnType);
if (comparator != null) {
return comparator;
}
292,6 → 323,9
}
 
private Row[] getViewToModel() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (viewToModel == null) {
int tableModelRowCount = tableModel.getRowCount();
viewToModel = new Row[tableModelRowCount];
318,6 → 352,9
}
 
private int[] getModelToView() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
if (modelToView == null) {
int n = getViewToModel().length;
modelToView = new int[n];
334,31 → 371,50
 
// TableModel interface methods
 
@Override
public int getRowCount() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
return (tableModel == null) ? 0 : tableModel.getRowCount();
}
 
@Override
public int getColumnCount() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
return (tableModel == null) ? 0 : tableModel.getColumnCount();
}
 
@Override
public String getColumnName(int column) {
return tableModel.getColumnName(column);
}
 
public Class getColumnClass(int column) {
@Override
public Class<?> getColumnClass(int column) {
return tableModel.getColumnClass(column);
}
 
@Override
public boolean isCellEditable(int row, int column) {
return tableModel.isCellEditable(modelIndex(row), column);
}
 
@Override
public Object getValueAt(int row, int column) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
return tableModel.getValueAt(modelIndex(row), column);
}
 
@Override
public void setValueAt(Object aValue, int row, int column) {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("must be called from EDT");
}
tableModel.setValueAt(aValue, modelIndex(row), column);
}
 
376,7 → 432,7
 
// Helper classes
 
private class Row implements Comparable {
private class Row implements Comparable<Row> {
private int modelIndex;
 
public Row(int index) {
383,12 → 439,13
this.modelIndex = index;
}
 
public int compareTo(Object o) {
@Override
public int compareTo(Row o) {
int row1 = modelIndex;
int row2 = ((Row) o).modelIndex;
int row2 = o.modelIndex;
 
for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
Directive directive = (Directive) it.next();
for (Iterator<Directive> it = sortingColumns.iterator(); it.hasNext();) {
Directive directive = it.next();
int column = directive.column;
Object o1 = tableModel.getValueAt(row1, column);
Object o2 = tableModel.getValueAt(row2, column);
413,6 → 470,7
}
 
private class TableModelHandler implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
// If we're not sorting by anything, just pass the event along.
if (!isSorting()) {
487,6 → 545,7
}
 
private class MouseHandler extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
JTableHeader h = (JTableHeader) e.getSource();
TableColumnModel columnModel = h.getColumnModel();
523,6 → 582,7
this.priority = priority;
}
 
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
Color color = c == null ? Color.GRAY : c.getBackground();
// In a compound sort, make each succesive triangle 20%
556,10 → 616,12
g.translate(-x, -y);
}
 
@Override
public int getIconWidth() {
return size;
}
 
@Override
public int getIconHeight() {
return size;
}
572,11 → 634,12
this.tableCellRenderer = tableCellRenderer;
}
 
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = tableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
l.setHorizontalTextPosition(JLabel.LEFT);
l.setHorizontalTextPosition(SwingConstants.LEFT);
int modelColumn = table.convertColumnIndexToModel(column);
l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));
}
584,13 → 647,27
}
}
 
private static class Directive {
private int column;
private int direction;
@Immutable
public static class Directive {
private final int column;
private final int direction;
 
public Directive(int column, int direction) {
this.column = column;
this.direction = direction;
}
 
public final int getColumn() {
return this.column;
}
 
public final int getDirection() {
return this.direction;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + this.getDirection() + " on column " + this.getColumn();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/FileUtils.java
38,6 → 38,7
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryStream;
import java.nio.file.DirectoryStream.Filter;
97,6 → 98,9
}
 
public static void openFile(File f) throws IOException {
if (!f.exists()) {
throw new FileNotFoundException(f.getAbsolutePath() + " not found");
}
if (Desktop.isDesktopSupported()) {
Desktop d = Desktop.getDesktop();
if (d.isSupported(Desktop.Action.OPEN)) {
616,6 → 620,10
return readUTF8(new FileInputStream(f));
}
 
public static final String readUTF8(Path p) throws IOException {
return new String(Files.readAllBytes(p), StandardCharsets.UTF_8);
}
 
public static final String readUTF8(InputStream ins) throws IOException {
return read(ins, StringUtils.UTF8);
}
900,6 → 908,9
* @throws IOException if the file can't be opened.
*/
public static final void open(File f, String[] executables) throws IOException {
if (!f.exists()) {
throw new FileNotFoundException(f.getAbsolutePath() + " not found");
}
try {
openNative(f);
} catch (IOException exn) {
/trunk/OpenConcerto/src/org/openconcerto/utils/ReflectUtils.java
13,6 → 13,7
package org.openconcerto.utils;
 
import java.beans.Expression;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericArrayType;
29,7 → 30,10
public final class ReflectUtils {
 
/**
* Find a constructor with compatible parameters.
* Find a constructor with compatible parameters. NOTE: This follow a simpler algorithm than the
* one in the JLS (<a href=
* "https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2.5">15.12.2.5.
* Choosing the Most Specific Method</a>).
*
* @param cls the class to find a constructor for, not <code>null</code>.
* @param parameterTypes types of parameters the constructor must accept.
58,6 → 62,35
}
}
 
@SuppressWarnings("unchecked")
static public final <T> T createInstance(final Class<T> clazz, Object... args) throws Exception {
// too difficult to order superclasses and all implemented interfaces of args in order to
// find the most specific constructor
return (T) new Expression(clazz, "new", args).getValue();
}
 
/**
* Return the class with the passed name if it is a subclass of <code>clazz</code>.
*
* @param name the name of the class, not <code>null</code>.
* @param clazz the superclass, not <code>null</code>.
* @return the requested class, <code>null</code> if {@link ClassNotFoundException not found} or
* not a {@link Class#asSubclass(Class) subclass} of <code>clazz</code>.
*/
static public final <T> Class<? extends T> getSubclass(final String name, final Class<T> clazz) {
return getSubclass(name, clazz, clazz.getClassLoader());
}
 
static public final <T> Class<? extends T> getSubclass(final String name, final Class<T> clazz, final ClassLoader cl) {
final Class<?> res;
try {
res = Class.forName(name, true, cl);
} catch (ClassNotFoundException e) {
return null;
}
return clazz.isAssignableFrom(res) ? res.asSubclass(clazz) : null;
}
 
static private Map<Type, Type> resolveTypes(Class<?> c, Class<?> raw) {
final Map<Type, Type> res = new HashMap<Type, Type>();
if (!raw.isAssignableFrom(c))
/trunk/OpenConcerto/src/org/openconcerto/utils/ntp/SNTPClient.java
New file
0,0 → 1,116
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ntp;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
 
public class SNTPClient {
 
protected final DatagramSocket socket;
 
/**
* The SNTP time is referenced to 01/01/1900-00:00. On the other hand, Unix systems and Java
* reference time to 01/01/1970-00:00. This means that convertion is necessary.
*/
private static final long SECS_1900_1970 = 2208988800L;
 
/**
* Constructor.
*
* @param timeout the response timeout (in milliseconds).
* @throws IllegalArgumentException if the timeout is invalid.
* @throws SocketException if an error occurs while creating the socket.
*/
public SNTPClient() throws SocketException {
this.socket = new DatagramSocket();
// 10s timeout
socket.setSoTimeout(10000);
}
 
/**
* Retrieves the network time offset from an SNTP server.
*
* @param host the server host address (IP or DNS).
* @param port the server port.
* @return the network time offset (in milliseconds).
*
* @throws IOException if an error occurs while contacting the server.
*/
public long getOffsetInMillis(final String host, final int port) throws IOException {
final InetAddress addr = InetAddress.getByName(host);
// Send
final Message smessage = new Message();
smessage.setTransmitTimestamp(toTimestamp(System.currentTimeMillis()));
final ByteArrayOutputStream output = new ByteArrayOutputStream();
smessage.encodeMessage(output);
final byte[] data = output.toByteArray();
output.close();
 
DatagramPacket rpacket = new DatagramPacket(data, data.length, addr, port);
socket.send(rpacket);
 
// Receive
final DatagramPacket packet = new DatagramPacket(new byte[Message.MAXIMUM_LENGTH], Message.MAXIMUM_LENGTH);
socket.receive(packet);
final long destinationTime = System.currentTimeMillis();
final Message rmessage = Message.decodeMessage(new ByteArrayInputStream(packet.getData()));
final long originalTime = fromTimestamp(rmessage.getOriginateTimestamp());
final long receiveTime = fromTimestamp(rmessage.getReceiveTimestamp());
final long transmitTime = fromTimestamp(rmessage.getTransmitTimestamp());
return ((receiveTime - originalTime) + (transmitTime - destinationTime)) / 2;
 
}
 
public void close() {
socket.close();
}
 
/**
* Converts Java time to an SNTP timestamp.
*
* @param time the Java time (in milliseconds).
* @return the SNTP timestamp.
*/
private static Timestamp toTimestamp(final long time) {
final double temp = ((double) time) / 1000D;
final long integer = (long) Math.floor(temp);
final long fraction = (long) ((temp - (double) integer) * 0x100000000L);
return new Timestamp(integer + SECS_1900_1970, fraction);
}
 
/**
* Converts an SNTP timestamp to Java time.
*
* @param timestamp the timestamp.
* @return the Java time (in milliseconds).
*/
private static final long fromTimestamp(final Timestamp timestamp) {
long time = (timestamp.getInteger() - SECS_1900_1970) * 1000L;
time += (timestamp.getFraction() * 1000L) / 0x100000000L;
return time;
}
 
public static void main(String[] args) throws IOException {
final SNTPClient client = new SNTPClient();
final long offset = client.getOffsetInMillis("fr.pool.ntp.org", 123);
client.close();
System.out.println(offset);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ntp/Timestamp.java
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.utils.ntp;
 
public final class Timestamp {
 
public static final Timestamp ZERO = new Timestamp(0, 0);
 
private final long integer;
private final long fraction;
 
public Timestamp(final long integer, final long fraction) {
this.integer = integer;
this.fraction = fraction;
}
 
public long getInteger() {
return integer;
}
 
public long getFraction() {
return fraction;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ntp/Message.java
New file
0,0 → 1,448
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.ntp;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
public final class Message {
 
/** Maximum message length (in bytes), without authentication */
public static final int MAXIMUM_LENGTH = 384;
 
/** Leap Indicator. */
private byte byLeapIndicator;
 
/** Version Number. */
private byte byVersionNumber = 0x04;
 
/** Client mode. */
private byte byMode = 0x03;
 
/** Stratum. */
private byte byStratum;
 
/** Poll Interval. */
private byte byPollInterval;
 
/** Precision. */
private byte byPrecision;
 
/** Rood Delay. */
private double dRootDelay;
 
/** Root Dispersion. */
private double dRootDispersion;
 
/** Reference Identifier. */
private byte[] sReferenceIdentifier = "LOCL".getBytes();
 
/** Reference Timestamp. */
private Timestamp tReferenceTimestamp = Timestamp.ZERO;
 
/** Originate Timestamp. */
private Timestamp tOriginateTimestamp = Timestamp.ZERO;
 
/** Receive Timestamp. */
private Timestamp tReceiveTimestamp = Timestamp.ZERO;
 
/** Transmit Timestamp. */
private Timestamp tTransmitTimestamp = Timestamp.ZERO;
 
/**
* Returns the Leap Indicator.
*
* @return the Leap Indicator.
*/
public byte getLeapIndicator() {
return byLeapIndicator;
}
 
/**
* Sets the Leap Indicator.
*
* @param byLeapIndicator the Leap Indicator.
*/
public void setLeapIndicator(final byte byLeapIndicator) {
this.byLeapIndicator = byLeapIndicator;
}
 
/**
* Returns the Version Number.
*
* @return the Version Number.
*/
public byte getVersionNumber() {
return byVersionNumber;
}
 
/**
* Sets the Version Number.
*
* @param byVersionNumber the Version Number.
*/
public void setVersionNumber(final byte byVersionNumber) {
this.byVersionNumber = byVersionNumber;
}
 
/**
* Returns the Mode.
*
* @return the Mode.
*/
public byte getMode() {
return byMode;
}
 
/**
* Sets the Mode.
*
* @param byMode the Mode.
*/
public void setMode(final byte byMode) {
this.byMode = byMode;
}
 
/**
* Returns the Stratum.
*
* @return the Stratum.
*/
public byte getStratum() {
return byStratum;
}
 
/**
* Sets the Stratum.
*
* @param byStratum the Stratum.
*/
public void setStratum(final byte byStratum) {
this.byStratum = byStratum;
}
 
/**
* Returns the Poll Interval.
*
* @return the Poll Interval.
*/
public byte getPollInterval() {
return byPollInterval;
}
 
/**
* Sets the Poll Interval.
*
* @param byPollInterval the Poll Interval.
*/
public void setPollInterval(final byte byPollInterval) {
this.byPollInterval = byPollInterval;
}
 
/**
* Returns the Precision.
*
* @return the Precision.
*/
public byte getPrecision() {
return byPrecision;
}
 
/**
* Sets the Precision.
*
* @param byPrecision the Precision.
*/
public void setPrecision(final byte byPrecision) {
this.byPrecision = byPrecision;
}
 
/**
* Returns the Root Delay.
*
* @return the Root Delay.
*/
public double getRootDelay() {
return dRootDelay;
}
 
/**
* Sets the Root Delay.
*
* @param dRootDelay the Root Delay.
*/
public void setRootDelay(final double dRootDelay) {
this.dRootDelay = dRootDelay;
}
 
/**
* Returns the Root Dispersion.
*
* @return the Root Dispersion.
*/
public double getRootDispersion() {
return dRootDispersion;
}
 
/**
* Sets the Root Dispersion.
*
* @param dRootDispersion the Root Dispersion.
*/
public void setRootDispersion(final double dRootDispersion) {
this.dRootDispersion = dRootDispersion;
}
 
/**
* Returns the Reference Identifier.
*
* @return the Reference Identifier.
*/
public byte[] getReferenceIdentifier() {
return sReferenceIdentifier;
}
 
/**
* Sets the Reference Identifier.
*
* @param sReferenceIdentifier the Reference Identifier.
*/
public void setReferenceIdentifier(final byte[] sReferenceIdentifier) {
this.sReferenceIdentifier = sReferenceIdentifier;
}
 
/**
* Returns the Reference Timestamp.
*
* @return the Reference Timestamp.
*/
public Timestamp getReferenceTimestamp() {
return tReferenceTimestamp;
}
 
/**
* Sets the Reference Timestamp.
*
* @param tReferenceTimestamp the Reference Timestamp.
*/
public void setReferenceTimestamp(final Timestamp tReferenceTimestamp) {
this.tReferenceTimestamp = tReferenceTimestamp;
}
 
/**
* Returns the Originate Timestamp.
*
* @return the Originate Timestamp.
*/
public Timestamp getOriginateTimestamp() {
return tOriginateTimestamp;
}
 
/**
* Sets the Originate Timestamp.
*
* @param tOriginateTimestamp the Originate Timestamp.
*/
public void setOriginateTimestamp(final Timestamp tOriginateTimestamp) {
this.tOriginateTimestamp = tOriginateTimestamp;
}
 
/**
* Returns the Receive Timestamp.
*
* @return the Receive Timestamp.
*/
public Timestamp getReceiveTimestamp() {
return tReceiveTimestamp;
}
 
/**
* Sets the Receive Timestamp.
*
* @param tReceiveTimestamp the Receive Timestamp.
*/
public void setReceiveTimestamp(final Timestamp tReceiveTimestamp) {
this.tReceiveTimestamp = tReceiveTimestamp;
}
 
/**
* Returns the Transmit Timestamp.
*
* @return the Transmit Timestamp.
*/
public Timestamp getTransmitTimestamp() {
return tTransmitTimestamp;
}
 
/**
* Sets the Transmit Timestamp.
*
* @param tTransmitTimestamp the Transmit Timestamp.
*/
public void setTransmitTimestamp(final Timestamp tTransmitTimestamp) {
this.tTransmitTimestamp = tTransmitTimestamp;
}
 
/**
* Encodes an SNTP message to a byte stream.
*
* @param output the byte stream.
*/
public void encodeMessage(final OutputStream output) throws IOException {
byte flags = (byte) (this.getLeapIndicator() << 6);
flags += (byte) (this.getVersionNumber() << 3);
flags += this.getMode();
output.write(flags);
output.write(this.getStratum());
output.write(this.getPollInterval());
output.write(this.getPrecision());
encodeFixedPoint(this.getRootDelay(), output);
encodeFixedPoint(this.getRootDispersion(), output);
encodeBitstring(this.getReferenceIdentifier(), output);
encodeTimestamp(this.getReferenceTimestamp(), output);
encodeTimestamp(this.getOriginateTimestamp(), output);
encodeTimestamp(this.getReceiveTimestamp(), output);
encodeTimestamp(this.getTransmitTimestamp(), output);
}
 
/**
* Decodes an SNTP message from a byte stream.
*
* @param input the byte stream.
* @return the message.
*/
public static Message decodeMessage(final InputStream input) throws IOException {
final Message message = new Message();
final byte flags = (byte) input.read();
message.setLeapIndicator((byte) (flags >> 6));
message.setVersionNumber((byte) ((flags >> 3) & 0x07));
message.setMode((byte) (flags & 0x07));
message.setStratum((byte) input.read());
message.setPollInterval((byte) input.read());
message.setPrecision((byte) input.read());
message.setRootDelay(decodeFixedPoint(input));
message.setRootDispersion(decodeFixedPoint(input));
message.setReferenceIdentifier(decodeBitstring(input));
message.setReferenceTimestamp(decodeTimestamp(input));
message.setOriginateTimestamp(decodeTimestamp(input));
message.setReceiveTimestamp(decodeTimestamp(input));
message.setTransmitTimestamp(decodeTimestamp(input));
 
return message;
}
 
/**
* Encodes a 32 bit number to a byte stream.
*
* @param number the number to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encode32(final long number, final OutputStream output) throws IOException {
for (int i = 3; i >= 0; i--) {
output.write((int) ((number >> (8 * i)) & 0xFF));
}
}
 
/**
* Decodes a 32 bit number from a byte stream.
*
* @param input the byte stream.
* @return the decoded number.
* @throws IOException if an error occurs while reading from the stream.
*/
private static long decode32(final InputStream input) throws IOException {
long number = 0;
for (int i = 0; i < 4; i++) {
number = (number << 8) + input.read();
}
return number;
}
 
/**
* Encodes a 32-bit bitstring to a byte stream.
*
* @param bitstring the bitstring to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encodeBitstring(final byte[] bitstring, final OutputStream output) throws IOException {
final byte[] temp = { 0, 0, 0, 0 };
System.arraycopy(bitstring, 0, temp, 0, bitstring.length);
output.write(temp);
}
 
/**
* Decodes a 32-bit bitstring from a byte stream.
*
* @param input the byte stream.
* @return the decoded string.
* @throws IOException if an error occurs while reading from the stream.
*/
private static byte[] decodeBitstring(final InputStream input) throws IOException {
final byte[] bitstring = new byte[4];
input.read(bitstring, 0, 4);
 
return bitstring;
}
 
/**
* Encodes a 32 bit fixed-point number to a byte stream.
*
* @param number the fixed-point number to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encodeFixedPoint(final double number, final OutputStream output) throws IOException {
encode32((long) (number * 0x10000L), output);
}
 
/**
* Decodes a 32 bit fixed-point number from a byte stream. The binary point is between bits 15
* and 16.
*
* @param input the byte stream.
* @return the decoded fixed-point number.
* @throws IOException if an error occurs while reading from the stream.
*/
private static double decodeFixedPoint(final InputStream input) throws IOException {
return ((double) decode32(input)) / 0x10000L;
}
 
/**
* Encodes a timestamp to a byte stream.
*
* @param timestamp the timestamp to encode.
* @param output the byte stream.
* @throws IOException if an error occurs while writting to the stream.
*/
private static void encodeTimestamp(final Timestamp timestamp, final OutputStream output) throws IOException {
encode32(timestamp.getInteger(), output);
encode32(timestamp.getFraction(), output);
}
 
/**
* Decodes a timestamp from a byte stream.
*
* @param input the byte stream.
* @return the decoded timestamp.
* @throws IOException if an error occurs while reading from the stream.
*/
private static Timestamp decodeTimestamp(final InputStream input) throws IOException {
final long integer = decode32(input);
final long fraction = decode32(input);
return new Timestamp(integer, fraction);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/SleepingQueue.java
18,6 → 18,7
 
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Collection;
import java.util.Deque;
import java.util.concurrent.Callable;
227,6 → 228,13
}
 
public final void start() {
this.start(null);
}
 
public final void start(final IClosure<Thread> customizeThread) {
customizeThread(this.tasksQueue);
if (customizeThread != null)
customizeThread.executeChecked(this.tasksQueue);
synchronized (this) {
this.tasksQueue.start();
this.setState(RunningState.RUNNING);
338,14 → 346,25
}
 
/**
* An exception was thrown by a task. This implementation merely
* {@link Exception#printStackTrace()}.
* An exception was thrown by a task. This implementation uses
* {@link Thread#getUncaughtExceptionHandler()} or
* {@link Thread#getDefaultUncaughtExceptionHandler()} if available, otherwise falls back to
* just {@link Exception#printStackTrace()}. To set the handler, {@link #start(IClosure)} can be
* used.
*
* @param exn the exception thrown.
*/
protected void exceptionThrown(final ExecutionException exn) {
final Thread thr = this.tasksQueue;
UncaughtExceptionHandler h = thr.getUncaughtExceptionHandler();
if (h == null)
h = Thread.getDefaultUncaughtExceptionHandler();
if (h != null) {
h.uncaughtException(thr, exn);
} else {
exn.printStackTrace();
}
}
 
/**
* Cancel all queued tasks and the current task.
617,7 → 636,6
private final class SingleThreadedExecutor extends DropperQueue<FutureTask<?>> {
private SingleThreadedExecutor() {
super(SleepingQueue.this.name + System.currentTimeMillis());
customizeThread(this);
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/utils/ExceptionUtils.java
81,7 → 81,7
}
 
static public String getStackTrace(Throwable cause) {
final StringWriter res = new StringWriter(128);
final StringWriter res = new StringWriter(8192);
final PrintWriter pw = new PrintWriter(res);
try {
cause.printStackTrace(pw);
/trunk/OpenConcerto/src/org/openconcerto/utils/ExceptionHandler.java
25,6 → 25,7
import java.awt.Desktop.Action;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
47,8 → 48,10
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
66,7 → 69,6
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.JTextComponent;
 
/**
* Allow to display an exception both on the GUI and on the console.
81,6 → 83,9
private static boolean showProbably = false;
private static IFactory<String> softwareInfos = null;
private static ThrowableHandler tHandler = null;
private static boolean safeToExit = false;
private static final CompletableFuture<Boolean> FALSE_FUTURE = CompletableFuture.completedFuture(Boolean.FALSE);
private static final CompletableFuture<Boolean> TRUE_FUTURE = CompletableFuture.completedFuture(Boolean.TRUE);
 
public static void setThrowableHandler(ThrowableHandler handler) {
tHandler = handler;
90,11 → 95,19
forumURL = url;
}
 
public synchronized static void setShowProbably(boolean showProbably) {
public static void setSafeToExit(boolean b) {
safeToExit = b;
}
 
public static void setSubmitErrorAutoEnabled(boolean b) {
submitErrorAuto = b;
}
 
public static synchronized void setShowProbably(boolean showProbably) {
ExceptionHandler.showProbably = showProbably;
}
 
public synchronized static boolean isShowProbably() {
public static synchronized boolean isShowProbably() {
return ExceptionHandler.showProbably;
}
 
120,21 → 133,25
* @param comp the modal parent of the error window.
* @param msg the message to display.
* @param originalExn the cause, can be <code>null</code>.
* @return an exception.
* @return a future completed when the error is handled (e.g. the user clicked on the dialog),
* <code>false</code> if the error couldn't be displayed to the user.
*/
static public ExceptionHandler handle(Component comp, String msg, Throwable originalExn) {
static public Future<Boolean> handle(Component comp, String msg, Throwable originalExn) {
final Future<Boolean> res;
if (tHandler != null && tHandler.handle(msg, originalExn)) {
return new ExceptionHandler(msg, originalExn);
res = TRUE_FUTURE;
} else {
res = new ExceptionHandler(comp, msg, originalExn, false).display();
}
return new ExceptionHandler(comp, msg, originalExn, false);
 
assert res != null;
return res;
}
 
static public RuntimeException handle(String msg, Throwable originalExn) {
static public Future<Boolean> handle(String msg, Throwable originalExn) {
return handle(null, msg, originalExn);
}
 
static public RuntimeException handle(String msg) {
static public Future<Boolean> handle(String msg) {
return handle(msg, null);
}
 
147,7 → 164,9
* @return an exception.
*/
static public RuntimeException die(String msg, Throwable originalExn) {
return new ExceptionHandler(null, msg, originalExn);
final ExceptionHandler res = new ExceptionHandler(null, msg, originalExn);
res.display();
return res;
}
 
static public RuntimeException die(String msg) {
160,27 → 179,31
 
// the comp on which to display the popup, may be null
private final Component comp;
private final Future<?> future;
private final boolean quit;
protected static AtomicInteger openedWindows = new AtomicInteger(0);
private static boolean forceUI;
private static boolean submitErrorAuto = false;
 
public static void setForceUI(boolean forceUI) {
ExceptionHandler.forceUI = forceUI;
}
 
private Future<?> display(final boolean error) {
private Future<Boolean> display() {
final boolean error = this.quit;
final String msg = this.getMessage();
// write out the message as soon as possible
getLogger().log(error ? Level.SEVERE : Level.INFO, null, this);
// then show it to the user
if (!GraphicsEnvironment.isHeadless() || forceUI) {
if (openedWindows.get() > 3) {
return FALSE_FUTURE;
}
final FutureTask<Boolean> run = new FutureTask<>(() -> {
return showMsgHardened(msg, error);
});
if (SwingUtilities.isEventDispatchThread()) {
showMsgHardened(msg, error);
run.run();
} else {
final FutureTask<?> run = new FutureTask<Object>(new Runnable() {
public void run() {
showMsgHardened(msg, error);
}
}, null);
if (error) {
try {
SwingUtilities.invokeAndWait(run);
191,19 → 214,16
} else {
SwingUtilities.invokeLater(run);
}
}
return run;
}
return TRUE_FUTURE;
}
return null;
}
 
public final Future<?> getDialogFuture() {
return this.future;
}
 
protected final void showMsgHardened(final String msg, final boolean error) {
protected final Boolean showMsgHardened(final String msg, final boolean error) {
try {
showMsg(msg, error);
return Boolean.TRUE;
} catch (Throwable e) {
// sometimes the VM cannot display the dialog, in that case don't crash the EDT as the
// message has already been logged. Further if this class is used in
217,6 → 237,7
// nothing
}
}
return Boolean.FALSE;
}
 
protected final void showMsg(final String msg, final boolean quit) {
320,62 → 341,6
}
}));
 
final javax.swing.Action submitAction = new AbstractAction("Soumettre l'erreur") {
@Override
public void actionPerformed(ActionEvent e) {
submitError(p, textArea);
}
 
private void submitError(final JPanel p, final JTextComponent textArea) {
final Charset cs = StringUtils.UTF8;
try {
ProductInfo productInfo = ProductInfo.getInstance();
 
String name = "", version = "";
if (productInfo != null) {
name = productInfo.getName();
version = productInfo.getProperty(ProductInfo.VERSION, version);
}
 
final Map<Info, String> systemInfos = SystemInfo.get(false);
final String os = systemInfos.remove(Info.OS);
final String java = systemInfos.toString();
final String encodedData = "java=" + PercentEncoder.encode(java, cs) + "&os=" + PercentEncoder.encode(os, cs) + "&software=" + PercentEncoder.encode(name + version, cs) + "&stack="
+ PercentEncoder.encode(computeSoftwareInformations() + "\n\n" + textArea.getText(), cs);
final String request = "http://bugreport.ilm-informatique.fr:5000/bugreport";
final URL url = new URL(request);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", cs.name());
final byte[] bytes = encodedData.getBytes(cs);
connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
 
final OutputStream outputStream = connection.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
 
// Get the response
final StringBuilder answer = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
answer.append(line);
}
outputStream.close();
reader.close();
connection.disconnect();
 
JOptionPane.showMessageDialog(p, "Merci d'avoir envoyé le rapport d'erreur au service technique.\nIl sera analysé prochainement.");
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
 
btnPanel.add(new JButton(submitAction));
 
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.EAST;
p.add(btnPanel, c);
400,9 → 365,10
message = msg + "\n\n" + message;
}
message += "\n";
message +=
 
getTrace();
message += getTrace();
if (submitErrorAuto) {
submitError(message);
}
textArea.setText(message);
textArea.setEditable(false);
 
420,9 → 386,22
c.fill = GridBagConstraints.NONE;
c.weighty = 0;
c.insets = new Insets(2, 4, 2, 4);
JPanel closePanel = new JPanel();
closePanel.setLayout(new FlowLayout());
if (safeToExit) {
closePanel.add(new JButton(new AbstractAction("Quitter") {
 
@Override
public void actionPerformed(ActionEvent e) {
System.exit(2);
}
}));
}
final JButton buttonClose = new JButton("Fermer");
p.add(buttonClose, c);
closePanel.add(buttonClose);
 
p.add(closePanel, c);
 
final Window window = this.comp == null ? null : SwingUtilities.getWindowAncestor(this.comp);
final JDialog f;
if (window instanceof Frame) {
432,7 → 411,7
}
f.setContentPane(p);
f.pack();
f.setSize(580, 680);
f.setSize(780, 580);
f.setMinimumSize(new Dimension(380, 380));
f.setLocationRelativeTo(this.comp);
final ActionListener al = new ActionListener() {
439,12 → 418,12
 
@Override
public void actionPerformed(ActionEvent e) {
openedWindows.decrementAndGet();
if (quit) {
System.exit(1);
} else {
f.dispose();
}
 
}
};
buttonClose.addActionListener(al);
453,10 → 432,13
@Override
public void windowClosing(WindowEvent e) {
al.actionPerformed(null);
 
}
});
openedWindows.incrementAndGet();
 
f.setVisible(true);
 
}
 
private String getTrace() {
485,17 → 467,70
private ExceptionHandler(Component comp, String msg, Throwable cause, boolean quit) {
super(msg, cause);
this.comp = comp;
this.future = this.display(quit);
this.quit = quit;
}
 
public ExceptionHandler(String msg, Throwable cause) {
super(msg, cause);
this.comp = null;
this.future = null;
private void submitError(String error) {
final Charset cs = StringUtils.UTF8;
try {
ProductInfo productInfo = ProductInfo.getInstance();
 
String name = "", version = "";
if (productInfo != null) {
name = productInfo.getName();
version = productInfo.getProperty(ProductInfo.VERSION, version);
}
 
final Map<Info, String> systemInfos = SystemInfo.get(false);
final String os = systemInfos.remove(Info.OS);
final String java = systemInfos.toString();
final String encodedData = "java=" + PercentEncoder.encode(java, cs) + "&os=" + PercentEncoder.encode(os, cs) + "&software=" + PercentEncoder.encode(name + version, cs) + "&stack="
+ PercentEncoder.encode(computeSoftwareInformations() + "\n\n" + error, cs);
Thread t = new Thread(new Runnable() {
 
@Override
public void run() {
final String request = "http://bugreport.ilm-informatique.fr:5000/bugreport";
try {
System.err.println("ExceptionHandler.submitError");
final URL url = new URL(request);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", cs.name());
final byte[] bytes = encodedData.getBytes(cs);
connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
 
final OutputStream outputStream = connection.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
 
// Get the response
final StringBuilder answer = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
answer.append(line);
}
outputStream.close();
reader.close();
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
 
} catch (Exception ex) {
ex.printStackTrace();
}
}
 
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
ExceptionHandler.handle("Fichier de configuration corrompu\n\nmulti\nline", new IllegalStateException("Id manquant"));
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/task/ui/UserRightPanelDetail.java
179,14 → 179,15
private void swapOnDoubleClick(final JList list, MouseEvent e, String field) {
if (e.getClickCount() == 2) {
int index = list.locationToIndex(e.getPoint());
if (index >= 0) {
ListModel dlm = list.getModel();
Object item = dlm.getElementAt(index);
list.ensureIndexIsVisible(index);
User toUser = (User) item;
swapState(selectedUser, toUser, field);
 
}
}
}
 
protected void swapState(User user, User toUser, String field) {
final SQLSelect sel = new SQLSelect();
/trunk/OpenConcerto/src/org/openconcerto/task/element/CompanyAccessSQLElement.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.task.element;
 
import org.openconcerto.sql.element.ConfSQLElement;
 
import java.util.ArrayList;
import java.util.List;
 
public class CompanyAccessSQLElement extends ConfSQLElement {
 
public CompanyAccessSQLElement() {
super("ACCES_SOCIETE");
 
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_USER_COMMON");
l.add("ID_SOCIETE_COMMON");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("ID_USER_COMMON");
l.add("ID_SOCIETE_COMMON");
return l;
}
 
@Override
protected String createCode() {
return "common.company-access";
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/task/element/TaskSQLElementBase.java
15,8 → 15,6
 
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.task.TM;
import org.openconcerto.utils.i18n.I18nUtils;
 
/**
* @author Sylvain CUAZ
23,10 → 21,6
*/
public abstract class TaskSQLElementBase extends ConfSQLElement {
 
{
this.setL18nPackageName(I18nUtils.getPackageName(TM.class));
}
 
public TaskSQLElementBase(final String tableName) {
super(tableName);
}
/trunk/OpenConcerto/src/org/openconcerto/task/translation/messages_es.properties
New file
0,0 → 1,20
summary=Summary :
todoBefore=Para hacer antes de {date, date, medium} en {date, time, short} por {user}
todoBefore.col=Hacer antes
ok=OK
cancel=Cancelar
taskToDo=Descripción de la tarea
assignedTo=Asignado a
created=Created
completed=Completado
deleteForbidden=Solo puedes eliminar tareas que creaste
assignedBy=Asignado por {user}\nEn {date, date, medium} por {date, time, short}
delete=Borrar
deleteSelectedTasks=Borrar {count, plural, =0 {selected tasks} one {the selected task} other {the # selected tasks}}
addTask=Nueva tarea
hideHistory= Ocultar historial
showDetails=Mostrar detalles
details=Detalles
markDone=Marca hecha
moveOneDay=Mover por un día
showTaskAssignedTo=Mostrar tarea asignada a ...
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_en.xml
1,4 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="User" />
<FIELD name="ID_SOCIETE_COMMON" label="Allowed company access" />
</element>
<element refid="TACHE_COMMON" name="task" />
<element refid="TACHE_RIGHTS" name="right for tasks" namePlural="rights for tasks" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_es.xml
New file
0,0 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="Usario" />
<FIELD name="ID_SOCIETE_COMMON" label="Acceso a la sociedad" />
</element>
<element refid="TACHE_COMMON" name="tarea" />
<element refid="TACHE_RIGHTS" name="derechos para tareas" namePlural="derechos para tareas" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_fr.xml
1,4 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="Utilisateur" />
<FIELD name="ID_SOCIETE_COMMON" label="Accés à la société" />
</element>
<element refid="TACHE_COMMON" nameClass="feminine" name="tâche" />
<element refid="TACHE_RIGHTS" nameClass="masculine" name="droit pour les tâches" namePlural="droits pour les tâches" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/translation/SQLElementNames_pl.xml
New file
0,0 → 1,8
<translations>
<element refid="common.company-access">
<FIELD name="USER_COMMON" label="User" />
<FIELD name="ID_SOCIETE_COMMON" label="Ustawienia dostępu" />
</element>
<element refid="TACHE_COMMON" name="task" />
<element refid="TACHE_RIGHTS" name="right for tasks" namePlural="rights for tasks" />
</translations>
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListModel.java
152,7 → 152,7
for (TodoListElement elt : rowsDeleted) {
int index = this.elements.indexOf(elt);
if (index >= 0) {
removeRow(index);
elements.remove(index);
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/task/config/ComptaBasePropsConfiguration.java
23,10 → 23,12
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLFilter;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.users.CompanyAccessSQLElement;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.users.UserCommonSQLElement;
import org.openconcerto.sql.users.rights.RightSQLElement;
import org.openconcerto.sql.users.rights.UserRightSQLElement;
import org.openconcerto.task.TM;
import org.openconcerto.task.element.CompanyAccessSQLElement;
import org.openconcerto.task.element.TaskRightSQLElement;
import org.openconcerto.task.element.TaskSQLElement;
import org.openconcerto.utils.BaseDirs;
33,6 → 35,8
import org.openconcerto.utils.DesktopEnvironment;
import org.openconcerto.utils.LogUtils;
import org.openconcerto.utils.ProductInfo;
import org.openconcerto.utils.i18n.Grammar_fr;
import org.openconcerto.utils.i18n.NounClass;
 
import java.io.File;
import java.io.FileNotFoundException;
39,8 → 43,10
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
 
public abstract class ComptaBasePropsConfiguration extends PropsConfiguration {
125,13 → 131,21
}
 
@Override
protected List<String> getMappings() {
final List<String> res = new ArrayList<>(super.getMappings());
final String pkg = "/" + TM.class.getPackage().getName().replace('.', '/');
res.add(pkg + "/translation/SQLElementNames");
return res;
}
 
@Override
protected SQLElementDirectory createDirectory() {
final SQLElementDirectory dir = super.createDirectory();
 
// TACHE_COMMON points to SOCIETE but we never display it we don't need the full element
dir.addSQLElement(new ConfSQLElement("SOCIETE_COMMON", "une société", "sociétés"));
dir.addSQLElement(new ConfSQLElement("EXERCICE_COMMON", "un exercice", "exercices"));
dir.addSQLElement(new ConfSQLElement("ADRESSE_COMMON", "une adresse", "adresses"));
dir.addSQLElement(new ConfSQLElement("SOCIETE_COMMON", Grammar_fr.getInstance().createPhrase(NounClass.FEMININE, "société")));
dir.addSQLElement(new ConfSQLElement("EXERCICE_COMMON", Grammar_fr.getInstance().createPhrase(NounClass.MASCULINE, "exercice")));
dir.addSQLElement(new ConfSQLElement("ADRESSE_COMMON", Grammar_fr.getInstance().createPhrase(NounClass.FEMININE, "adresse")));
 
dir.addSQLElement(new TaskRightSQLElement());
dir.addSQLElement(new TaskSQLElement());
138,8 → 152,8
 
dir.addSQLElement(new UserCommonSQLElement(getRoot(), false));
dir.addSQLElement(new CompanyAccessSQLElement());
dir.addSQLElement(UserRightSQLElement.class);
dir.addSQLElement(RightSQLElement.class);
dir.addSQLElement(new UserRightSQLElement(getRoot()));
dir.addSQLElement(new RightSQLElement(getRoot()));
 
return dir;
}
164,8 → 178,15
 
protected final void setRowSociete(int id) {
this.idSociete = id;
this.rowSociete = getSystemRoot().findTable("SOCIETE_COMMON").getValidRow(this.getSocieteID());
final SQLTable tableSociete = getSystemRoot().findTable("SOCIETE_COMMON");
final SQLRow row = tableSociete.getRow(id);
if (row == null) {
throw new IllegalArgumentException("no row for id " + id + " in " + tableSociete);
} else if (!row.isValid()) {
throw new IllegalArgumentException("invalid row : " + row);
}
this.rowSociete = row;
}
 
public final SQLBase getSQLBaseSociete() {
return this.getRootSociete().getBase();
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetXml.java
15,7 → 15,10
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.ui.PreviewFrame;
import org.openconcerto.erp.core.sales.invoice.report.VenteFactureXmlSheet;
import org.openconcerto.erp.core.sales.quote.report.PaypalStamper;
import org.openconcerto.erp.generationDoc.element.TypeModeleSQLElement;
import org.openconcerto.erp.preferences.PayPalPreferencePanel;
import org.openconcerto.erp.storage.CloudStorageEngine;
import org.openconcerto.erp.storage.StorageEngine;
import org.openconcerto.erp.storage.StorageEngines;
26,19 → 29,31
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.preferences.SQLPreferences;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.GraphicsEnvironment;
import java.awt.print.PrinterJob;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
213,8 → 228,7
}
 
} catch (Exception e) {
e.printStackTrace();
ExceptionHandler.handle("Impossible de charger le document OpenOffice", e);
ExceptionHandler.handle("Impossible de charger le document OpenOffice " + pdfFile.getAbsolutePath() + "(viewer : " + useODSViewer + ")", e);
}
}
 
239,12 → 253,87
return this.meta;
}
 
public static void createPDF(final File generatedFile, final File pdfFile, final OpenDocument doc, String storagePath) {
public void createPDF(final File generatedFile, final File pdfFile, final OpenDocument doc, String storagePath) {
if (pdfFile == null) {
throw new IllegalArgumentException("null PDF file");
}
try {
if (VenteFactureXmlSheet.TEMPLATE_ID.equals(getDefaultTemplateId())) {
final SQLPreferences prefs = SQLPreferences.getMemCached(getElement().getTable().getDBRoot());
if (prefs.getBoolean(PayPalPreferencePanel.PAYPAL_INVOICE, false)) {
try {
final File inFile = File.createTempFile("oc_", pdfFile.getName());
SheetUtils.convert2PDF(doc, inFile);
PaypalStamper s = new PaypalStamper();
int x = prefs.getInt(PayPalPreferencePanel.PAYPAL_INVOICE_X, 0);
int y = prefs.getInt(PayPalPreferencePanel.PAYPAL_INVOICE_Y, 0);
 
// Reference
String ref = getSQLRow().getString("NUMERO");
// Montant : ex : 10.55
long cents = getSQLRow().getLong("NET_A_PAYER");
String amount = cents / 100 + "." + cents % 100;
// Devise
// TODO : autres devises
String currency = "EUR";
// POST
final URL url = new URL("https://cloud.openconcerto.org/payment");
final URLConnection con = url.openConnection();
final HttpURLConnection http = (HttpURLConnection) con;
http.setRequestMethod("POST");
http.setDoOutput(true);
http.setDefaultUseCaches(false);
 
String hyperlink = null;
// x-www-form-urlencoded
final Map<String, String> arguments = new HashMap<>();
arguments.put("pI", prefs.get(PayPalPreferencePanel.PAYPAL_CLIENTID, ""));
arguments.put("pS", prefs.get(PayPalPreferencePanel.PAYPAL_SECRET, ""));
arguments.put("ref", ref);
arguments.put("amount", amount);
arguments.put("currency", currency);
arguments.put("type", "paypal");
final StringJoiner sj = new StringJoiner("&");
for (Map.Entry<String, String> entry : arguments.entrySet()) {
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
}
final String postData = sj.toString();
System.err.println("SheetXml.createPDF() " + postData);
byte[] out = postData.getBytes(StandardCharsets.UTF_8);
int length = out.length;
http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.connect();
try (OutputStream os = http.getOutputStream()) {
os.write(out);
}
if (http.getResponseCode() != 401) {
 
InputStream is = http.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
 
int numCharsRead;
char[] charArray = new char[1024];
StringBuilder sb = new StringBuilder();
while ((numCharsRead = isr.read(charArray)) > 0) {
sb.append(charArray, 0, numCharsRead);
}
//
hyperlink = sb.toString();
}
s.addLink(inFile, pdfFile, x, y, hyperlink);
} catch (Exception e) {
e.printStackTrace();
SheetUtils.convert2PDF(doc, pdfFile);
}
 
} else {
SheetUtils.convert2PDF(doc, pdfFile);
}
} else {
SheetUtils.convert2PDF(doc, pdfFile);
}
 
} catch (Throwable e) {
ExceptionHandler.handle("Impossible de créer le PDF " + pdfFile.getAbsolutePath(), e);
}
421,8 → 510,23
File f;
try {
f = getOrCreateDocumentFile();
// ComptaPropsConfiguration.getOOConnexion().loadDocument(f, false);
if (f != null && f.exists()) {
OOUtils.open(f);
} else {
if (!GraphicsEnvironment.isHeadless()) {
if (f != null) {
JOptionPane.showMessageDialog(null, "Le fichier " + f.getAbsolutePath() + " est manquant");
} else {
JOptionPane.showMessageDialog(null, "Fichier manquant");
}
} else {
if (f != null) {
throw new FileNotFoundException(f.getAbsolutePath() + " missing");
} else {
throw new NullPointerException("null document");
}
}
}
} catch (Exception e) {
ExceptionHandler.handle("Impossible d'ouvrir le document.", e);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLField.java
84,6 → 84,9
// {
String field = this.elt.getAttributeValue("name");
 
if (field != null && field.trim().length() > 0 && !this.row.getTable().contains(field)) {
throw new InvalidTemplateException("Le champ " + field + " n'existe pas dans la table " + this.row.getTable().getName());
}
final SQLField sqlField = (field == null || field.trim().length() == 0) ? null : this.row.getTable().getField(field);
boolean isForeignField = (sqlField == null) ? false : this.row.getTable().getForeignKeys().contains(sqlField);
 
137,10 → 140,16
String typeComp = this.elt.getAttributeValue("type");
if (this.op != null && this.op.trim().length() > 0 && !(typeComp != null && typeComp.trim().length() > 0 && typeComp.toLowerCase().startsWith("deviselettre"))) {
String field2 = this.elt.getAttributeValue("name2");
if (!this.row.getTable().contains(field)) {
throw new InvalidTemplateException("Le champ " + field + " n'existe pas dans la table " + this.row.getTable().getName());
}
Number o = (Number) this.row.getObject(field);
 
Number o2;
if (field2 != null && field2.trim().length() > 0) {
if (!this.row.getTable().contains(field2)) {
throw new InvalidTemplateException("Le champ " + field2 + " n'existe pas dans la table " + this.row.getTable().getName());
}
o2 = (Number) this.row.getObject(field2);
} else {
o2 = Double.parseDouble(this.elt.getAttributeValue("number"));
223,6 → 232,9
}
stringValue = o.toString();
} else {
if (!this.row.getTable().contains(field)) {
throw new InvalidTemplateException("Le champ " + field + " n'existe pas dans la table " + this.row.getTable().getName());
}
Object o2 = this.row.getObject(field);
 
if (o2 != null && scale != null && scale.trim().length() > 0) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SpreadSheetGenerator.java
14,6 → 14,7
package org.openconcerto.erp.generationDoc;
 
import static org.openconcerto.task.config.ComptaBasePropsConfiguration.getStreamStatic;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.ui.PreviewFrame;
import org.openconcerto.erp.preferences.TemplateNXProps;
216,14 → 217,13
fTmp.renameTo(fDest);
 
fDest = new File(this.destDirOO, this.destFileName + ".ods");
final InputStream stream = getStreamStatic(fODSP);
try (final InputStream stream = getStreamStatic(fODSP)) {
if (stream != null) {
// Copie de l'odsp
File odspOut = new File(this.destDirOO, this.destFileName + ".odsp");
StreamUtils.copy(stream, odspOut);
stream.close();
 
}
}
try {
ssheet.saveAs(fDest);
} catch (FileNotFoundException e) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractJOOReportsSheet.java
231,7 → 231,7
}
}
 
private File getDocumentFile() {
public File getDocumentFile() {
File outputDir = DocumentLocalStorageManager.getInstance().getDocumentOutputDirectory(getDefaultTemplateID());
return new File(outputDir, getFileName() + ".odt");
}
302,12 → 302,15
return init;
}
 
public File getPDFDocumentFile() {
final File outputPDFDirectory = DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.templateId);
return new File(outputPDFDirectory, getFileName() + ".pdf");
}
 
public void exportToPdf() {
// Export vers PDF
final String fileName = getFileName();
final File fileOutOO = getDocumentFile();
final File outputPDFDirectory = DocumentLocalStorageManager.getInstance().getPDFOutputDirectory(this.templateId);
final File fileOutPDF = new File(outputPDFDirectory, fileName + ".pdf");
final File fileOutPDF = getPDFDocumentFile();
 
if (!fileOutOO.exists()) {
generate(false, false, "");
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractLocalTemplateProvider.java
47,7 → 47,7
throw new NullPointerException("null templateId");
}
File templateFile1 = getTemplateFromLocalFile(templateId, language, type);
if (templateFile1 != null && templateFile1.exists()) {
if (templateFile1 != null && templateFile1.exists() && !templateFile1.isDirectory()) {
return templateFile1;
}
File templateFile2 = getTemplateFromLocalFile(templateId + ".ods", language, type);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationListeColumnXML.java
24,12 → 24,16
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.io.BOMSkipper;
 
import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
46,7 → 50,7
public class OOgenerationListeColumnXML {
 
// Cache pour la recherche des styles
private static Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>();
private static Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<>();
 
public static File genere(String modele, File pathDest, String fileDest, Map<Integer, List<Map<String, Object>>> liste, Map<Integer, Map<String, Object>> values) {
return genere(modele, pathDest, fileDest, liste, values, new HashMap<Integer, Map<Integer, String>>(), null, null);
61,7 → 65,11
if (xmlConfiguration == null) {
throw new IllegalStateException("Template configuration " + templateId + " not found (" + TemplateManager.getInstance().getClass().getName() + ")");
}
Document doc = builder.build(xmlConfiguration);
final BufferedReader xmlConfigurationReader = new BufferedReader(new InputStreamReader(xmlConfiguration, Charset.forName("UTF8")));
BOMSkipper.skip(xmlConfigurationReader);
final Document doc = builder.build(xmlConfigurationReader);
xmlConfigurationReader.close();
xmlConfiguration.close();
 
// On initialise un nouvel élément racine avec l'élément racine du
// document.
84,7 → 92,7
for (Integer i : liste.keySet()) {
final Sheet sheet = spreadSheet.getSheet(i);
List children = racine.getChildren("element" + i);
if (children.size() == 0) {
if (children.isEmpty()) {
children = racine.getChildren("element");
}
parseElementsXML(children, sheet, values.get(i));
138,7 → 146,7
}
Object oLastColTmp = tableau.getAttributeValue("lastColumn");
int lastColumn = -1;
int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endPageLine = Integer.parseInt(tableau.getAttributeValue("endPageLine"));
if (oLastColTmp != null) {
lastColumn = sheet.resolveHint(oLastColTmp.toString() + 1).x + 1;
}
202,11 → 210,7
*/
private static int fillTable(Element tableau, List<Map<String, Object>> liste, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test, Map<Integer, String> style) {
 
// int nbPage = 1;
// int currentLineTmp = Integer.valueOf(tableau.getAttributeValue("firstLine"));
// int currentLine = Integer.valueOf(tableau.getAttributeValue("firstLine"));
// int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endLine = Integer.valueOf(tableau.getAttributeValue("endLine"));
int endLine = Integer.parseInt(tableau.getAttributeValue("endLine"));
 
List listElts = tableau.getChildren("element");
 
222,7 → 226,6
int currentCol = firstCol;
for (int i = 0; i < liste.size(); i++) {
Map<String, Object> mValues = liste.get(i);
// System.err.println(mValues);
if (currentCol != firstCol) {
for (int k = 0; k < endLine; k++) {
MutableCell<SpreadSheet> c1 = sheet.getCellAt(firstCol, k);
464,9 → 467,8
}
 
// Copie de l'odsp
try {
File odspOut = new File(pathDest, fileName + ".odsp");
InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);
try (final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);) {
if (odspIn != null) {
StreamUtils.copy(odspIn, odspOut);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/DepotChequeXmlSheet.java
New file
0,0 → 1,44
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationDoc.gestcomm;
 
import org.openconcerto.erp.generationDoc.AbstractSheetXMLWithDate;
import org.openconcerto.erp.preferences.PrinterNXProps;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRow;
 
public class DepotChequeXmlSheet extends AbstractSheetXMLWithDate {
 
public static final String TEMPLATE_ID = "DepotCheque";
public static final String TEMPLATE_PROPERTY_NAME = "LocationDepotCheque";
 
@Override
public String getName() {
 
return "DepotCheque" + this.row.getID();
}
 
public DepotChequeXmlSheet(SQLRow row) {
super(row);
this.printer = PrinterNXProps.getInstance().getStringProperty("FacturePrinter");
this.elt = Configuration.getInstance().getDirectory().getElement("DEPOT_CHEQUE");
getDefaultTemplateId();
}
 
@Override
public String getDefaultTemplateId() {
return TEMPLATE_ID;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/ReportingTaxeComplementaireSheetXML.java
83,16 → 83,26
private static SQLTable tableVF = Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE").getTable();
 
class TaxeComplRecap {
private final String code, nom;
private final String code, nom, numeroCptProduit, numeroCpt;
private BigDecimal percentTaxe, totalBase, qte;
 
public TaxeComplRecap(String code, String nom, BigDecimal percentTaxe) {
this.code = code;
this.nom = nom;
public TaxeComplRecap(SQLRowAccessor foreignTaxeCompl) {
this.code = foreignTaxeCompl.getString("CODE");
this.nom = foreignTaxeCompl.getString("NOM");
this.qte = BigDecimal.ZERO;
this.percentTaxe = percentTaxe;
this.percentTaxe = foreignTaxeCompl.getBigDecimal("POURCENT");
this.totalBase = BigDecimal.ZERO;
if (foreignTaxeCompl.getObject("ID_COMPTE_PCE") != null && !foreignTaxeCompl.isForeignEmpty("ID_COMPTE_PCE")) {
this.numeroCpt = foreignTaxeCompl.getForeign("ID_COMPTE_PCE").getString("NUMERO");
} else {
this.numeroCpt = "";
}
if (foreignTaxeCompl.getObject("ID_COMPTE_PCE_PRODUITS") != null && !foreignTaxeCompl.isForeignEmpty("ID_COMPTE_PCE_PRODUITS")) {
this.numeroCptProduit = foreignTaxeCompl.getForeign("ID_COMPTE_PCE_PRODUITS").getString("NUMERO");
} else {
this.numeroCptProduit = "";
}
}
 
public void cumul(BigDecimal qte, BigDecimal total) {
this.qte = qte.add(this.qte);
107,6 → 117,14
return nom;
}
 
public String getNumeroCpt() {
return numeroCpt;
}
 
public String getNumeroCptProduit() {
return numeroCptProduit;
}
 
public BigDecimal getQte() {
return qte;
}
142,8 → 160,10
rowvalsVFElt.put("T_PV_HT", null);
rowvalsVFElt.put("QTE", null);
rowvalsVFElt.put("QTE_UNITAIRE", null);
rowvalsVFElt.putRowValues("ID_ARTICLE").putRowValues("ID_TAXE_COMPLEMENTAIRE").putNulls("CODE", "NOM", "POURCENT");
 
final SQLRowValues rowValsTaxeCompl = rowvalsVFElt.putRowValues("ID_ARTICLE").putRowValues("ID_TAXE_COMPLEMENTAIRE");
rowValsTaxeCompl.putNulls("CODE", "NOM", "POURCENT");
rowValsTaxeCompl.putRowValues("ID_COMPTE_PCE_PRODUITS").putNulls("NUMERO", "NOM");
rowValsTaxeCompl.putRowValues("ID_COMPTE_PCE").putNulls("NUMERO", "NOM");
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowvalsVFElt);
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
 
166,7 → 186,7
if (recap.containsKey(foreignTaxeCompl.getID())) {
r = recap.get(foreignTaxeCompl.getID());
} else {
r = new TaxeComplRecap(foreignTaxeCompl.getString("CODE"), foreignTaxeCompl.getString("NOM"), foreignTaxeCompl.getBigDecimal("POURCENT"));
r = new TaxeComplRecap(foreignTaxeCompl);
recap.put(foreignTaxeCompl.getID(), r);
}
r.cumul(sqlRowValues.getBigDecimal("QTE_UNITAIRE").multiply(new BigDecimal(sqlRowValues.getInt("QTE"))), sqlRowValues.getBigDecimal("T_PV_HT"));
186,6 → 206,9
for (TaxeComplRecap item : recap.values()) {
Map<String, Object> vals = new HashMap<String, Object>();
 
vals.put("COMPTE_NUMERO", item.getNumeroCpt());
vals.put("COMPTE_PRODUIT_NUMERO", item.getNumeroCptProduit());
 
vals.put("CODE", item.getCode());
vals.put("NOM", item.getNom());
vals.put("QTE", item.getQte());
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/InvalidTemplateException.java
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.erp.generationDoc;
 
public class InvalidTemplateException extends RuntimeException {
 
public InvalidTemplateException(String cause) {
super(cause);
}
 
public InvalidTemplateException(String cause, Exception e) {
super(cause, e);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/A4.java
28,6 → 28,6
final double width = (210 * DPI) / INCH_TO_MM;
final double height = (297 * DPI) / INCH_TO_MM;
setSize(width, height);
setImageableArea(hMargin, vMargin, width + 2 * hMargin, height - 2 * vMargin);
setImageableArea(hMargin, vMargin, width - 2 * hMargin, height - 2 * vMargin);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/DefaultLocalTemplateProvider.java
109,9 → 109,15
final File from = getFile(templateId + ext, language, type);
final File to = getLocalFile(templateId + ext, language, type);
try {
if (from.exists() && !to.exists()) {
if (from != null && to != null && from.exists() && !to.exists()) {
final File parentDir = to.getParentFile();
if (parentDir != null) {
if (!parentDir.exists()) {
parentDir.mkdirs();
}
FileUtils.copyFile(from, to);
}
}
} catch (IOException e) {
throw new IllegalStateException("Copie impossible", e);
}
140,7 → 146,7
for (int i = 0; i < EXTS.length; i++) {
final String ext = EXTS[i];
final File local = getLocalFile(templateId + ext, language, type);
if (local.exists()) {
if (local != null && local.exists()) {
local.delete();
ensureDelete(local);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/element/ModeleSQLElement.java
33,15 → 33,17
super("MODELE", "un modele ", "modeles");
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("NOM");
l.add("ID_TYPE_MODELE");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
final List<String> l = new ArrayList<>(2);
l.add("NOM");
l.add("ID_TYPE_MODELE");
return l;
52,7 → 54,7
 
@Override
protected Set<String> createRequiredNames() {
final Set<String> s = new HashSet<String>();
final Set<String> s = new HashSet<>();
// s.add("NOM");
// s.add("ID_TYPE_MODELE");
return s;
65,8 → 67,13
};
}
 
@Override
public String getDescription(SQLRow fromRow) {
return fromRow.getString("NOM");
}
 
@Override
protected String createCode() {
return "document.template";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/element/TypeModeleSQLElement.java
16,8 → 16,7
*/
package org.openconcerto.erp.generationDoc.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.DBRoot;
33,16 → 32,12
import java.util.Map;
import java.util.Set;
 
public class TypeModeleSQLElement extends ConfSQLElement {
public class TypeModeleSQLElement extends ComptaSQLConfElement {
 
public TypeModeleSQLElement(DBRoot root) {
super(root.getTable("TYPE_MODELE"), "un type_modele ", "type_modeles");
super(root.getTable("TYPE_MODELE"), "un type de modèle", "types de modèles");
}
 
public TypeModeleSQLElement() {
this(Configuration.getInstance().getRoot());
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("NOM");
91,17 → 86,20
 
if (this.template == null) {
this.template = new HashMap<String, String>();
SQLSelect sel = new SQLSelect(getTable().getBase());
SQLSelect sel = new SQLSelect();
sel.addSelectStar(getTable());
List<SQLRow> rows = (List<SQLRow>) Configuration.getInstance().getBase().getDataSource().execute(sel.asString(), SQLRowListRSH.createFromSelect(sel));
for (SQLRow sqlRow : rows) {
template.put(sqlRow.getString("TABLE"), sqlRow.getString("DEFAULT_MODELE"));
for (SQLRow sqlRow : SQLRowListRSH.execute(sel)) {
this.template.put(sqlRow.getString("TABLE"), sqlRow.getString("DEFAULT_MODELE"));
}
 
}
 
return template;
return this.template;
 
}
 
@Override
protected String createCode() {
return "document.template-type";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java
37,15 → 37,19
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.io.BOMSkipper;
 
import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
77,12 → 81,12
private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
 
// Cache pour la recherche des styles
private Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<Sheet, Map<String, Map<Integer, String>>>();
private Map<SQLRowAccessor, Map<String, Object>> taxe = new HashMap<SQLRowAccessor, Map<String, Object>>();
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>();
private Map<Sheet, Map<String, Map<Integer, String>>> cacheStyle = new HashMap<>();
private Map<SQLRowAccessor, Map<String, Object>> taxe = new HashMap<>();
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<>();
 
// Cache pour les SQLRow du tableau
private Map<String, List<? extends SQLRowAccessor>> rowsEltCache = new HashMap<String, List<? extends SQLRowAccessor>>();
private Map<String, List<? extends SQLRowAccessor>> rowsEltCache = new HashMap<>();
private final OOXMLCache rowRefCache = new OOXMLCache();
private final SQLRow row;
 
155,7 → 159,11
+ ((typeTemplate == null) ? "" : typeTemplate));
return null;
}
Document doc = builder.build(xmlConfiguration);
 
final BufferedReader xmlConfigurationReader = new BufferedReader(new InputStreamReader(xmlConfiguration, Charset.forName("UTF8")));
BOMSkipper.skip(xmlConfigurationReader);
final Document doc = builder.build(xmlConfigurationReader);
xmlConfigurationReader.close();
xmlConfiguration.close();
 
// On initialise un nouvel élément racine avec l'élément racine du document.
239,7 → 247,7
// et d'optimiser la recherche
Object oLastColTmp = tableau.getAttributeValue("lastColumn");
int lastColumn = -1;
int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endPageLine = Integer.parseInt(tableau.getAttributeValue("endPageLine"));
if (oLastColTmp != null) {
lastColumn = sheet.resolveHint(oLastColTmp.toString() + 1).x + 1;
}
251,8 → 259,8
return;
}
int nbPage = fillTable(tableau, row, sheet, mapStyle, true, rowLanguage);
int firstLine = Integer.valueOf(tableau.getAttributeValue("firstLine"));
int endLine = Integer.valueOf(tableau.getAttributeValue("endLine"));
int firstLine = Integer.parseInt(tableau.getAttributeValue("firstLine"));
int endLine = Integer.parseInt(tableau.getAttributeValue("endLine"));
Object printRangeObj = sheet.getPrintRanges();
 
System.err.println("Nombre de page == " + nbPage);
286,7 → 294,7
int lineToAdd = endPageLine - endLine;
String repeatedCount = tableau.getAttributeValue("repeatedCount");
if (repeatedCount != null && repeatedCount.trim().length() > 0) {
int count = Integer.valueOf(repeatedCount);
int count = Integer.parseInt(repeatedCount);
sheet.duplicateRows(firstLine, lineToAdd / count, count);
final int rest = lineToAdd % count;
// Si le nombre de ligne ne termine pas à la fin de la page
324,7 → 332,7
cell2.setValue("Page " + (i + start) + "/" + nbPageRef);
}
if (pageAdd != null && pageAdd.trim().length() > 0) {
int pAdd = Integer.valueOf(pageAdd);
int pAdd = Integer.parseInt(pageAdd);
for (int i = 0; i < pAdd; i++) {
Sheet s = sheet.getSpreadSheet().getSheet(idSheet + i + 1);
MutableCell<SpreadSheet> cell2 = s.getCellAt(pageRef);
362,7 → 370,7
SQLRowAccessor foreign = row.getForeign(field.getName());
 
if (c == null) {
Map<Integer, SQLRowAccessor> map = new HashMap<Integer, SQLRowAccessor>();
Map<Integer, SQLRowAccessor> map = new HashMap<>();
map.put(i, foreign);
cacheForeign.put(field.getName(), map);
} else {
371,7 → 379,6
 
return foreign;
}
// return row.getForeignRow(field.getName());
 
}
 
384,7 → 391,7
SQLBackgroundTableCacheItem prefsCpt = SQLBackgroundTableCache.getInstance().getCacheForTable(tableElt.getTable("PREFS_COMPTE"));
if (tableElt.contains("ID_TAXE") && tableElt.contains("T_PA_HT")) {
boolean achat = tableElt.contains("T_PA_TTC");
TotalCalculator calc = new TotalCalculator("T_PA_HT", achat ? "T_PA_HT" : "T_PV_HT", null, achat, null);
TotalCalculator calc = new TotalCalculator("T_PA_HT", achat ? "T_PA_HT" : "T_PV_HT", null, achat, null, null);
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean bServiceActive = Boolean.valueOf(val);
 
487,7 → 494,7
Map<SQLRowAccessor, Tuple2<BigDecimal, BigDecimal>> taxeCalc = calc.getMapHtTVARowTaux();
for (SQLRowAccessor sqlRow : taxeCalc.keySet()) {
Tuple2<BigDecimal, BigDecimal> v = taxeCalc.get(sqlRow);
Map<String, Object> m = new HashMap<String, Object>();
Map<String, Object> m = new HashMap<>();
m.put("MONTANT_HT", v.get0());
m.put("MONTANT_TVA", v.get1());
taxe.put(sqlRow, m);
510,12 → 517,9
 
StyleSQLElement styleElt = Configuration.getInstance().getDirectory().getElement(StyleSQLElement.class);
 
boolean cache = false;
String ref = tableau.getAttributeValue("table") + "_" + row.getTable().getName() + row.getID();
if (rowsEltCache.get(ref) == null) {
rowsEltCache.put(ref, tableElement.getRows());
} else {
cache = true;
}
List<Element> listElts = tableau.getChildren("element");
 
553,10 → 557,10
}
 
// Cache des valeurs
Map<Element, Object> mapValues = new HashMap<Element, Object>();
Map<Element, Object> mapValues = new HashMap<>();
 
// Test si l'ensemble des donnees tient sur la page courante
Map<String, Integer> tmpMapNbCel = new HashMap<String, Integer>();
Map<String, Integer> tmpMapNbCel = new HashMap<>();
int tmpNbCellule = fillTableLine(sheet, mapStyle, true, rowLanguage, tableElement, currentLine, listElts, numeroRef, rowElt, tmpMapNbCel, styleName, mapValues);
for (String s : tmpMapNbCel.keySet()) {
tmpNbCellule = Math.max(tmpNbCellule, tmpMapNbCel.get(s));
569,7 → 573,7
}
 
// Remplissage reel des cellules
Map<String, Integer> mapNbCel = new HashMap<String, Integer>();
Map<String, Integer> mapNbCel = new HashMap<>();
int nbCellule = fillTableLine(sheet, mapStyle, test, rowLanguage, tableElement, currentLine, listElts, numeroRef, rowElt, mapNbCel, styleName, mapValues);
 
for (String s : mapNbCel.keySet()) {
707,7 → 711,7
 
private void fillTaxeDocumentMap(Element tableau, Sheet sheet, Map<String, Map<Integer, String>> mapStyle, boolean test) {
 
int line = Integer.valueOf(tableau.getAttributeValue("firstLine"));
int line = Integer.parseInt(tableau.getAttributeValue("firstLine"));
List<Element> listElts = tableau.getChildren("element");
 
for (SQLRowAccessor rowTaxe : taxe.keySet()) {
953,12 → 957,10
}
 
// Copie de l'odsp
try {
File odspOut = new File(pathDest, fileName + ".odsp");
final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, langage, null);
try (final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, langage, null);) {
if (odspIn != null) {
StreamUtils.copy(odspIn, odspOut);
odspIn.close();
}
} catch (FileNotFoundException e) {
System.err.println("OOgenerationXML.saveSpreadSheet() : Le fichier odsp n'existe pas.");
985,7 → 987,7
System.err.println("End row search : " + rowCount);
for (int i = 0; i < rowCount; i++) {
int x = 0;
Map<Integer, String> mapCellStyle = new HashMap<Integer, String>();
Map<Integer, String> mapCellStyle = new HashMap<>();
String style = "";
 
for (int j = 0; j < columnCount; j++) {
1045,7 → 1047,7
List<Element> listTable = racine.getChildren("table");
 
Element tableau;
if (listTable.size() == 0) {
if (listTable.isEmpty()) {
return false;
} else {
if (listTable.get(0).getAttributeValue("table").equalsIgnoreCase("TVA")) {
1058,7 → 1060,7
 
Object oLastColTmp = tableau.getAttributeValue("lastColumn");
int lastColumn = -1;
int endPageLine = Integer.valueOf(tableau.getAttributeValue("endPageLine"));
int endPageLine = Integer.parseInt(tableau.getAttributeValue("endPageLine"));
if (oLastColTmp != null) {
lastColumn = sheet.resolveHint(oLastColTmp.toString() + 1).x + 1;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationListeXML.java
24,12 → 24,16
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.StreamUtils;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.io.BOMSkipper;
 
import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
62,7 → 66,11
if (xmlConfiguration == null) {
throw new IllegalStateException("Template configuration " + templateId + " not found (" + TemplateManager.getInstance().getClass().getName() + ")");
}
Document doc = builder.build(xmlConfiguration);
final BufferedReader xmlConfigurationReader = new BufferedReader(new InputStreamReader(xmlConfiguration, Charset.forName("UTF8")));
BOMSkipper.skip(xmlConfigurationReader);
final Document doc = builder.build(xmlConfigurationReader);
xmlConfigurationReader.close();
xmlConfiguration.close();
 
// On initialise un nouvel élément racine avec l'élément racine du
// document.
74,6 → 82,7
throw new IllegalStateException("Template " + templateId + " not found (" + TemplateManager.getInstance().getClass().getName() + ")");
}
final SpreadSheet spreadSheet = new ODPackage(template).getSpreadSheet();
 
Sheet sheet0 = spreadSheet.getSheet(0);
if (sheetName != null && sheetName.size() > 0) {
for (int i = 1; i < sheetName.size(); i++) {
83,7 → 92,12
}
 
for (Integer i : liste.keySet()) {
final Sheet sheet = spreadSheet.getSheet(i);
final Sheet sheet;
try {
sheet = spreadSheet.getSheet(i);
} catch (Exception e) {
throw new InvalidTemplateException("La feuille numéro " + i + " n'est pas dans le modèle", e);
}
List children = racine.getChildren("element" + i);
if (children.size() == 0) {
children = racine.getChildren("element");
96,6 → 110,7
parseListeXML(child, liste.get(i), sheet, mapStyle.get(i));
}
cacheStyle.clear();
 
// Sauvegarde du fichier
return saveSpreadSheet(spreadSheet, pathDest, fileDest, templateId, rowLanguage);
 
555,9 → 570,8
}
 
// Copie de l'odsp
try {
File odspOut = new File(pathDest, fileName + ".odsp");
InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);
try (final InputStream odspIn = TemplateManager.getInstance().getTemplatePrintConfiguration(templateId, rowLanguage != null ? rowLanguage.getString("CHEMIN") : null, null);) {
if (odspIn != null) {
StreamUtils.copy(odspIn, odspOut);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLCache.java
24,6 → 24,7
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelectJoin;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.CompareUtils;
301,8 → 302,11
if (orderBy != null && orderBy.contains(".")) {
String fieldRefTable = orderBy.substring(0, orderBy.indexOf('.'));
String field = orderBy.substring(orderBy.indexOf('.') + 1, orderBy.length());
if (sel.getJoin(tableForeign.getField(fieldRefTable)) == null) {
sel.addJoin("LEFT", sel.getAlias(tableForeign).getField(fieldRefTable));
sel.addFieldOrder(sel.getAlias(tableForeign.getForeignTable(fieldRefTable)).getField(field));
}
SQLSelectJoin join = sel.getJoin(tableForeign.getField(fieldRefTable));
sel.addFieldOrder(join.getJoinedTable().getField(field));
} else {
sel.addFieldOrder(tableForeign.getOrderField());
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtTicketCaisse.java
79,7 → 79,7
GenerationMvtTicketCaisse.this.putValue("ID_MOUVEMENT", Integer.valueOf(GenerationMvtTicketCaisse.this.idMvt));
}
 
TotalCalculator calc = getValuesFromElement(rowTicket, rowTicket.getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT"), BigDecimal.ZERO, null, null);
TotalCalculator calc = getValuesFromElement(rowTicket, rowTicket.getTable().getTable("SAISIE_VENTE_FACTURE_ELEMENT"), BigDecimal.ZERO, null, BigDecimal.ZERO, null, null);
long ttcLongValue = calc.getTotalTTC().movePointRight(2).longValue();
 
// compte Vente Produits
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationEcritures.java
19,6 → 19,7
import org.openconcerto.erp.core.common.ui.TotalCalculator;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.generationDoc.OOXMLCache;
import org.openconcerto.erp.generationEcritures.provider.AnalytiqueProvider;
import org.openconcerto.erp.generationEcritures.provider.AnalytiqueProviderManager;
import org.openconcerto.erp.preferences.DefaultNXProps;
26,11 → 27,13
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLBackgroundTableCacheItem;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
40,6 → 43,7
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
92,6 → 96,9
return this.rowAnalytiqueSource;
}
 
private Date dDebEx = null;
private Date dCloture = null;
 
/**
* Ajout d'une écriture et maj des totaux du compte associé
*
106,7 → 113,8
// Report des valeurs pour accelerer les IListes
Number n = (Number) this.mEcritures.get("ID_JOURNAL");
if (n != null) {
SQLRow rowJrnl = journalTable.getRow(n.intValue());
final SQLBackgroundTableCacheItem cacheForTableJrnl = SQLBackgroundTableCache.getInstance().getCacheForTable(journalTable);
SQLRow rowJrnl = cacheForTableJrnl.getRowFromId(n.intValue());
if (rowJrnl == null) {
throw new IllegalArgumentException("Le journal qui a pour ID " + n + " a été archivé.");
}
116,7 → 124,11
 
Number n2 = (Number) this.mEcritures.get("ID_COMPTE_PCE");
if (n2 != null) {
SQLRow rowCpt = compteTable.getRow(n2.intValue());
final SQLBackgroundTableCacheItem cacheForTableCpt = SQLBackgroundTableCache.getInstance().getCacheForTable(compteTable);
SQLRow rowCpt = cacheForTableCpt.getRowFromId(n2.intValue());
if (rowCpt == null) {
rowCpt = compteTable.getRow(n2.intValue());
}
this.mEcritures.put("COMPTE_NUMERO", rowCpt.getString("NUMERO"));
this.mEcritures.put("COMPTE_NOM", rowCpt.getString("NOM"));
}
143,17 → 155,18
// TODO checker que les ecritures sont entrees à une date correcte
Date d = (Date) this.mEcritures.get("DATE");
 
if (this.dDebEx == null) {
SQLTable tableExercice = Configuration.getInstance().getBase().getTable("EXERCICE_COMMON");
SQLRow rowSociete = ((ComptaPropsConfiguration) Configuration.getInstance()).getRowSociete();
SQLRow rowExercice = tableExercice.getRow(rowSociete.getInt("ID_EXERCICE_COMMON"));
Date dDebEx = (Date) rowExercice.getObject("DATE_DEB");
this.dDebEx = (Date) rowExercice.getObject("DATE_DEB");
this.dCloture = (Date) rowExercice.getObject("DATE_CLOTURE");
}
 
Date dCloture = (Date) rowExercice.getObject("DATE_CLOTURE");
 
if (dCloture != null) {
if (dCloture.after(d)) {
final String error = "Impossible de générer l'écriture pour la date " + SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL).format(d)
+ ". Cette date est postérieure à la date de clôture (" + SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL).format(dCloture) + ")";
+ ". Cette date est antérieure à la date de clôture (" + SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL).format(dCloture) + ")";
throw new IllegalArgumentException(error);
}
} else {
168,17 → 181,14
valEcriture.put("IDUSER_CREATE", UserManager.getInstance().getCurrentUser().getId());
 
try {
if (valEcriture.getInvalid() == null) {
// ajout de l'ecriture
SQLRow ecritureRow = valEcriture.insert();
// SQLRow ecritureRow = valEcriture.insert();
SQLRow ecritureRow = valEcriture.getGraph().store(StoreMode.INSERT, false).getStoredRow(valEcriture);
 
// TODO Analytique
addAssocAnalytiqueFromProvider(ecritureRow, this.rowAnalytiqueSource);
return ecritureRow;
} else {
System.err.println("GenerationEcritures.java :: Error in values for insert in table " + GenerationEcritures.ecritureTable.getName() + " : " + valEcriture.toString());
throw new IllegalArgumentException("Erreur lors de la génération des écritures données incorrectes. " + valEcriture);
}
 
} catch (SQLException e) {
System.err.println("Error insert row in " + GenerationEcritures.ecritureTable.getName() + " : " + e);
final SQLException eFinal = e;
368,27 → 378,41
return getNewMouvement(source, idSource, idPere, rowValsPiece);
}
 
protected TotalCalculator getValuesFromElement(SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, SQLTable tableEchantillon) {
return getValuesFromElement(false, false, "T_PV_HT", row, foreign, portHT, rowTVAPort, tableEchantillon, null);
protected TotalCalculator getValuesFromElement(SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, BigDecimal fraisDocHT, SQLRow rowTVAFraisDoc, SQLTable tableEchantillon) {
return getValuesFromElement(false, false, "T_PV_HT", row, foreign, portHT, rowTVAPort, fraisDocHT, rowTVAFraisDoc, tableEchantillon, null);
}
 
protected TotalCalculator getValuesFromElement(boolean intra, boolean achat, String fieldTotalHT, SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, SQLTable tableEchantillon,
SQLRow defaultCompte) {
protected TotalCalculator getValuesFromElement(boolean intra, boolean achat, String fieldTotalHT, SQLRow row, SQLTable foreign, BigDecimal portHT, SQLRow rowTVAPort, BigDecimal fraisDocHT,
SQLRow rowTVAFraisDoc, SQLTable tableEchantillon, SQLRow defaultCompte) {
 
TotalCalculator calc = new TotalCalculator("T_PA_HT", fieldTotalHT, null, achat, defaultCompte);
final SQLRow tiers;
if (achat) {
tiers = row.getForeign("ID_FOURNISSEUR");
} else {
tiers = row.getForeign("ID_CLIENT");
}
 
SQLRowAccessor rowCatCompta = null;
if (tiers.getObject("ID_CATEGORIE_COMPTABLE") != null && !tiers.isForeignEmpty("ID_CATEGORIE_COMPTABLE")) {
rowCatCompta = tiers.getForeign("ID_CATEGORIE_COMPTABLE");
}
TotalCalculator calc = new TotalCalculator("T_PA_HT", fieldTotalHT, null, achat, defaultCompte, rowCatCompta);
calc.setIntraComm(intra);
 
String val = DefaultNXProps.getInstance().getStringProperty("ArticleService");
Boolean bServiceActive = Boolean.valueOf(val);
 
calc.setServiceActive(bServiceActive != null && bServiceActive);
 
SQLBackgroundTableCacheItem cacheCompte = SQLBackgroundTableCache.getInstance().getCacheForTable(compteTable);
if (row.getTable().contains("ID_COMPTE_PCE_SERVICE") && !row.isForeignEmpty("ID_COMPTE_PCE_SERVICE")) {
SQLRowAccessor serviceCompte = row.getForeign("ID_COMPTE_PCE_SERVICE");
if (!serviceCompte.isUndefined()) {
SQLRowAccessor serviceCompte = cacheCompte.getRowFromId(row.getForeignID("ID_COMPTE_PCE_SERVICE"));
if (serviceCompte != null && !serviceCompte.isUndefined()) {
calc.setRowDefaultCptService(serviceCompte);
}
}
if (row.getTable().contains("ID_COMPTE_PCE_VENTE") && !row.isForeignEmpty("ID_COMPTE_PCE_VENTE")) {
SQLRowAccessor produitCompte = row.getForeign("ID_COMPTE_PCE_VENTE");
SQLRowAccessor produitCompte = cacheCompte.getRowFromId(row.getForeignID("ID_COMPTE_PCE_VENTE"));
if (!produitCompte.isUndefined()) {
calc.setRowDefaultCptProduit(produitCompte);
}
395,11 → 419,14
}
long remise = 0;
BigDecimal totalAvtRemise = BigDecimal.ZERO;
OOXMLCache cacheRefRows = new OOXMLCache();
final List<? extends SQLRowAccessor> referentRows = cacheRefRows.getReferentRows(Arrays.asList(row), foreign);
if (row.getTable().contains("REMISE_HT")) {
remise = row.getLong("REMISE_HT");
if (remise != 0) {
List<SQLRow> rows = row.getReferentRows(foreign);
for (SQLRow sqlRow : rows) {
 
// List<SQLRow> rows = row.getReferentRows(foreign);
for (SQLRowAccessor sqlRow : referentRows) {
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), 1, false);
}
 
429,10 → 456,10
}
calc.setRemise(valRemiseHTReel, totalAvtRemise);
 
List<SQLRow> rows = row.getReferentRows(foreign);
for (int i = 0; i < rows.size(); i++) {
SQLRow sqlRow = rows.get(i);
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), i, i == rows.size() - 1);
// List<SQLRow> rows = row.getReferentRows(foreign);
for (int i = 0; i < referentRows.size(); i++) {
SQLRowAccessor sqlRow = referentRows.get(i);
calc.addLine(sqlRow, sqlRow.getForeign("ID_ARTICLE"), i, i == referentRows.size() - 1);
}
 
if (tableEchantillon != null) {
448,10 → 475,10
rowValsPort.put("ID_TAXE", rowTVAPort.getIDNumber());
 
final SQLTable tablePrefCompte = Configuration.getInstance().getRoot().findTable("PREFS_COMPTE");
final SQLRow rowPrefsCompte = tablePrefCompte.getRow(2);
final SQLRow rowPrefsCompte = SQLBackgroundTableCache.getInstance().getCacheForTable(tablePrefCompte).getRowFromId(2);
SQLRow rowDefaultCptPort;
if (rowTVAPort.getFloat("TAUX") > 0) {
rowDefaultCptPort = rowPrefsCompte.getForeign("ID_COMPTE_PCE_PORT_SOUMIS");
rowDefaultCptPort = cacheCompte.getRowFromId(rowPrefsCompte.getForeignID("ID_COMPTE_PCE_PORT_SOUMIS"));
if (rowDefaultCptPort == null || rowDefaultCptPort.isUndefined()) {
try {
rowDefaultCptPort = ComptePCESQLElement.getRowComptePceDefault("PortVenteSoumisTVA");
460,7 → 487,7
}
}
} else {
rowDefaultCptPort = rowPrefsCompte.getForeign("ID_COMPTE_PCE_PORT_NON_SOUMIS");
rowDefaultCptPort = cacheCompte.getRowFromId(rowPrefsCompte.getForeignID("ID_COMPTE_PCE_PORT_NON_SOUMIS"));
if (rowDefaultCptPort == null || rowDefaultCptPort.isUndefined()) {
try {
rowDefaultCptPort = ComptePCESQLElement.getRowComptePceDefault("PortVenteNonSoumisTVA");
472,8 → 499,21
final SQLRowValues rowValsArt = rowValsPort.putRowValues("ID_ARTICLE");
rowValsArt.put(achat ? "ID_COMPTE_PCE_ACHAT" : "ID_COMPTE_PCE", rowDefaultCptPort.getID());
rowValsArt.put("ID_TAXE_COMPLEMENTAIRE", null);
rowValsArt.put("ID_FAMILLE_ARTICLE", null);
calc.addLine(rowValsPort, rowValsPort.getForeign("ID_ARTICLE"), 1, false);
}
 
if (rowTVAFraisDoc != null && !rowTVAFraisDoc.isUndefined()) {
// Frais documents
SQLRowValues rowValsFraisDoc = new SQLRowValues(foreign);
rowValsFraisDoc.put(achat ? "T_PA_HT" : "T_PV_HT", fraisDocHT);
rowValsFraisDoc.put("QTE", 1);
rowValsFraisDoc.put("ID_TAXE", rowTVAFraisDoc.getIDNumber());
rowValsFraisDoc.put("SERVICE", Boolean.TRUE);
rowValsFraisDoc.put("ID_FAMILLE_ARTICLE", null);
calc.addLine(rowValsFraisDoc, null, 1, false);
}
 
calc.checkResult();
return calc;
}
646,4 → 686,5
}
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtAvoirClient.java
100,9 → 100,10
 
TotalCalculator calc;
if (rowClient.getTable().contains("ID_COMPTE_PCE_PRODUIT") && !rowClient.isForeignEmpty("ID_COMPTE_PCE_PRODUIT")) {
calc = getValuesFromElement(false, false, "T_PV_HT", avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, null, rowClient.getForeign("ID_COMPTE_PCE_PRODUIT"));
calc = getValuesFromElement(false, false, "T_PV_HT", avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, BigDecimal.ZERO, null, null,
rowClient.getForeign("ID_COMPTE_PCE_PRODUIT"));
} else {
calc = getValuesFromElement(avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, null);
calc = getValuesFromElement(avoirRow, avoirRow.getTable().getTable("AVOIR_CLIENT_ELEMENT"), portHT, null, BigDecimal.ZERO, null, null);
}
Map<SQLRowAccessor, Map<SQLRowAccessor, BigDecimal>> taxeCompl = calc.getMapHtTaxeCompl();
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementVenteNG.java
63,7 → 63,12
 
public GenerationReglementVenteNG(String label, SQLRow rowClient, PrixTTC ttc, Date d, SQLRow modeReglement, SQLRow source, SQLRow mvtSource, boolean createEncaisse, boolean avance)
throws Exception {
this(label, rowClient, ttc, d, modeReglement, source, mvtSource, createEncaisse, avance, rowClient.getString("NOM"), null);
}
 
public GenerationReglementVenteNG(String label, SQLRow rowClient, PrixTTC ttc, Date d, SQLRow modeReglement, SQLRow source, SQLRow mvtSource, boolean createEncaisse, boolean avance, String tiers,
SQLRowAccessor cptTiers) throws Exception {
 
SQLRow typeRegRow = modeReglement.getForeignRow("ID_TYPE_REGLEMENT");
setRowAnalytiqueSource(source);
// iniatilisation des valeurs de la map
107,7 → 112,8
if (createEncaisse) {
SQLRowValues rowVals = new SQLRowValues(tableEncaisse);
rowVals.put("MONTANT", ttc.getLongValue());
rowVals.put("ID_CLIENT", rowClient.getID());
rowVals.put("ID_CLIENT", rowClient != null ? rowClient.getID() : null);
rowVals.put("TIERS", tiers);
rowVals.put("DATE", this.date);
if (typeRegRow.getID() >= TypeReglementSQLElement.TRAITE) {
Calendar c2 = modeReglement.getDate("DATE_VIREMENT");
154,9 → 160,9
 
Calendar c = modeReglement.getDate("DATE_DEPOT");
if (c != null) {
paiementCheque(c.getTime(), source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance);
paiementCheque(c.getTime(), source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance, tiers, cptTiers);
} else {
paiementCheque(this.date, source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance);
paiementCheque(this.date, source, ttc, rowClient, modeReglement, mvtSource.getTable().getRow(idMvt), avance, tiers, cptTiers);
}
 
} else {
176,7 → 182,7
this.putValue("ID_JOURNAL", JournalSQLElement.CAISSES);
}
 
int idCompteClient = rowClient.getInt("ID_COMPTE_PCE");
int idCompteClient = cptTiers != null && !cptTiers.isUndefined() ? cptTiers.getID() : rowClient.getInt("ID_COMPTE_PCE");
if (avance) {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_AVANCE_CLIENT");
if (idCompteClient <= 1) {
239,7 → 245,9
valEcheance.put("ID_MOUVEMENT", Integer.valueOf(this.idMvt));
valEcheance.put("DATE", dateEch);
valEcheance.put("MONTANT", Long.valueOf(ttc.getLongValue()));
valEcheance.put("ID_CLIENT", rowClient.getID());
valEcheance.put("ID_CLIENT", rowClient == null ? null : rowClient.getID());
valEcheance.put("TIERS", tiers);
valEcheance.put("ID_COMPTE_PCE_TIERS", cptTiers == null || !cptTiers.isUndefined() ? null : cptTiers.getID());
if (source.getTable().equals(tableSaisieVenteFacture)) {
valEcheance.put("ID_SAISIE_VENTE_FACTURE", source.getID());
}
334,13 → 342,15
}
}
 
private void paiementCheque(Date dateEch, SQLRow source, PrixTTC ttc, SQLRow rowClient, SQLRow modeRegl, SQLRow mvtSource, boolean avance) throws Exception {
private void paiementCheque(Date dateEch, SQLRow source, PrixTTC ttc, SQLRow rowClient, SQLRow modeRegl, SQLRow mvtSource, boolean avance, String tiers, SQLRowAccessor cptTiers) throws Exception {
 
SQLRowValues valCheque = new SQLRowValues(base.getTable("CHEQUE_A_ENCAISSER"));
SQLPreferences prefs = SQLPreferences.getMemCached(valCheque.getTable().getDBRoot());
boolean createEcr = prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CREATE_ECR_CHQ, true);
 
valCheque.put("ID_CLIENT", rowClient.getID());
valCheque.put("ID_CLIENT", rowClient == null ? null : rowClient.getID());
valCheque.put("ID_COMPTE_PCE_TIERS", cptTiers == null ? null : cptTiers.getID());
valCheque.put("TIERS", tiers);
valCheque.put("SANS_VALEUR_ENCAISSEMENT", !createEcr);
final String foreignBanqueFieldName = "ID_" + BanqueSQLElement.TABLENAME;
if (valCheque.getTable().contains(foreignBanqueFieldName))
364,7 → 374,7
}
 
if (createEcr) {
int idCompteClient = rowClient.getInt("ID_COMPTE_PCE");
int idCompteClient = cptTiers == null || cptTiers.isUndefined() ? rowClient.getInt("ID_COMPTE_PCE") : cptTiers.getID();
if (avance) {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_AVANCE_CLIENT");
if (idCompteClient <= 1) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtAvoirFournisseur.java
15,9 → 15,11
 
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.model.PrixHT;
import org.openconcerto.erp.model.PrixTTC;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
 
91,6 → 93,7
SQLRow rowEcr = ajoutEcriture();
// addAssocAnalytiqueFromProvider(rowEcr, avoirRow);
 
SQLRowAccessor taxe = TaxeCache.getCache().getRowFromId(avoirRow.getForeignID("ID_TAXE"));
if (prixTVA.getLongValue() > 0) {
// compte TVA
int idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
100,11 → 103,21
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVAImmo");
}
} else {
if (rowFourn.getBoolean("UE")) {
idCompteTVA = taxe.getForeignID("ID_COMPTE_PCE_DED_INTRA");
if (idCompteTVA <= 1) {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVAIntraComm");
}
}
} else {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVADeductible");
}
}
}
 
this.putValue("ID_COMPTE_PCE", Integer.valueOf(idCompteTVA));
this.putValue("DEBIT", Long.valueOf(0));
112,10 → 125,13
ajoutEcriture();
 
if (rowFourn.getBoolean("UE")) {
int idCompteTVAIntra = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
int idCompteTVAIntra = taxe.getForeignID("ID_COMPTE_PCE_COLLECTE_INTRA");
if (idCompteTVAIntra <= 1) {
idCompteTVAIntra = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
if (idCompteTVAIntra <= 1) {
idCompteTVAIntra = ComptePCESQLElement.getIdComptePceDefault("TVAIntraComm");
}
}
this.putValue("ID_COMPTE_PCE", Integer.valueOf(idCompteTVAIntra));
this.putValue("DEBIT", Long.valueOf(prixTVA.getLongValue()));
this.putValue("CREDIT", Long.valueOf(0));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtSaisieVenteFacture.java
139,12 → 139,14
 
SQLTable tableEchantillon = null;
BigDecimal portHT = BigDecimal.valueOf(saisieRow.getLong("PORT_HT")).movePointLeft(2);
BigDecimal fraisDocHT = BigDecimal.valueOf(saisieRow.getLong("FRAIS_DOCUMENT_HT")).movePointLeft(2);
TotalCalculator calc;
if (clientRow.getTable().contains("ID_COMPTE_PCE_PRODUIT") && !clientRow.isForeignEmpty("ID_COMPTE_PCE_PRODUIT")) {
calc = getValuesFromElement(false, false, "T_PV_HT", saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), tableEchantillon,
clientRow.getForeign("ID_COMPTE_PCE_PRODUIT"));
calc = getValuesFromElement(false, false, "T_PV_HT", saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), fraisDocHT,
saisieRow.getForeign("ID_TAXE_FRAIS_DOCUMENT"), tableEchantillon, clientRow.getForeign("ID_COMPTE_PCE_PRODUIT"));
} else {
calc = getValuesFromElement(saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), tableEchantillon);
calc = getValuesFromElement(saisieRow, saisieVFTable.getTable("SAISIE_VENTE_FACTURE_ELEMENT"), portHT, saisieRow.getForeign("ID_TAXE_PORT"), fraisDocHT,
saisieRow.getForeign("ID_TAXE_FRAIS_DOCUMENT"), tableEchantillon);
}
 
// On génére les ecritures si la facture n'est pas un acompte
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementAchat.java
72,6 → 72,9
}
 
SQLRow rowMvtSource = tableMouvement.getRow(mvtSource);
if (rowMvtSource == null) {
throw new IllegalStateException("Aucun mouvement source associé aux échéances.\n(Mouvement source : " + mvtSource + ", REGLER_MONTANT " + regMontantRow.getID() + ")");
}
 
// si paiement comptant
if ((modeRegRow.getInt("AJOURS") == 0) && (modeRegRow.getInt("LENJOUR") == 0)) {
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtFactureFournisseur.java
96,7 → 96,7
}
BigDecimal portHT = BigDecimal.valueOf(saisieRow.getLong("PORT_HT")).movePointLeft(2);
TotalCalculator calc = getValuesFromElement(rowFournisseur.getBoolean("UE"), true, "T_PA_HT", saisieRow, saisieRow.getTable().getTable("FACTURE_FOURNISSEUR_ELEMENT"), portHT,
saisieRow.getForeign("ID_TAXE_PORT"), null, rowCompteAchat);
saisieRow.getForeign("ID_TAXE_PORT"), BigDecimal.ZERO, null, null, rowCompteAchat);
 
long ttcLongValue = calc.getTotalTTC().movePointRight(2).longValue();
long htLongValue = calc.getTotalHT().movePointRight(2).longValue();
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtReglementFactureFournisseur.java
70,7 → 70,7
// long l = ((Number) avoirRow.getObject("MONTANT_TTC")).longValue();
// prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue() - l);
// } else {
prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue());
prixTTC = new PrixTTC(((Long) saisieRow.getObject("NET_A_PAYER")).longValue());
// }
 
this.date = (Date) saisieRow.getObject("DATE");
192,7 → 192,7
// long l = ((Number) avoirRow.getObject("MONTANT_TTC")).longValue();
// prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue() - l);
// } else {
prixTTC = new PrixTTC(((Long) saisieRow.getObject("T_TTC")).longValue());
prixTTC = new PrixTTC(((Long) saisieRow.getObject("NET_A_PAYER")).longValue());
// }
 
// Ajout dans cheque fournisseur
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtDepotChequeClient.java
New file
0,0 → 1,174
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
 
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.erp.core.common.element.BanqueSQLElement;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesCluster.StoreMode;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.StringUtils;
 
import java.util.ArrayList;
import java.util.List;
 
public class GenerationMvtDepotChequeClient extends GenerationEcritures {
 
private long montant;
 
private static final SQLTable tablePrefCompte = base.getTable("PREFS_COMPTE");
private static final SQLRow rowPrefsCompte = tablePrefCompte.getRow(2);
private final SQLRow depot;
private SQLRowAccessor banque;
 
public GenerationMvtDepotChequeClient(SQLRow depot) {
this.montant = depot.getLong("MONTANT");
this.date = depot.getDate("DATE").getTime();
this.banque = depot.getForeign("ID_" + BanqueSQLElement.TABLENAME);
this.depot = depot;
// SQLRow chequeRow = base.getTable("CHEQUE_A_ENCAISSER").getRow(this.idCheque);
// String num = "";
// if (chequeRow != null && !chequeRow.isUndefined() &&
// chequeRow.getString("NUMERO").trim().length() > 0) {
// num = " N° " + chequeRow.getString("NUMERO");
// }
//
// if (s != null && s.trim().length() > 0) {
// this.nom = s + (num.trim().length() > 0 ? " - Cheque" + num : "");
// } else {
// this.nom = "Reglement cheque client" + num;
// }
}
 
public void genere() throws Exception {
System.err.println("génération des ecritures de règlement d'un cheque client du mouvement " + this.idMvt);
this.nom = this.depot.getString("NOM");
if (this.depot.getObject("ID_MOUVEMENT") == null || this.depot.isForeignEmpty("ID_MOUVEMENT")) {
this.idMvt = getNewMouvement(depot.getTable().getName(), depot.getID(), 1, this.nom);
} else {
this.idMvt = this.depot.getForeignID("ID_MOUVEMENT");
SQLRowValues rowValspiece = this.depot.getForeign("ID_MOUVEMENT").getForeign("ID_PIECE").createEmptyUpdateRow();
rowValspiece.put("NOM", this.nom);
rowValspiece.update();
}
 
// initialisation des valeurs de la map
this.putValue("ID_MOUVEMENT", new Integer(this.idMvt));
this.putValue("DATE", new java.sql.Date(this.date.getTime()));
this.putValue("NOM", this.nom);
if (this.banque == null || this.banque.isUndefined() || this.banque.isForeignEmpty("ID_JOURNAL")) {
fillJournalBanqueFromRow(depot);
} else {
int idJrnl = this.banque.getForeignID("ID_JOURNAL");
this.putValue("ID_JOURNAL", idJrnl);
}
 
List<Integer> pieceIDs = new ArrayList<Integer>();
SQLRowValues rowValsDepotElt = new SQLRowValues(depot.getTable().getTable("DEPOT_CHEQUE_ELEMENT"));
rowValsDepotElt.putNulls("MONTANT", "TIERS");
rowValsDepotElt.putRowValues("ID_CLIENT").putNulls("NOM", "ID_COMPTE_PCE");
final SQLRowValues rowValuesChq = rowValsDepotElt.putRowValues("ID_CHEQUE_A_ENCAISSER");
rowValuesChq.putNulls("SANS_VALEUR_ENCAISSEMENT").putRowValues("ID_MOUVEMENT").putNulls("ID_PIECE");
rowValuesChq.putNulls("ID_COMPTE_PCE_TIERS").putNulls("NUMERO");
List<SQLRowValues> cheques = SQLRowValuesListFetcher.create(rowValsDepotElt).fetch(new Where(rowValsDepotElt.getTable().getField("ID_DEPOT_CHEQUE"), "=", depot.getID()));
for (SQLRowValues sqlRowAccessor : cheques) {
final SQLRowAccessor clientRow = sqlRowAccessor.getForeign("ID_CLIENT");
// this.nom = this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20);
this.putValue("NOM", this.nom + " " + StringUtils.limitLength(clientRow.getString("NOM"), 20));
SQLRowAccessor chequeRow = sqlRowAccessor.getForeign("ID_CHEQUE_A_ENCAISSER");
pieceIDs.add(chequeRow.getForeign("ID_MOUVEMENT").getForeignID("ID_PIECE"));
// compte Clients
SQLRowAccessor rowCptTiers = chequeRow.getForeign("ID_COMPTE_PCE_TIERS");
int idCompteClient = rowCptTiers != null && !rowCptTiers.isUndefined() ? rowCptTiers.getID() : -1;
 
if (chequeRow.getBoolean("SANS_VALEUR_ENCAISSEMENT")) {
if (idCompteClient == -1) {
if (clientRow != null) {
idCompteClient = clientRow.getInt("ID_COMPTE_PCE");
}
if (idCompteClient <= 1) {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_CLIENT");
if (idCompteClient <= 1) {
idCompteClient = ComptePCESQLElement.getIdComptePceDefault("Clients");
}
}
}
} else {
idCompteClient = rowPrefsCompte.getInt("ID_COMPTE_PCE_VALEUR_ENCAISSEMENT");
if (idCompteClient <= 1) {
idCompteClient = ComptePCESQLElement.getIdComptePceDefault("ValeurEncaissement");
}
}
 
this.putValue("ID_COMPTE_PCE", new Integer(idCompteClient));
this.putValue("DEBIT", new Long(0));
this.putValue("CREDIT", new Long(sqlRowAccessor.getLong("MONTANT")));
SQLRow insertedRow = ajoutEcriture();
 
sqlRowAccessor.createEmptyUpdateRow().put("ID_ECRITURE", insertedRow.getID()).getGraph().store(StoreMode.COMMIT, false);
sqlRowAccessor.getForeign("ID_CHEQUE_A_ENCAISSER").createEmptyUpdateRow().put("ENCAISSE", Boolean.TRUE).getGraph().store(StoreMode.COMMIT, false);
}
// compte de reglement cheque, ...
fillCompteBanqueFromRow(depot, "VenteCheque", false);
this.putValue("NOM", this.nom);
this.putValue("DEBIT", new Long(this.montant));
this.putValue("CREDIT", new Long(0));
SQLRow insertedRow = ajoutEcriture();
 
depot.createEmptyUpdateRow().put("ID_MOUVEMENT", idMvt).put("ID_ECRITURE", insertedRow.getID()).getGraph().store(StoreMode.COMMIT, false);
 
pieceIDs.add(mouvementTable.getRow(idMvt).getForeignID("ID_PIECE"));
lettrageAuto(pieceIDs, this.date);
 
System.err.println("Ecritures générées pour le mouvement " + this.idMvt);
 
}
 
// private void setDateReglement(int idCheque, Date d) throws SQLException {
// if (idCheque > 1) {
// SQLRow chequeRow =
// Configuration.getInstance().getBase().getTable("CHEQUE_A_ENCAISSER").getRow(idCheque);
// final int sourceId = MouvementSQLElement.getSourceId(chequeRow.getInt("ID_MOUVEMENT"));
// SQLRow rowMvt = Configuration.getInstance().getBase().getTable("MOUVEMENT").getRow(sourceId);
//
// if (rowMvt.getString("SOURCE").equalsIgnoreCase("SAISIE_VENTE_FACTURE")) {
// SQLElement eltFacture =
// Configuration.getInstance().getDirectory().getElement("SAISIE_VENTE_FACTURE");
// SQLRow saisieRow = eltFacture.getTable().getRow(rowMvt.getInt("IDSOURCE"));
// // On fixe la date du paiement
// SQLRowValues rowValsUpdateVF = saisieRow.createEmptyUpdateRow();
// rowValsUpdateVF.put("DATE_REGLEMENT", new Timestamp(d.getTime()));
// rowValsUpdateVF.update();
// }
// }
// }
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/stock/element/ComposedItemStockUpdater.java
14,6 → 14,7
package org.openconcerto.erp.core.supplychain.stock.element;
 
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;
23,10 → 24,13
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
 
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
40,6 → 44,8
private final List<StockItem> itemsUpdated;
private final DBRoot root;
 
/// FIXME mettre à jour les stocks des kits à partir des feuilles
 
/**
* Met à jour les stocks des nomenclature composé par un des articles de itemsUpdated
*
59,14 → 65,22
public void update() throws SQLException {
// Liste des nomenclatures dépendantes des itemsUpdated
List<StockItem> items = getAllComposedItemToUpdate();
updateNomenclature(items);
}
 
public void updateNomenclature(List<StockItem> items) throws SQLException {
 
// Fecth des articles liés
getAllChildren(items);
 
List<StockItem> removedBadItem = new ArrayList<>();
// Mise à jour des stocks
for (StockItem stockItem : items) {
stockItem.updateQtyFromChildren();
if (!stockItem.updateQtyFromChildren()) {
removedBadItem.add(stockItem);
}
}
items.removeAll(removedBadItem);
 
SQLTable stockTable = root.getTable("STOCK");
List<String> requests = new ArrayList<String>();
73,7 → 87,7
for (StockItem stockItem : items) {
if (stockItem.isStockInit()) {
UpdateBuilder update = new UpdateBuilder(stockTable);
update.setWhere(new Where(stockTable.getKey(), "=", stockItem.getArticle().getForeign("ID_STOCK").getID()));
update.setWhere(new Where(stockTable.getKey(), "=", stockItem.stock.getID()));
update.setObject("QTE_REEL", stockItem.getRealQty());
update.setObject("QTE_TH", stockItem.getVirtualQty());
update.setObject("QTE_LIV_ATTENTE", stockItem.getDeliverQty());
85,11 → 99,16
rowVals.put("QTE_TH", stockItem.getVirtualQty());
rowVals.put("QTE_LIV_ATTENTE", stockItem.getDeliverQty());
rowVals.put("QTE_RECEPT_ATTENTE", stockItem.getReceiptQty());
rowVals.put("ID_ARTICLE", stockItem.getArticle().getID());
rowVals.put("ID_DEPOT_STOCK", stockItem.stock.getForeignID("ID_DEPOT_STOCK"));
rowVals.commit();
if (stockItem.getArticle().getForeignID("ID_DEPOT_STOCK") == stockItem.stock.getForeignID("ID_DEPOT_STOCK")) {
SQLRowValues rowValsArt = stockItem.getArticle().createEmptyUpdateRow();
rowValsArt.put("ID_STOCK", rowVals);
rowValsArt.commit();
}
}
}
 
List<? extends ResultSetHandler> handlers = new ArrayList<ResultSetHandler>(requests.size());
for (String s : requests) {
106,15 → 125,17
*/
private void getAllChildren(List<StockItem> items) {
final SQLTable tableArticle = this.root.getTable("ARTICLE");
final int undefDepot = tableArticle.getTable("DEPOT_STOCK").getUndefinedID();
final SQLRowValues rowValsArt = new SQLRowValues(tableArticle);
rowValsArt.put(tableArticle.getKey().getName(), null);
 
SQLRowValues rowValsStock = new SQLRowValues(tableArticle.getForeignTable("ID_STOCK"));
SQLRowValues rowValsStock = new SQLRowValues(this.root.getTable("STOCK"));
rowValsStock.put("QTE_REEL", null);
rowValsStock.put("QTE_TH", null);
rowValsStock.put("QTE_RECEPT_ATTENTE", null);
rowValsStock.put("QTE_LIV_ATTENTE", null);
rowValsArt.put("ID_STOCK", rowValsStock);
rowValsStock.put("ID_DEPOT_STOCK", null);
rowValsStock.put("ID_ARTICLE", rowValsArt);
 
final SQLTable tableArticleElt = this.root.getTable("ARTICLE_ELEMENT");
SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
124,12 → 145,14
rowValsArtItem.put("ID_ARTICLE_PARENT", null);
 
final List<Integer> ids = new ArrayList<Integer>();
Map<Integer, StockItem> mapItem = new HashMap<Integer, StockItem>();
Map<Tuple2<Integer, Integer>, StockItem> mapItem = new HashMap<Tuple2<Integer, Integer>, StockItem>();
for (StockItem stockItem : items) {
final int id = stockItem.getArticle().getID();
ids.add(id);
mapItem.put(id, stockItem);
if (stockItem.stock.getForeignID("ID_DEPOT_STOCK") != undefDepot) {
mapItem.put(Tuple2.create(id, stockItem.stock.getForeignID("ID_DEPOT_STOCK")), stockItem);
}
}
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsArtItem);
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
147,10 → 170,48
 
final SQLRowAccessor article = sqlRowValues.getForeign("ID_ARTICLE");
final SQLRowAccessor articleParent = sqlRowValues.getForeign("ID_ARTICLE_PARENT");
mapItem.get(articleParent.getID()).addItemComponent(new StockItemComponent(new StockItem(article), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
if (article != null && !article.isUndefined()) {
final Collection<? extends SQLRowAccessor> referentStockRows = article.getReferentRows(this.root.getTable("STOCK"));
 
{
// Init Stock if no depot
if (referentStockRows.size() == 0) {
// init default stock depot
SQLRowValues rowVals = new SQLRowValues(article.getTable().getTable("STOCK"));
rowVals.put("ID_ARTICLE", article.getID());
rowVals.put("ID_DEPOT_STOCK", DepotStockSQLElement.DEFAULT_ID);
try {
SQLRow rowStock = rowVals.commit();
article.createEmptyUpdateRow().put("ID_STOCK", rowStock.getID()).commit();
 
System.err.println("NO DEPOT STOCK FOR ITEM " + articleParent.getID() + " -- PARENT " + articleParent.getID());
StockItem stockItem = mapItem.get(Tuple2.create(articleParent.getID(), DepotStockSQLElement.DEFAULT_ID));
if (stockItem != null) {
stockItem.addItemComponent(new StockItemComponent(new StockItem(article, rowStock), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
} else {
System.err.println("Unable to find stock of item ARTICLE " + articleParent.getID() + " DEPOT " + DepotStockSQLElement.DEFAULT_ID);
}
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'initialisation du stock de l'article", e);
}
}
}
 
for (SQLRowAccessor sqlRowAccessor : referentStockRows) {
StockItem stockItem = mapItem.get(Tuple2.create(articleParent.getID(), sqlRowAccessor.getForeignID("ID_DEPOT_STOCK")));
if (stockItem != null) {
stockItem.addItemComponent(new StockItemComponent(new StockItem(article, sqlRowAccessor), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
} else if (sqlRowAccessor.getForeignID("ID_DEPOT_STOCK") == sqlRowAccessor.getTable().getForeignTable("ID_DEPOT_STOCK").getUndefinedID()) {
stockItem = mapItem.get(Tuple2.create(articleParent.getID(), DepotStockSQLElement.DEFAULT_ID));
stockItem.addItemComponent(new StockItemComponent(new StockItem(article, sqlRowAccessor), sqlRowValues.getBigDecimal("QTE_UNITAIRE"), sqlRowValues.getInt("QTE")));
} else {
System.err.println("Unable to find stock of item ARTICLE " + articleParent.getID() + " DEPOT " + sqlRowAccessor.getForeignID("ID_DEPOT_STOCK"));
}
}
}
}
}
 
/**
* @return l'ensemble des stockItems composés à mettre à jour
*/
168,6 → 229,7
for (SQLRowValues sqlRowValues : list) {
result.put(sqlRowValues.getID(), sqlRowValues);
}
// Liste des nomenclatures dépendantes des nomenclatures (kit dans kits)
while (size > 0) {
 
List<SQLRowValues> l = getComposedItemToUpdate(ids);
178,7 → 240,7
if (size > 0) {
ids.clear();
for (SQLRowValues r : l) {
ids.add(r.getID());
ids.add(r.getForeignID("ID_ARTICLE"));
}
}
}
186,7 → 248,7
List<StockItem> items = new ArrayList<StockItem>(result.size());
for (SQLRowValues rowVals : result.values()) {
 
StockItem item = new StockItem(rowVals);
StockItem item = new StockItem(rowVals.getForeign("ID_ARTICLE"), rowVals);
items.add(item);
}
return items;
203,29 → 265,30
final SQLRowValues rowValsArt = new SQLRowValues(tableArticle);
rowValsArt.put(tableArticle.getKey().getName(), null);
 
SQLRowValues rowValsStock = new SQLRowValues(tableArticle.getForeignTable("ID_STOCK"));
SQLRowValues rowValsStock = new SQLRowValues(this.root.getTable("STOCK"));
rowValsStock.put("QTE_REEL", null);
rowValsStock.put("QTE_TH", null);
rowValsStock.put("QTE_RECEPT_ATTENTE", null);
rowValsStock.put("QTE_LIV_ATTENTE", null);
rowValsArt.put("ID_STOCK", rowValsStock);
rowValsStock.put("ID_ARTICLE", rowValsArt);
rowValsStock.put("ID_DEPOT_STOCK", null);
 
final SQLTable tableArticleElt = this.root.getTable("ARTICLE_ELEMENT");
SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
rowValsArtItem.put("ID_ARTICLE_PARENT", rowValsArt);
// SQLRowValues rowValsArtItem = new SQLRowValues(tableArticleElt);
// rowValsArtItem.put("ID_ARTICLE_PARENT", rowValsArt);
// rowValsArtItem.put("QTE", null);
// rowValsArtItem.put("QTE_UNITAIRE", null);
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsArt);
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsStock);
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
 
@Override
public SQLSelect transformChecked(SQLSelect input) {
final SQLSelectJoin joinFromField = input.getJoinFromField(tableArticleElt.getField("ID_ARTICLE_PARENT"));
SQLSelectJoin joinFromField = input.addJoin("RIGHT", tableArticleElt, new Where(tableArticleElt.getField("ID_ARTICLE_PARENT"), "=", input.getTable("STOCK").getField("ID_ARTICLE")));
Where w = new Where(joinFromField.getJoinedTable().getField("ID_ARTICLE"), ids);
joinFromField.setWhere(w);
Where w2 = new Where(joinFromField.getJoinedTable().getKey(), "is not", (Object) null);
input.setWhere(w2);
input.clearOrder();
input.setDistinct(true);
return input;
}
});
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/stock/element/EtatStockFromInventoryFileCreator.java
New file
0,0 → 1,165
/*
* 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.supplychain.stock.element;
 
import org.openconcerto.erp.core.sales.product.model.PriceByQty;
import org.openconcerto.erp.importer.ArrayTableModel;
import org.openconcerto.erp.importer.DataImporter;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
 
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
public class EtatStockFromInventoryFileCreator {
 
// Map<String, SQLRowValues> kits = new HashMap<String, SQLRowValues>();
// List<String> codeKits = new ArrayList<String>();
// List<SQLRowValues> rowValsArtNonSync = new ArrayList<SQLRowValues>();
 
public void importArticles(File file, Date d) throws IOException, SQLException {
 
final SQLTable table = Configuration.getInstance().getRoot().findTable("ARTICLE");
Map<String, SQLRowValues> articles = getArticles();
 
final DataImporter importer = new DataImporter(table) {
@Override
protected void customizeRowValuesToFetch(SQLRowValues vals) {
 
vals.putRowValues("ID_STOCK").putNulls("ID", "QTE_REEL", "QTE_TH");
}
};
importer.setSkipFirstLine(true);
 
ArrayTableModel m = importer.createModelFrom(file);
 
SQLRowValues rowValsEtatStock = new SQLRowValues(table.getTable("ETAT_STOCK"));
rowValsEtatStock.put("DATE", d);
SQLRow etatStock = rowValsEtatStock.commit();
BigDecimal total = BigDecimal.ZERO;
for (int i = 0; i < m.getRowCount(); i++) {
List<Object> o = m.getLineValuesAt(i);
String code = o.get(0).toString();
if (code.trim().length() == 0) {
break;
}
final String stringQty = o.get(3).toString();
Integer qty = stringQty.trim().length() == 0 ? 0 : Integer.valueOf(stringQty);
 
SQLRowValues match = articles.get(code);
if (match != null) {
 
SQLRowValues stockValues = new SQLRowValues(table.getTable("ETAT_STOCK_ELEMENT"));
 
final BigDecimal qtyB = new BigDecimal(qty);
stockValues.put("QTE", qtyB);
stockValues.put("NOM", match.getString("NOM"));
stockValues.put("CODE", match.getString("CODE"));
stockValues.put("ID_ARTICLE", match.getID());
final BigDecimal prc = getPRC(match, qty, d);
stockValues.put("PA", prc);
final BigDecimal totalElt = prc.multiply(qtyB);
stockValues.put("T_PA", totalElt);
stockValues.put("ID_ETAT_STOCK", etatStock.getID());
stockValues.commit();
 
total = total.add(totalElt);
 
} else {
System.err.println("Aucun article correspondant au code " + code);
}
}
etatStock.createEmptyUpdateRow().put("MONTANT_HA", total).commit();
}
 
public BigDecimal getPRC(SQLRowValues rowVals, int qty, Date d) {
if (rowVals.getTable().getDBRoot().contains("ARTICLE_PRIX_REVIENT")) {
SQLTable table = rowVals.getTable().getDBRoot().getTable("ARTICLE_PRIX_REVIENT");
Collection<SQLRow> prcs = rowVals.asRow().getReferentRows(table);
 
BigDecimal result = null;
final List<PriceByQty> prices = new ArrayList<PriceByQty>();
 
for (SQLRow row : prcs) {
Calendar date = Calendar.getInstance();
date.set(Calendar.DAY_OF_MONTH, 1);
date.set(Calendar.MONTH, 1);
date.set(Calendar.YEAR, 2001);
if (row.getObject("DATE") != null) {
date = row.getDate("DATE");
}
prices.add(new PriceByQty(row.getLong("QTE"), row.getBigDecimal("PRIX"), date.getTime()));
}
 
result = PriceByQty.getPriceForQty(qty, prices, d);
if (result == null) {
// Can occur during editing
result = BigDecimal.ZERO;
}
return result;
} else {
return rowVals.getBigDecimal("PA_HT");
}
}
 
private Map<String, SQLRowValues> getArticles() throws SQLException {
final SQLTable table = Configuration.getInstance().getRoot().findTable("