Dépôt officiel du code source de l'ERP OpenConcerto
/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/jopenchart/DataModel1D.java |
---|
4,7 → 4,7 |
import java.util.List; |
public class DataModel1D extends DataModel { |
private final List<Number> l = new ArrayList<Number>(); |
private final List<Number> l = new ArrayList<>(); |
public DataModel1D() { |
12,8 → 12,7 |
public DataModel1D(Number[] data) { |
for (int i = 0; i < data.length; i++) { |
Number number = data[i]; |
l.add(number); |
l.add(data[i]); |
} |
} |
21,15 → 20,15 |
this.addAll(list); |
} |
public void addAll(List<Number> data) { |
public synchronized void addAll(List<Number> data) { |
l.addAll(data); |
} |
public int getSize() { |
public synchronized int getSize() { |
return l.size(); |
} |
public void setValueAt(int index, Number value) { |
public synchronized void setValueAt(int index, Number value) { |
ensureCapacity(index); |
l.set(index, value); |
} |
40,37 → 39,34 |
} |
} |
public Number getValueAt(int index) { |
public synchronized Number getValueAt(int index) { |
ensureCapacity(index); |
return l.get(index); |
} |
public Number getMaxValue() { |
public synchronized Number getMaxValue() { |
Number max = 0; |
for (Number b : this.l) { |
if (max == null) { |
if (b != null && b.doubleValue() > max.doubleValue()) { |
max = b; |
} else if (b != null && b.doubleValue() > max.doubleValue()) { |
max = b; |
} |
} |
return max; |
} |
public Number getMinValue() { |
public synchronized Number getMinValue() { |
Number min = 0; |
for (Number b : this.l) { |
if (min == null) { |
if (b != null && b.doubleValue() < min.doubleValue()) { |
min = b; |
} else if (b != null && b.doubleValue() < min.doubleValue()) { |
min = b; |
} |
} |
return min; |
} |
public void clear() { |
for (int i = 0; i < this.getSize(); i++) { |
public synchronized void clear() { |
final int size = l.size(); |
for (int i = 0; i < size; i++) { |
this.setValueAt(i, null); |
} |
} |
/trunk/OpenConcerto/src/org/jopenchart/DataModel2D.java |
---|
7,10 → 7,10 |
public class DataModel2D extends DataModel { |
private String[][] data; |
private int rowCount; |
private int colCount; |
private List<String> rowLabels = new ArrayList<String>(); |
private List<String> colLabels = new ArrayList<String>(); |
private final int rowCount; |
private final int colCount; |
private List<String> rowLabels = new ArrayList<>(); |
private List<String> colLabels = new ArrayList<>(); |
public DataModel2D(int row, int col) { |
this.rowCount = row; |
27,24 → 27,24 |
this.rowLabels.add(String.valueOf((char) ('A' + i))); |
} |
for (int i = 0; i < col; i++) { |
this.colLabels.add(String.valueOf(((1 + i)))); |
this.colLabels.add(String.valueOf(1 + i)); |
} |
} |
public String getValue(int row, int col) { |
public synchronized String getValue(int row, int col) { |
return data[row][col]; |
} |
public void setValue(String value, int row, int col) { |
public synchronized void setValue(String value, int row, int col) { |
data[row][col] = value; |
} |
public String getColumnLabel(int col) { |
public synchronized String getColumnLabel(int col) { |
return this.colLabels.get(col); |
} |
public String getRowLabel(int row) { |
public synchronized String getRowLabel(int row) { |
return this.rowLabels.get(row); |
} |
/trunk/OpenConcerto/src/org/openconcerto/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/light/LightControler.java |
---|
File deleted |
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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_en.properties |
---|
69,7 → 69,18 |
editFrame.look=Details of {element__singularIndefiniteArticle} |
listPanel.cloneToolTip=<html>Allow to duplicate a row.<br>Hold CTRL down to also duplicate the content<br>Hold Shift down to change the location.</html> |
listPanel.cloneRows=Do you want to clone {rowCount, plural, one {this row{rec, select, true { and its content} other {}}} other {these # rows{rec, select, true { and their contents} other {}}}} ? |
listPanel.cloneRows=Do you want to clone {rec, select,\ |
true {\ |
{rowCount, plural,\ |
one {this row and its content ?}\ |
other {these # rows and their content ?}\ |
}}\ |
other {\ |
{rowCount, plural,\ |
one {this row ?}\ |
other {these # rows ?}\ |
}}\ |
} |
listPanel.noSelectionOrSort=No selection or list sorted |
listPanel.export=List export |
listPanel.save=Save the list |
87,8 → 98,10 |
ilist.unlockRows=Unlock rows |
ilist.metadata={0,choice,0#Modified|1#Created}{1,choice,0#|1# by {2} {3}}{4,choice,0#|1#, {5,date,long} at {5,time,medium}} |
sqlComp.stringValueTooLong=The value is {0} character{0,choice,1#|1<s} too long |
sqlComp.bdTooHigh=Number too high, it must have at most {0} digit{0,choice,1#|1<s} before the decimal point ({1} after) |
sqlComp.stringValueTooLong=The value is {0, plural, one {# character too long} other {# characters too long}} |
sqlComp.bdTooHigh=Number too high, {0, plural,\ |
one {it must have at most # digit before the decimal point ({1} after)}\ |
other {it must have at most # digits before the decimal point ({1} after)}} |
sqlComp.invalidItem={0} is invalid{1,choice,0#|1# ({2})} |
sqlComp.emptyItem={0} is empty |
sqlComp.insertError=Error while inserting |
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_es.properties |
---|
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/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/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/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/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/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/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/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/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/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/users/CompanyAccessSQLElement.java |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightSQLElement.java |
---|
14,14 → 14,13 |
package org.openconcerto.sql.users.rights; |
import static java.util.Arrays.asList; |
import org.openconcerto.sql.TM; |
import org.openconcerto.sql.element.ConfSQLElement; |
import org.openconcerto.sql.element.GlobalMapper; |
import org.openconcerto.sql.element.SQLComponent; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.DBRoot; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.utils.SQLCreateTable; |
import org.openconcerto.utils.i18n.I18nUtils; |
import java.util.ArrayList; |
import java.util.Collections; |
28,7 → 27,7 |
import java.util.List; |
import java.util.Set; |
public class UserRightSQLElement extends ConfSQLElement { |
public class UserRightSQLElement extends SQLElement { |
public static final String TABLE_NAME = "USER_RIGHT"; |
static public List<SQLCreateTable> getCreateTables(final SQLTable userT) { |
56,9 → 55,8 |
return res; |
} |
public UserRightSQLElement() { |
super(TABLE_NAME); |
this.setL18nPackageName(I18nUtils.getPackageName(TM.class)); |
public UserRightSQLElement(final DBRoot r) { |
super(r.findTable(TABLE_NAME), null, "sql.user-right"); |
final UserRightGroup group = new UserRightGroup(); |
GlobalMapper.getInstance().map(UserRightSQLComponent.ID, group); |
setDefaultGroup(group); |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/RightSQLElement.java |
---|
13,20 → 13,18 |
package org.openconcerto.sql.users.rights; |
import org.openconcerto.sql.TM; |
import org.openconcerto.sql.element.ConfSQLElement; |
import org.openconcerto.sql.element.SQLComponent; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.element.UISQLComponent; |
import org.openconcerto.sql.model.DBRoot; |
import org.openconcerto.sql.utils.SQLCreateTable; |
import org.openconcerto.ui.component.ITextArea; |
import org.openconcerto.utils.ListMap; |
import org.openconcerto.utils.i18n.I18nUtils; |
import java.util.Arrays; |
import java.util.List; |
public class RightSQLElement extends ConfSQLElement { |
public class RightSQLElement extends SQLElement { |
public static final String TABLE_NAME = "RIGHT"; |
38,9 → 36,8 |
return res; |
} |
public RightSQLElement() { |
super(TABLE_NAME); |
this.setL18nPackageName(I18nUtils.getPackageName(TM.class)); |
public RightSQLElement(final DBRoot root) { |
super(root.findTable(TABLE_NAME), null, "sql.right"); |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/rights/UserRightsManager.java |
---|
289,7 → 289,7 |
}; |
this.javaRights = new JavaRights(); |
this.table = t; |
this.toUserLink = t.getFieldGroups().get("ID_USER_COMMON").getKey().getForeignLink(); |
this.toUserLink = t.getField("ID_USER_COMMON").getFieldGroup().getForeignLink(); |
defaultRegister(); |
this.userRights = new HashMap<Integer, UserRights>(); |
this.exec = Executors.newSingleThreadExecutor(new ThreadFactory(this.getClass().getSimpleName() + " executor for " + t.getSQLName(), true).setPriority(Thread.MIN_PRIORITY)); |
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java |
---|
16,7 → 16,6 |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.TM; |
import org.openconcerto.sql.element.BaseSQLComponent; |
import org.openconcerto.sql.element.ConfSQLElement; |
import org.openconcerto.sql.element.SQLComponent; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.DBRoot; |
47,7 → 46,6 |
import org.openconcerto.utils.ListMap; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.checks.ValidState; |
import org.openconcerto.utils.i18n.I18nUtils; |
import org.openconcerto.utils.text.SimpleDocumentListener; |
import java.awt.Component; |
75,7 → 73,7 |
import javax.swing.table.DefaultTableCellRenderer; |
// FIXME Login user unique ? |
public class UserCommonSQLElement extends ConfSQLElement { |
public class UserCommonSQLElement extends SQLElement { |
/** |
* Set this system property to "true" if this should generate old style passwords. |
82,19 → 80,15 |
*/ |
public static final String LEGACY_PASSWORDS = "org.openconcerto.sql.legacyPasswords"; |
{ |
this.setL18nPackageName(I18nUtils.getPackageName(TM.class)); |
} |
private final boolean familyNameFirst; |
public UserCommonSQLElement() { |
super("USER_COMMON"); |
this.familyNameFirst = false; |
public UserCommonSQLElement(final DBRoot root) { |
this(root, false); |
} |
public UserCommonSQLElement(final DBRoot root, final boolean familyNameFirst) { |
super(root.findTable("USER_COMMON")); |
// allow subclass to keep same code |
super(root.findTable("USER_COMMON"), null, "sql.user"); |
this.familyNameFirst = familyNameFirst; |
} |
/trunk/OpenConcerto/src/org/openconcerto/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/IListe.java |
---|
370,7 → 370,7 |
public String getLine(final boolean created, final SQLRowValues row, final SQLField userF, final SQLField dateF) { |
final Calendar date = dateF == null ? null : row.getDate(dateF.getName()); |
final SQLRowAccessor user = userF == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName()); |
final SQLRowAccessor user = userF == null || row.getObject(userF.getName()) == null || row.isForeignEmpty(userF.getName()) ? null : row.getForeign(userF.getName()); |
if (user == null && date == null) |
return null; |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ListSQLLine.java |
---|
275,8 → 275,8 |
} |
if (toRemove != null) |
toRemove.remove(lastField.getName()); |
// attach updated values |
if (vals != null && vals.getLong(lastField.getName()) == target.getIDNumber().longValue()) |
// attach updated values, foreign ID is always present but can be null |
if (vals != null && target.getIDNumber().equals(vals.getForeignIDNumberValue(lastField.getName()).getValue())) |
vals.deepCopy().put(lastField.getName(), target); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/MoveQueue.java |
---|
18,17 → 18,19 |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLSelect.LockStrength; |
import org.openconcerto.sql.model.SQLSyntax; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.UpdateBuilder; |
import org.openconcerto.sql.utils.ReOrder; |
import org.openconcerto.sql.utils.SQLUtils; |
import org.openconcerto.utils.DecimalUtils; |
import org.openconcerto.utils.ExceptionUtils; |
import org.openconcerto.utils.NumberUtils; |
import org.openconcerto.utils.SleepingQueue; |
import java.math.BigDecimal; |
import java.math.RoundingMode; |
import java.sql.SQLException; |
import java.util.ArrayList; |
import java.util.Arrays; |
131,20 → 133,13 |
// if only some rows are moved, update one by one (avoids refreshing the whole list) |
// (getRowCount() is not thread-safe, so use getTotalRowCount()) |
if (rowCount < 5 && rowCount < (this.tableModel.getTotalRowCount() / 3)) { |
final List<?> l; |
if (after) { |
// If we want to put X,Y after A in the list A,B,C |
// we need to pass first Y : A,Y,B,C then X : |
// A,X,Y,B,C |
l = new ArrayList<Object>(srcRows); |
Collections.reverse(l); |
} else { |
l = srcRows; |
} |
final SQLTable t = getTable(); |
final String orderName = t.getOrderField().getName(); |
final SQLRowValues vals = new SQLRowValues(t); |
for (final Object src : l) { |
vals.setOrder(destRow, after).update(getID(src, t).intValue()); |
final List<BigDecimal> orders = ReOrder.getFreeOrderValuesFor(rowCount, after, destRow).get0(); |
for (int i = 0; i < rowCount; i++) { |
final Object src = srcRows.get(i); |
vals.put(orderName, orders.get(i)).update(getID(src, t).intValue()); |
} |
} else { |
// update all rows at once and refresh the whole list |
184,75 → 179,64 |
moveAtOnce(srcRows, srcRows.size(), after, destRow); |
} |
/** |
* Move the passed rows just before or just after the destination row if needed. |
* |
* @param ids rows to order. |
* @param after <code>true</code> if the rows should be placed after <code>destRow</code>, |
* <code>false</code> otherwise. |
* @param destRow <code>srcRows</code> will be placed relative to the order of this row. |
* @param checkBefore if <code>true</code> the current DB order will be checked and if it |
* matched the passed rows, no change will be made to the DB, <code>false</code> to |
* always change the orders in the DB. |
* @return if the DB was changed. |
* @throws SQLException if an error occurs. |
*/ |
static public boolean moveIDsAtOnce(final List<? extends Number> ids, final boolean after, final SQLRow destRow, final boolean checkBefore) throws SQLException { |
final int size = ids.size(); |
if (checkBefore) { |
final SQLTable table = destRow.getTable(); |
final SQLSelect sel = new SQLSelect(true); |
sel.addSelect(table.getKey()); |
sel.addOrder(table); |
sel.setWhere(new Where(table.getKey(), ids)); |
// needed since we might update them just after in moveAtOnce(), and it's safer to lock |
// with the most restrictive mode first. |
sel.setLockStrength(LockStrength.UPDATE); |
final List<?> dbOrderedIDs = table.getDBSystemRoot().getDataSource().executeCol(sel.asString()); |
if (dbOrderedIDs.size() != size) |
throw new IllegalStateException("Missing rows"); |
boolean orderOK = true; |
for (int i = 0; i < size && orderOK; i++) { |
final Number passedID = ids.get(i); |
final Number dbID = (Number) dbOrderedIDs.get(i); |
orderOK = NumberUtils.areNumericallyEqual(passedID, dbID); |
} |
if (orderOK) |
return false; |
} |
moveAtOnce(ids, size, after, destRow); |
return true; |
} |
static private void moveAtOnce(final List<?> srcRows, final int rowCount, final boolean after, final SQLRow destRow) throws SQLException { |
if (rowCount == 0) |
return; |
final SQLTable t = destRow.getTable(); |
// ULP * 10 to give a little breathing room |
final BigDecimal minDistance = t.getOrderULP().scaleByPowerOfTen(1); |
assert minDistance.signum() > 0; |
final BigDecimal places = BigDecimal.valueOf(rowCount + 1); |
// the minimum room so that we can move all rows |
final BigDecimal room = minDistance.multiply(places); |
final List<BigDecimal> freeOrderValues = ReOrder.getFreeOrderValuesFor(rowCount, after, destRow).get0(); |
final BigDecimal destOrder = destRow.getOrder(); |
final SQLRow nextRow = destRow.getRow(true); |
final BigDecimal inc; |
final boolean destRowReordered; |
if (nextRow == null) { |
// if destRow is the last row, we can choose whatever increment we want |
inc = ReOrder.DISTANCE; |
// but we need to move destRow if we want to add before it |
destRowReordered = false; |
} else { |
final BigDecimal nextOrder = nextRow.getOrder(); |
assert nextOrder.compareTo(destOrder) > 0; |
final BigDecimal diff = nextOrder.subtract(destOrder); |
assert diff.signum() > 0; |
if (diff.compareTo(room) < 0) { |
// if there's not enough room, reorder to squeeze rows upwards |
// since we keep increasing count, we will eventually reorder all rows afterwards |
int count = 100; |
final int tableRowCount = t.getRowCount(); |
boolean reordered = false; |
while (!reordered) { |
// only push destRow upwards if we want to add before |
reordered = ReOrder.create(t, destOrder, !after, count, destOrder.add(room)).exec(); |
if (!reordered && count > tableRowCount) |
throw new IllegalStateException("Unable to reorder " + count + " rows in " + t); |
count *= 10; |
} |
inc = minDistance; |
destRowReordered = true; |
} else { |
// truncate |
inc = DecimalUtils.round(diff.divide(places, DecimalUtils.HIGH_PRECISION), t.getOrderDecimalDigits(), RoundingMode.DOWN); |
destRowReordered = false; |
} |
} |
// i.e. inc > 0 |
assert inc.compareTo(minDistance) >= 0; |
BigDecimal newOrder = destOrder; |
// by definition if we want to add after, destOrder should remain unchanged |
if (after) { |
newOrder = newOrder.add(inc); |
} |
final List<List<String>> newOrdersAndIDs = new ArrayList<List<String>>(rowCount); |
int i = 0; |
final List<Number> ids = rowCount < 10 ? new ArrayList<Number>(rowCount) : null; |
// we go from newOrder and up, so that the passed rows are in ascending order |
for (final Object src : srcRows) { |
final Number srcID = getID(src, t); |
if (ids != null) |
ids.add(srcID); |
final BigDecimal newOrder = freeOrderValues.get(i++); |
newOrdersAndIDs.add(Arrays.asList(srcID.toString(), newOrder.toPlainString())); |
newOrder = newOrder.add(inc); |
} |
// move out before general request as most DB systems haven't got DEFERRABLE constraints |
if (!after && !destRowReordered) { |
final UpdateBuilder updateDestRow = new UpdateBuilder(t); |
updateDestRow.setObject(t.getOrderField(), newOrder); |
updateDestRow.setWhere(destRow.getWhere()); |
t.getDBSystemRoot().getDataSource().execute(updateDestRow.asString()); |
} |
final SQLSyntax syntax = SQLSyntax.get(t); |
final UpdateBuilder update = new UpdateBuilder(t); |
261,6 → 245,12 |
update.setFromVirtualJoinField(t.getOrderField().getName(), constantTableAlias, "newOrder"); |
t.getDBSystemRoot().getDataSource().execute(update.asString()); |
t.fireTableModified(SQLRow.NONEXISTANT_ID, Collections.singletonList(t.getOrderField().getName())); |
final List<String> fieldsChanged = Collections.singletonList(t.getOrderField().getName()); |
if (ids == null) { |
t.fireTableModified(SQLRow.NONEXISTANT_ID, fieldsChanged); |
} else { |
for (final Number id : ids) |
t.fireTableModified(id.intValue(), fieldsChanged); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/view/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/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/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/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/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/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/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/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/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/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/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_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/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/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/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/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><media type>/<sub type></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>*/*</code> and <code>text/*</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><media type>/<sub type>. |
* @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/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/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/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/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/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/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/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/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/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/erp/panel/ITreeSelection.java |
---|
42,8 → 42,10 |
import java.beans.PropertyChangeSupport; |
import java.sql.SQLException; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
import java.util.concurrent.ExecutionException; |
import javax.swing.AbstractAction; |
319,7 → 321,7 |
} |
for (int i = 0; i < l.size(); i++) { |
SQLRow row = l.get(i); |
addNewNode(familles, row, row.getInt("ID_" + element.getTable().getName() + "_PERE")); |
addNewNode(familles, row, row.getInt("ID_" + element.getTable().getName() + "_PERE"), new HashSet<>()); |
} |
expandRow(0); |
} |
338,14 → 340,17 |
* @param id |
* @param idPere |
*/ |
private void addNewNode(Map<Integer, SQLRow> familles, SQLRow row, int idPere) { |
private void addNewNode(Map<Integer, SQLRow> familles, SQLRow row, int idPere, Set<Integer> addedIDs) { |
if (row != null && this.mapNode.get(row.getID()) == null) { |
ITreeSelectionNode nodePere = this.mapNode.get(Integer.valueOf(idPere)); |
if (idPere > 1 && nodePere == null && familles != null) { |
final SQLRow rowPere = familles.get(idPere); |
if (rowPere.getID() != row.getID()) { |
addNewNode(familles, rowPere, rowPere.getInt("ID_" + element.getTable().getName() + "_PERE")); |
if (idPere != row.getID()) { |
if (!addedIDs.contains(idPere)) { |
addedIDs.add(idPere); |
addNewNode(familles, rowPere, rowPere.getInt("ID_" + element.getTable().getName() + "_PERE"), addedIDs); |
} |
} |
nodePere = this.mapNode.get(Integer.valueOf(idPere)); |
} |
final ITreeSelectionNode newNode = new ITreeSelectionNode(row); |
425,7 → 430,7 |
public void rowAdded(SQLTable table, int id) { |
final SQLRow row = table.getRow(id); |
int idPere = row.getInt("ID_" + element.getTable().getName() + "_PERE"); |
addNewNode(null, row, idPere); |
addNewNode(null, row, idPere, new HashSet<>()); |
} |
public void rowDeleted(SQLTable table, int id) { |
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/UserExitPanel.java |
---|
219,6 → 219,7 |
p.waitFor(); |
} |
ComptaPropsConfiguration.getInstanceCompta().tearDownLogging(true); |
} catch (IOException e1) { |
// TODO Auto-generated catch block |
e1.printStackTrace(); |
266,6 → 267,7 |
} |
try { |
Configuration.getInstance().destroy(); |
ComptaPropsConfiguration.getInstanceCompta().tearDownLogging(true); |
} catch (Throwable e) { |
e.printStackTrace(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/ChargementCreationSocietePanel.java |
---|
13,7 → 13,7 |
package org.openconcerto.erp.panel; |
import org.openconcerto.erp.core.common.component.SocieteCommonSQLElement; |
import org.openconcerto.erp.core.common.element.SocieteCommonSQLElement; |
import org.openconcerto.erp.utils.ActionDB; |
import org.openconcerto.erp.utils.StatusListener; |
import org.openconcerto.sql.Configuration; |
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/PanelOOSQLComponent.java |
---|
18,6 → 18,7 |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.preferences.GenerationDocGlobalPreferencePanel; |
import org.openconcerto.erp.utils.TM; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.BaseSQLComponent; |
import org.openconcerto.sql.element.SQLElement; |
38,9 → 39,9 |
public class PanelOOSQLComponent extends JPanel { |
private final JCheckBox checkImpression = new JCheckBox("Imprimer"); |
private final JCheckBox checkVisu = new JCheckBox("Visualiser"); |
private final JCheckBox checkAbo = new JCheckBox("Créer l'abonnement associé"); |
private final JCheckBox checkImpression = new JCheckBox(TM.tr("PanelOOSQLComponent.print")); //$NON-NLS-1$ |
private final JCheckBox checkVisu = new JCheckBox(TM.tr("PanelOOSQLComponent.view")); //$NON-NLS-1$ |
private final JCheckBox checkAbo = new JCheckBox(TM.tr("PanelOOSQLComponent.createSubscription")); //$NON-NLS-1$ |
public PanelOOSQLComponent(final BaseSQLComponent comp) { |
super(new GridBagLayout()); |
49,7 → 50,7 |
this.setOpaque(false); |
final SQLTable tableComp = comp.getElement().getTable(); |
if (tableComp.getName().equals("SAISIE_VENTE_FACTURE") && tableComp.getDBRoot().contains("ABONNEMENT")) { |
if (tableComp.getName().equals("SAISIE_VENTE_FACTURE") && tableComp.getDBRoot().contains("ABONNEMENT")) { //$NON-NLS-1$ //$NON-NLS-2$ |
this.checkAbo.setOpaque(false); |
this.add(this.checkAbo, c); |
} |
57,22 → 58,22 |
SQLPreferences prefs = SQLPreferences.getMemCached(((ComptaPropsConfiguration) Configuration.getInstance()).getRootSociete()); |
if (prefs.getBoolean(GenerationDocGlobalPreferencePanel.MULTIMOD, false)) { |
if (tableComp.getFieldsName().contains("ID_MODELE")) { |
String labelFor = comp.getLabelFor("ID_MODELE"); |
if (tableComp.getFieldsName().contains("ID_MODELE")) { //$NON-NLS-1$ |
String labelFor = comp.getLabelFor("ID_MODELE"); //$NON-NLS-1$ |
if (labelFor == null || labelFor.trim().length() == 0) { |
labelFor = "Modéles"; |
labelFor = "Modéles"; //$NON-NLS-1$ |
} |
JLabel labelModele = new JLabel(labelFor); |
ElementComboBox boxModele = new ElementComboBox(true, 25); |
SQLElement modeleElement = Configuration.getInstance().getDirectory().getElement("MODELE"); |
SQLElement modeleElement = Configuration.getInstance().getDirectory().getElement("MODELE"); //$NON-NLS-1$ |
boxModele.init(modeleElement, modeleElement.getComboRequest(true)); |
comp.addView(boxModele, "ID_MODELE"); |
comp.addView(boxModele, "ID_MODELE"); //$NON-NLS-1$ |
boxModele.getRequest().setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() { |
@Override |
public SQLSelect transformChecked(SQLSelect input) { |
SQLTable table = Configuration.getInstance().getDirectory().getElement("TYPE_MODELE").getTable(); |
Where w = new Where(input.getAlias(table.getField("TABLE")), "=", tableComp.getName()); |
SQLTable table = Configuration.getInstance().getDirectory().getElement("TYPE_MODELE").getTable(); //$NON-NLS-1$ |
Where w = new Where(input.getAlias(table.getField("TABLE")), "=", tableComp.getName()); //$NON-NLS-1$ //$NON-NLS-2$ |
input.setWhere(w); |
return input; |
} |
81,7 → 82,7 |
DefaultGridBagConstraints.lockMinimumSize(boxModele); |
this.add(boxModele, c); |
} else { |
System.err.println("Impossible d'ajouter la combo pour le choix des modèles car le champ ID_MODELE n'est pas présent dans la table " + tableComp.getName()); |
System.err.println(TM.tr("PanelOOSQLComponent.missingField", tableComp.getName())); //$NON-NLS-1$ |
Thread.dumpStack(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ExportFEC.java |
---|
84,7 → 84,9 |
sel.addFieldOrder(tableEcriture.getField("DATE")); |
sel.addFieldOrder(tableMouvement.getField("NUMERO")); |
sel.setWhere(sel.getWhere().and(new Where(tableEcriture.getField("DEBIT"), "!=", tableEcriture.getField("CREDIT")))); |
final Where w = new Where(tableEcriture.getField("DEBIT"), "!=", tableEcriture.getField("CREDIT")); |
final Where w2 = new Where(tableEcriture.getField("CLOTURE"), "!=", Boolean.TRUE); |
sel.setWhere(sel.getWhere().and(w).and(w2)); |
@SuppressWarnings("unchecked") |
final List<Object[]> l = (List<Object[]>) this.getRootSociete().getDBSystemRoot().getDataSource().execute(sel.asString(), new ArrayListHandler()); |
105,8 → 107,8 |
if (s == null) { |
throw new NullPointerException("Valeur manquante pour remplir la ligne : " + line); |
} |
// TODO remove \r |
line.add(s.trim().replace(ZONE_SEPARATOR, REPLACEMENT).replace(RECORD_SEPARATOR, REPLACEMENT)); |
final String escapedString = StringUtils.toAsciiString(s).trim(); |
line.add(escapedString.replace(ZONE_SEPARATOR, REPLACEMENT).replace(RECORD_SEPARATOR, REPLACEMENT)); |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/erp/model/MouseSheetXmlListeListener.java |
---|
26,6 → 26,7 |
import org.openconcerto.sql.view.list.RowAction; |
import org.openconcerto.ui.EmailComposer; |
import org.openconcerto.utils.ExceptionHandler; |
import org.openconcerto.utils.ListMap; |
import java.awt.event.ActionEvent; |
import java.io.File; |
33,6 → 34,7 |
import java.util.ArrayList; |
import java.util.List; |
import java.util.Set; |
import java.util.StringJoiner; |
import javax.swing.AbstractAction; |
import javax.swing.Action; |
111,15 → 113,18 |
} |
protected void sendMail(final AbstractSheetXml sheet, final boolean readOnly) { |
List<AbstractSheetXml> l = new ArrayList<AbstractSheetXml>(1); |
List<AbstractSheetXml> l = new ArrayList<>(1); |
l.add(sheet); |
sendMail(l, readOnly); |
} |
protected void sendMail(final List<AbstractSheetXml> sheets, final boolean readOnly) { |
final Thread t = new Thread() { |
@Override |
public void run() { |
ListMap<String, File> mailFilesMap = new ListMap<>(); |
for (AbstractSheetXml sheet : sheets) { |
String mail = ""; |
for (AbstractSheetXml sheet : sheets) { |
final SQLRow row = sheet.getSQLRow(); |
Set<SQLField> setContact = null; |
SQLTable tableContact = Configuration.getInstance().getRoot().findTable("CONTACT"); |
134,7 → 139,7 |
mail = row.getForeignRow(field.getName()).getString("EMAIL"); |
} |
} |
String nomClient = ""; |
if (setClient != null && (mail == null || mail.trim().length() == 0)) { |
for (SQLField field : setClient) { |
SQLRow rowCli = row.getForeignRow(field.getName()); |
141,9 → 146,18 |
if (mail == null || mail.trim().length() == 0) { |
mail = rowCli.getString("MAIL"); |
} |
nomClient = rowCli.getString("NOM"); |
} |
} |
if (mail.trim().length() == 0) { |
mail = nomClient; |
} |
String table = row.getTable().getName(); |
if (table.equalsIgnoreCase("COMMANDE") || table.equalsIgnoreCase("DEMANDE_PRIX") || table.equalsIgnoreCase("FACTURE_FOURNISSEUR")) { |
mail = ""; |
} |
if (mail == null || mail.trim().length() == 0) { |
SQLTable tableF = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete().getTable("FOURNISSEUR"); |
Set<SQLField> setF = null; |
195,20 → 209,21 |
} |
} |
} |
try { |
if (readOnly) { |
mailFilesMap.add(mail, sheet.getOrCreatePDFDocumentFile(true).getAbsoluteFile()); |
} else { |
mailFilesMap.add(mail, sheet.getOrCreateDocumentFile().getAbsoluteFile()); |
} |
final String adresseMail = mail; |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de charger le document PDF", e); |
} |
} |
final String subject = sheets.get(0).getReference(); |
for (final String mailDest : mailFilesMap.keySet()) { |
if (readOnly) { |
final Thread t = new Thread() { |
@Override |
public void run() { |
final List<File> files = new ArrayList<File>(); |
try { |
for (AbstractSheetXml sheet : sheets) { |
files.add(sheet.getOrCreatePDFDocumentFile(true).getAbsoluteFile()); |
} |
final List<File> files = mailFilesMap.get(mailDest); |
SwingUtilities.invokeLater(new Runnable() { |
215,31 → 230,27 |
@Override |
public void run() { |
try { |
EmailComposer.getInstance().compose(adresseMail, subject + (subject.trim().length() == 0 ? "" : ", ") + files.get(0).getName(), |
getMailObject(sheets.get(0).getSQLRow()), files.toArray(new File[files.size()])); |
String subject = sheets.get(0).getReference(); |
if (subject.isEmpty()) { |
final StringJoiner joiner = new StringJoiner(", "); |
for (File f : files) { |
joiner.add(f.getName()); |
} |
subject = joiner.toString(); |
} |
final String message = getMailObject(sheets.get(0).getSQLRow()); |
EmailComposer.getInstance().compose(mailDest, subject, message, files.toArray(new File[files.size()])); |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de charger le document PDF dans l'email!", e); |
ExceptionHandler.handle("Impossible d'envoyer le courriel!", e); |
} |
} |
}); |
} catch (Exception e) { |
ExceptionHandler.handle("Impossible de charger le document PDF", e); |
} |
} |
}; |
t.start(); |
} else { |
try { |
final List<File> files = new ArrayList<File>(); |
for (AbstractSheetXml sheet : sheets) { |
files.add(sheet.getGeneratedFile().getAbsoluteFile()); |
} |
EmailComposer.getInstance().compose(adresseMail, subject + (subject.trim().length() == 0 ? "" : ", ") + sheets.get(0).getGeneratedFile().getName(), |
getMailObject(sheets.get(0).getSQLRow()), files.toArray(new File[files.size()])); |
} catch (Exception exn) { |
ExceptionHandler.handle(null, "Impossible de créer le courriel", exn); |
} |
} |
} |
365,7 → 376,7 |
@Override |
public boolean enabledFor(List<SQLRowValues> selection) { |
return selection != null && selection.size() > 0; |
return selection != null && !selection.isEmpty(); |
} |
}); |
/trunk/OpenConcerto/src/org/openconcerto/erp/model/FichePayeModel.java |
---|
72,7 → 72,7 |
private SQLJavaEditor javaEdit = new SQLJavaEditor(VariablePayeSQLElement.getMapTree()); |
// liste des variable de paye à calculer |
private BigDecimal salBrut, salBrutBase, salBrutCotis, salBrutTaxable, cotPat, cotSal, taxCmPat, taxCmSal, netImp, netAPayer, csg, csgSansAbattement, cice, allegmentCotisation, avantage, |
private BigDecimal salBrut, salBrutBase, salBrutCotis, salBrutTaxable, cotPat, cotSal, taxCmPat, taxCmSal, netImp, pas, netAPayer, csg, csgSansAbattement, cice, allegmentCotisation, avantage, |
reduction; |
private Map<Integer, String> mapField; |
154,14 → 154,22 |
return csgSansAbattement; |
} |
public BigDecimal getPas() { |
return pas; |
} |
public BigDecimal getNetAPayerTotal() { |
return netAPayer.add(this.salBrut); |
} |
public BigDecimal getNetImpTotal() { |
return netImp.add(this.salBrut); |
return netImp.add(this.salBrutTaxable); |
} |
public BigDecimal getNetAvantPas() { |
return getNetAPayerTotal().subtract(this.pas); |
} |
public BigDecimal getSalBrut() { |
return salBrut; |
} |
206,6 → 214,7 |
this.taxCmPat = BigDecimal.ZERO; |
this.taxCmSal = BigDecimal.ZERO; |
this.netAPayer = BigDecimal.ZERO; |
this.pas = BigDecimal.ZERO; |
this.netImp = BigDecimal.ZERO; |
this.csg = BigDecimal.ZERO; |
this.csgSansAbattement = BigDecimal.ZERO; |
757,6 → 766,7 |
rowValsFiche.put("SAL_BRUT_TAXABLE", this.salBrutTaxable); |
rowValsFiche.put("NET_IMP", getNetImpTotal()); |
rowValsFiche.put("NET_A_PAYER", getNetAPayerTotal()); |
rowValsFiche.put("NET_AVANT_PAS", getNetAvantPas()); |
rowValsFiche.put("COT_SAL", this.cotSal); |
rowValsFiche.put("COT_PAT", this.cotPat); |
rowValsFiche.put("TAXE_CM_PAT", this.taxCmPat); |
763,6 → 773,8 |
rowValsFiche.put("TAXE_CM_SAL", this.taxCmSal); |
rowValsFiche.put("CSG", getCsgTotal()); |
rowValsFiche.put("HEURE_TRAV", getHeureTrav()); |
rowValsFiche.put("TOTAL_PAS", getPas()); |
if (this.cice == null) { |
if (salBrut.signum() > 0 |
&& salBrut.compareTo(new BigDecimal(getSmicHoraire(tableFichePaye.getDBRoot())).multiply(getHeureTrav()).multiply(new BigDecimal(2.5), DecimalUtils.HIGH_PRECISION)) <= 0) { |
954,6 → 966,9 |
if (rowSource.getBoolean("IMPOSABLE")) { |
this.netImp = this.netImp.subtract(montant); |
} |
if (rowSource.getBoolean("PAS")) { |
this.pas = this.pas.subtract(montant); |
} |
} // Gain |
else { |
964,7 → 979,10 |
if (rowSource.getBoolean("IMPOSABLE")) { |
this.netImp = this.netImp.add(montant); |
} |
if (rowSource.getBoolean("PAS")) { |
this.pas = this.pas.add(montant); |
} |
} |
// Mis a jour du salaire net |
// updateValueFiche(); |
975,7 → 993,10 |
if (rowSource.getBoolean("IMPOSABLE")) { |
this.netImp = this.netImp.subtract(ded); |
} |
if (rowSource.getBoolean("PAS")) { |
this.pas = this.pas.subtract(ded); |
} |
} |
BigDecimal add = rowVals.getBigDecimal("MONTANT_SAL_AJ"); |
if (add != null) { |
this.netAPayer = this.netAPayer.add(add); |
982,10 → 1003,13 |
if (rowSource.getBoolean("IMPOSABLE")) { |
this.netImp = this.netImp.add(add); |
} |
if (rowSource.getBoolean("IMPOSABLE")) { |
this.pas = this.pas.add(add); |
} |
} |
} |
} |
} |
private void loadElementNet(SQLRow rowSource, SQLRow row) { |
SQLRowValues rowVals = new SQLRowValues(tableFichePayeElt); |
1057,7 → 1081,12 |
// CICE |
int codeTP = rowSource.getForeignID("ID_CODE_CAISSE_TYPE_RUBRIQUE"); |
if (codeTP == 298) { |
String codeStringTP = ""; |
if (rowSource.getForeign("ID_CODE_CAISSE_TYPE_RUBRIQUE") != null && !rowSource.isForeignEmpty("ID_CODE_CAISSE_TYPE_RUBRIQUE")) { |
codeStringTP = rowSource.getForeign("ID_CODE_CAISSE_TYPE_RUBRIQUE").getString("CODE"); |
} |
if (codeTP == 298 || codeStringTP.equals("400")) { |
this.cice = rowVals.getBigDecimal("NB_BASE"); |
} |
1064,6 → 1093,7 |
// Mis a jour des cotisations |
// updateValueFiche(); |
} |
} |
private void loadElementCotisation(final SQLRow rowSource, SQLRow row) { |
1127,6 → 1157,7 |
return; |
} |
try { |
Object baseOb = this.javaEdit.checkFormule(rowSource.getString("NB_BASE"), "BASE"); |
Object tauxSalOb = this.javaEdit.checkFormule(rowSource.getString("TAUX_SAL"), "SAL"); |
Object tauxPatOb = this.javaEdit.checkFormule(rowSource.getString("TAUX_PAT"), "PAT"); |
1144,7 → 1175,6 |
rowVals.put("MONTANT_SAL_DED", montantDed); |
boolean b = isEltImprimable(rowSource, rowVals); |
// System.err.println("Impression --- > " + b); |
rowVals.put("IMPRESSION", Boolean.valueOf(b)); |
if (rowSource.getBoolean("REDUCTION_GVT_COM")) { |
1157,7 → 1187,10 |
} |
this.vectRubrique.add(rowVals); |
} catch (NumberFormatException e) { |
JOptionPane.showMessageDialog(null, "Une des formules de la rubrique de commentaire " + rowSource.getString("CODE") + " -- " + rowSource.getString("NOM") + " n'est pas correcte!"); |
} |
} |
private void calculValue() { |
1165,9 → 1198,6 |
resetValueFiche(); |
/* |
* this.threadUpdate = new Thread("Update Fiche Paye") { public void run() { |
*/ |
Vector<SQLRowValues> vectTmp = new Vector<SQLRowValues>(this.vectRubrique); |
this.vectRubrique = new Vector<SQLRowValues>(); |
1180,8 → 1210,6 |
if (source.trim().length() != 0) { |
// System.err.println("Source != null"); |
if (this.mapTableSource.get(source) != null) { |
SQLRow rowSource = this.mapTableSource.get(source).getRow(idSource); |
1205,9 → 1233,6 |
System.err.println(this.vectRubrique.size() + " elements ADDed "); |
updateValueFiche(); |
fireTableDataChanged(); |
/* |
* } }; this.threadUpdate.start(); |
*/ |
System.err.println("End calculValue At " + new Date()); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/rights/UserRightGroupComptaSQLElement.java |
---|
13,9 → 13,9 |
package org.openconcerto.erp.rights; |
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.users.rights.UserRightSQLComponent; |
import org.openconcerto.sql.users.rights.UserRightSQLElement; |
23,8 → 23,8 |
public class UserRightGroupComptaSQLElement extends UserRightSQLElement { |
public UserRightGroupComptaSQLElement() { |
super(); |
public UserRightGroupComptaSQLElement(final DBRoot r) { |
super(r); |
// ((Group)GlobalMapper.getInstance().get(UserRightSQLComponent.ID)). |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/translation/messages_pl.properties |
---|
7,4 → 7,7 |
apply.associated.pricelist.to.customer=Zastosuj cennik klienta |
invoice.address.same.main.address=Adres faktury same jak g\u0142ówny adres |
delivery.address.same.main.address=Adres dostawy same jak g\u0142ówny adres |
additional.address=Dodatkowy adres |
additional.address=Dodatkowy adres |
createMenuItem.name={elem__singular} |
listMenuItem.name=List of {elem__plural} |
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/translation/messages_en.properties |
---|
12,6 → 12,8 |
delivery.address.same.main.address=Delivery address same as main address |
additional.address=Additional address |
register.missing.title=Configuration error |
register.missing=The register n° {0} doesn\u2019t exist in the database.\n\nPlease create it or modify this host's configuration. |
register.moved.title=Different host |
register.moved=<html>It seems that this register has been moved.\ |
You can ignore this message if for instance :\ |
24,7 → 26,36 |
register.moved.ignore=Ignore |
register.moved.quit=Quit |
register.notReconciled.title=Incoherence of the opening state of the register |
register.notReconciled.outsideMeddling=The files and/or data base were modified outside of this software. |
register.notReconciled.resumeFailed=The opening or closure was interrupted, the process was resumed but it failed. |
register.notReconciled.unknown=The opening of the register on this host and in the database was incoherent. \ |
The state couldn\u2019t be reconciled. |
# local open |
register.notReconciled.open.datesMismatch=The register was opened at different dates on this host ({localDate,date} at {localDate,time}) \ |
and in the database ({remoteDate,date} at {remoteDate,time}). |
register.notReconciled.localOpen_remoteClosed=The register is opened on this host ({localDate,date} at {localDate,time}) \ |
but closed in the database ({remoteDate,date} at {remoteDate,time}). |
register.notReconciled.localOpen_remoteMissing=The register is opened on this host ({localDate,date} at {localDate,time}) \ |
but was never opened in the database. |
# remote open |
register.notReconciled.localMissing_remoteReopen=The register was opened multiple times in the database \ |
(the last time {remoteDate,date} at {remoteDate,time}), but never on this host. |
register.notReconciled.localOpenFailed_remoteOpen=The register was open in the database ({remoteDate,date} at {remoteDate,time}) \ |
and the opening on this host failed. |
register.notReconciled.localClosed_remoteCloseFailed=The register was closed on this host ({localDate,date} at {localDate,time}) \ |
and the closure in the database failed. |
register.notReconciled.localClosed_remoteOpen.datesMismatch=The register is closed on this host ({localDate,date} at {localDate,time}) \ |
but open in the database ({remoteDate,date} at {remoteDate,time}). The opening and closure dates don\u2019t match. |
# both closed |
register.notReconciled.localMissing_remoteClosed=The register is closed in the database ({remoteDate,date} at {remoteDate,time}) \ |
but was never used on this host. |
register.notReconciled.closed.datesMismatch=The register is closed on this host ({localDate,date} at {localDate,time}) \ |
and in the database ({remoteDate,date} at {remoteDate,time}), but with different dates. |
register.notReconciled.localClosed_remoteMissing=The register is closed on this host ({localDate,date} at {localDate,time}) \ |
but the database is empty. |
sddMessage.generation.noneNeeded=No invoice needs {msgElem__singularIndefiniteArticle}. |
sddMessage.generation.noneIgnored=The generated {msgElem__singular} includes {invoiceElem__definiteNumeral}. |
sddMessage.generation.someIgnored={invoiceElemCount, plural, =0 {All invoices needing {msgElem__singularIndefiniteArticle} were ignored :}\ |
33,3 → 64,47 |
sddMessage.generation.someIgnored.duplicateMandate={duplicateCount, plural, =1 {one because its mandate was shared with another invoice}\ |
other {# because their mandates were shared with other invoices}}. You must generate again {msgElem__singularIndefiniteArticle}. |
sddMessage.generation.someIgnored.missingInfo={missingInfoCount, plural, =1 {one because some information was missing} other {# because some information was missing}} |
sales.shipment.allShipments=All shipments |
sales.shipment.nonInvoicedShipments=Non invoiced shipments |
sales.shipment.invoicedShipments=Invoiced shipments |
sales.shipment.listTotal=Total of the shipments in the list |
dateFilter.none=No filter |
dateFilter.currentYear=Current year |
dateFilter.previousYear=Previous year |
dateFilter.currentMonth=Current month |
dateFilter.previousMonth=Previous month |
dateFilter.currentWeek=Current week |
dateFilter.previousWeek=Previous week |
dateFilter.currentFiscalYear=Current fiscal year |
dateFilter.custom=Custom |
dateFilter.range=Range |
dateFilter.from=From |
dateFilter.to=To |
TotalPanel.global=Global |
TotalPanel.margin=Margin |
TotalPanel.purchaseTotal.taxExcluded=Purchase total excl tax |
TotalPanel.service.taxExcluded=Service included excl tax |
TotalPanel.total.taxExcluded=Total excl tax |
TotalPanel.total.taxIncluded=Total incl tax |
TotalPanel.total.VAT=VAT total |
TotalPanel.currencyTotal=Currency total |
TotalPanel.ecoTax=Dont Eco-Contrib. |
TotalPanel.estimatedBudget=Estimated budget |
TotalPanel.selection=Selection |
deliveryForm.applyClientRates=Apply client rates? |
deliveryForm.cannotAdd.existingNumber=Cannot add, form number already exists. |
deliveryForm.cannotCreate.notInStock=Cannot create the form, the following articles are out of stock : |
deliveryForm.numberRefreshed=The number has been refreshed to {0} |
deliveryForm.shipAll=Ship all |
createMenuItem.name={elem__singular} |
listMenuItem.name=List of {elem__plural} |
PanelOOSQLComponent.createSubscription=Create subscription |
PanelOOSQLComponent.missingField=Cannot add a combo to choose templates because the field ID_MODELE is missing in the table {0} |
PanelOOSQLComponent.print=Print |
PanelOOSQLComponent.view=View |
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/translation/messages_es.properties |
---|
New file |
0,0 → 1,78 |
add=Ajouter |
modify.or.delete=Modifier/Supprimer |
address=Adresse |
address.type.invoice=Facturation |
address.type.delivery=Livraison |
address.type.external=Mandataire |
address.type.other=Autre |
product.bom.expand.warning=Attention en éclatant la nomenclature le prix total sera calculé à partir du prix des composants! |
product.bom.flatexpand.warning=Attention en applatissant la nomenclature le kit sera remplacé par ses composants! |
apply.associated.pricelist.to.customer=Appliquer les tarifs associés au client |
invoice.address.same.main.address=Adresse de facturation identique à la principale |
delivery.address.same.main.address=Adresse de livraison identique à l\u2019adresse principale |
additional.address=Adresses supplémentaires |
register.moved.title=Hôte différent |
register.moved=<html>Il semble que cette caisse ait été déplacée.\ |
Vous pouvez ignorer ce message si par exemple :\ |
<ul>\ |
<li>la session utilisateur a été renommé,</li>\ |
<li>l\u2019ordinateur a été renommé,</li>\ |
<li>la caisse a été déplacé vers un nouvel ordinateur.</li>\ |
</ul><p>Si ce n\u2019est pas le cas, merci de vérifier qu\u2019il n\u2019y ait pas plusieurs installations configurées avec le même numéro de caisse (n° {0}).\ |
<p>Voulez-vous ignorer message et continuer ou alors quitter l\u2019application ?</html> |
register.moved.ignore=Ignorer |
register.moved.quit=Quitter |
sddMessage.generation.noneNeeded=Aucune facture ne nécessite {msgElem__de__singular}. |
sddMessage.generation.noneIgnored={msgElem__singularDefiniteArticle} généré inclut {invoiceElem__definiteNumeral}. |
sddMessage.generation.someIgnored={invoiceElemCount, plural, =0 {Toutes les factures nécessitant {msgElem__singularIndefiniteArticle} ont été ignorées :}\ |
other {{msgElem__singularDefiniteArticle} généré inclut {invoiceElem__indefiniteNumeral}, d\u2019autres ont été ignorées :}} |
sddMessage.generation.someIgnored.future={futureCount, plural, =1 {une car sa date d\u2019échéance est trop éloignée} other {# car leurs dates d\u2019échéance sont trop éloignées}} |
sddMessage.generation.someIgnored.duplicateMandate={duplicateCount, plural, =1 {une car son mandat est partagé avec une autre facture}\ |
other {# car leurs mandats sont partagés avec d\u2019autres factures}}. Vous devez générer à nouveau {msgElem__singularIndefiniteArticle}. |
sddMessage.generation.someIgnored.missingInfo={missingInfoCount, plural, =1 {une car il manquait des informations} other {# car il manquait des informations}} |
sales.shipment.allShipments=Todas las salidas |
sales.shipment.nonInvoicedShipments=Salidas no facturadas |
sales.shipment.invoicedShipments=Salidas facturas |
sales.shipment.listTotal=Total salidas de la lista |
dateFilter.none=Sin filtrar |
dateFilter.currentYear=Año corriente |
dateFilter.previousYear=Año anterior |
dateFilter.currentMonth=Mes corriente |
dateFilter.previousMonth=Mes anterior |
dateFilter.currentWeek=Semana corriente |
dateFilter.previousWeek=Semana anterior |
dateFilter.currentFiscalYear=Ejercicio corriente |
dateFilter.custom=Personalizado |
dateFilter.range=Periodo |
dateFilter.from=Del |
dateFilter.to=Al |
TotalPanel.global=Global |
TotalPanel.margin=Margen |
TotalPanel.purchaseTotal.taxExcluded=Total compra bruto |
TotalPanel.service.taxExcluded=Service HT inclus |
TotalPanel.total.taxExcluded=Total bruto |
TotalPanel.total.taxIncluded=Total TTC |
TotalPanel.total.VAT=Total TVA |
TotalPanel.currencyTotal=Total Devise |
TotalPanel.ecoTax=Dont Eco-Contrib. |
TotalPanel.estimatedBudget=Budget prévisionnel |
TotalPanel.selection=Selección |
deliveryForm.applyClientRates=Appliquer les tarifs associés au client? |
deliveryForm.cannotAdd.existingNumber=Impossible d\u2019ajouter, numéro de bon existant. |
deliveryForm.cannotCreate.notInStock=Impossible de créer le BL, Les articles suivants ne sont pas en stock : |
deliveryForm.numberRefreshed=Le numéro a été actualisé en {0} |
deliveryForm.shipAll=Entregar todo |
createMenuItem.name={elem__singular} |
listMenuItem.name=Lista de {elem__plural} |
PanelOOSQLComponent.createSubscription=Create subscription |
PanelOOSQLComponent.missingField=Cannot add a combo to choose templates because the field ID_MODELE is missing in the table {0} |
PanelOOSQLComponent.print=Imprimir |
PanelOOSQLComponent.view=Visualizar |
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/translation/messages_fr.properties |
---|
9,9 → 9,11 |
product.bom.flatexpand.warning=Attention en applatissant la nomenclature le kit sera remplacé par ses composants! |
apply.associated.pricelist.to.customer=Appliquer les tarifs associés au client |
invoice.address.same.main.address=Adresse de facturation identique à la principale |
delivery.address.same.main.address=Adresse de livraison identique à l'adresse principale |
delivery.address.same.main.address=Adresse de livraison identique à l\u2019adresse principale |
additional.address=Adresses supplémentaires |
register.missing.title=Erreur de configuration |
register.missing=La caisse n° {0} n\u2019existe pas dans la base de données.\n\nMerci de la créer ou de corriger le paramétrage de ce poste. |
register.moved.title=Hôte différent |
register.moved=<html>Il semble que cette caisse ait été déplacée.\ |
Vous pouvez ignorer ce message si par exemple :\ |
19,16 → 21,94 |
<li>la session utilisateur a été renommé,</li>\ |
<li>l\u2019ordinateur a été renommé,</li>\ |
<li>la caisse a été déplacé vers un nouvel ordinateur.</li>\ |
</ul><p>Si ce n'est pas le cas, merci de vérifier qu'il n'y ait pas plusieurs installations configurées avec le même numéro de caisse (n° {0}).\ |
</ul><p>Si ce n\u2019est pas le cas, merci de vérifier qu\u2019il n\u2019y ait pas plusieurs installations configurées avec le même numéro de caisse (n° {0}).\ |
<p>Voulez-vous ignorer message et continuer ou alors quitter l\u2019application ?</html> |
register.moved.ignore=Ignorer |
register.moved.quit=Quitter |
register.notReconciled.title=Incohérence d\u2019ouverture de la caisse |
register.notReconciled.outsideMeddling=Les fichiers et/ou la base de données ont été modifiés en dehors de ce logiciel. |
register.notReconciled.resumeFailed=L\u2019ouverture ou la clôture avait été interrompue, elle a repris sans succès. |
register.notReconciled.unknown=L\u2019ouverture de la caisse sur ce poste et dans la base de donnée était incohérente. \ |
L\u2019état n\u2019a pas pu être réconcilié. |
# local open |
register.notReconciled.open.datesMismatch=La caisse est ouverte à des dates différentes sur ce poste (le {localDate,date} à {localDate,time}) \ |
et dans la base de donnée (le {remoteDate,date} à {remoteDate,time}). |
register.notReconciled.localOpen_remoteClosed=La caisse est ouverte sur ce poste (le {localDate,date} à {localDate,time}) \ |
mais fermée dans la base de donnée (le {remoteDate,date} à {remoteDate,time}). |
register.notReconciled.localOpen_remoteMissing=La caisse est ouverte sur ce poste (le {localDate,date} à {localDate,time}) \ |
mais n\u2019a jamais été ouverte dans la base de donnée. |
# remote open |
register.notReconciled.localMissing_remoteReopen=La caisse a été ouverte plusieurs fois dans la base de donnée \ |
(la dernière fois le {remoteDate,date} à {remoteDate,time}), mais jamais sur ce poste. |
register.notReconciled.localOpenFailed_remoteOpen=La caisse avait été ouverte dans la base de donnée (le {remoteDate,date} à {remoteDate,time}) \ |
et l\u2019ouverture sur ce poste a échouée. |
register.notReconciled.localClosed_remoteCloseFailed=La caisse avait été fermée sur ce poste (le {localDate,date} à {localDate,time}) \ |
et la clôture dans la base de donnée a échouée. |
register.notReconciled.localClosed_remoteOpen.datesMismatch=La caisse est fermée sur ce poste (le {localDate,date} à {localDate,time}) \ |
mais ouverte dans la base de donnée (le {remoteDate,date} à {remoteDate,time}). Les dates d\u2019ouverture et de clôture précédentes ne concordent pas. |
# both closed |
register.notReconciled.localMissing_remoteClosed=La caisse est fermée dans la base de donnée (le {remoteDate,date} à {remoteDate,time}), \ |
mais n\u2019a jamais été utilisée sur ce poste. |
register.notReconciled.closed.datesMismatch=La caisse est fermée sur ce poste (le {localDate,date} à {localDate,time}) \ |
et dans la base de donnée (le {remoteDate,date} à {remoteDate,time}), mais les dates ne concordent pas. |
register.notReconciled.localClosed_remoteMissing=La caisse est fermée sur ce poste (le {localDate,date} à {localDate,time}) \ |
mais la base de donnée est vide. |
sddMessage.generation.noneNeeded=Aucune facture ne nécessite {msgElem__de__singular}. |
sddMessage.generation.noneIgnored={msgElem__singularDefiniteArticle} généré inclut {invoiceElem__definiteNumeral}. |
sddMessage.generation.someIgnored={invoiceElemCount, plural, =0 {Toutes les factures nécessitant {msgElem__singularIndefiniteArticle} ont été ignorées :}\ |
other {{msgElem__singularDefiniteArticle} généré inclut {invoiceElem__indefiniteNumeral}, d'autres ont été ignorées :}} |
other {{msgElem__singularDefiniteArticle} généré inclut {invoiceElem__indefiniteNumeral}, d\u2019autres ont été ignorées :}} |
sddMessage.generation.someIgnored.future={futureCount, plural, =1 {une car sa date d\u2019échéance est trop éloignée} other {# car leurs dates d\u2019échéance sont trop éloignées}} |
sddMessage.generation.someIgnored.duplicateMandate={duplicateCount, plural, =1 {une car son mandat est partagé avec une autre facture}\ |
other {# car leurs mandats sont partagés avec d\u2019autres factures}}. Vous devez générer à nouveau {msgElem__singularIndefiniteArticle}. |
sddMessage.generation.someIgnored.missingInfo={missingInfoCount, plural, =1 {une car il manquait des informations} other {# car il manquait des informations}} |
sales.shipment.allShipments=Toutes les livraisons |
sales.shipment.nonInvoicedShipments=Livraisons non facturées |
sales.shipment.invoicedShipments=Livraisons facturées |
sales.shipment.listTotal=Total des livraisons de la liste |
dateFilter.none=Sans filtrage |
dateFilter.currentYear=Année courante |
dateFilter.previousYear=Année précédente |
dateFilter.currentMonth=Mois courant |
dateFilter.previousMonth=Mois précédent |
dateFilter.currentWeek=Semaine courante |
dateFilter.previousWeek=Semaine précédente |
dateFilter.currentFiscalYear=Exercice courant |
dateFilter.custom=Personnalisée |
dateFilter.range=Période |
dateFilter.from=Du |
dateFilter.to=Au |
TotalPanel.global=Global |
TotalPanel.margin=Marge |
TotalPanel.purchaseTotal.taxExcluded=Total achat HT |
TotalPanel.service.taxExcluded=Service HT inclus |
TotalPanel.total.taxExcluded=Total HT |
TotalPanel.total.taxIncluded=Total TTC |
TotalPanel.total.VAT=Total TVA |
TotalPanel.currencyTotal=Total Devise |
TotalPanel.ecoTax=Dont Eco-Contrib. |
TotalPanel.estimatedBudget=Budget prévisionnel |
TotalPanel.selection=Sélection |
deliveryForm.applyClientRates=Appliquer les tarifs associés au client? |
deliveryForm.cannotAdd.existingNumber=Impossible d\u2019ajouter, numéro de bon existant. |
deliveryForm.cannotCreate.notInStock=Impossible de créer le BL, Les articles suivants ne sont pas en stock : |
deliveryForm.numberRefreshed=Le numéro a été actualisé en {0} |
deliveryForm.shipAll=Tout livrer |
createMenuItem.name={elem__singular} |
listMenuItem.name=Liste {elem__pluralIndefiniteArticle} |
PanelOOSQLComponent.createSubscription=Créer l\u2019abonnement associé |
PanelOOSQLComponent.missingField=Impossible d\u2019ajouter la combo pour le choix des modèles car le champ ID_MODELE n\u2019est pas présent dans la table {0} |
PanelOOSQLComponent.print=Imprimer |
PanelOOSQLComponent.view=Visualiser |
accounting.editing.piece.label=Nom de la pièce comptable |
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/ConvertDevise.java |
---|
23,20 → 23,15 |
/** |
* Convertit un prix ht en ttc |
* |
* @param ht |
* la valeur hors taxe à convertir |
* @param taxe |
* taux de la tva à appliquer (ex : 7, 20) |
* @param scale |
* précision à appliquer sur le ttc retourné |
* @param ht la valeur hors taxe à convertir |
* @param taxe taux de la tva à appliquer (ex : 7, 20) |
* @param scale précision à appliquer sur le ttc retourné |
* @return le ttc avec la précision scale |
*/ |
public static final BigDecimal getTtcFromHt(BigDecimal ht, BigDecimal taxe, |
int scale) { |
public static final BigDecimal getTtcFromHt(BigDecimal ht, BigDecimal taxe, int scale) { |
BigDecimal tauxB = taxe.movePointLeft(2).add(BigDecimal.ONE); |
BigDecimal result = ht.multiply(tauxB, DecimalUtils.HIGH_PRECISION) |
.setScale(scale, RoundingMode.HALF_UP); |
BigDecimal result = ht.multiply(tauxB, DecimalUtils.HIGH_PRECISION).setScale(scale, RoundingMode.HALF_UP); |
return result; |
} |
44,23 → 39,18 |
/** |
* Convertit un prix ttc en ht |
* |
* @param tts |
* la valeur tts à convertir |
* @param taxe |
* taux de la tva à appliquer (ex : 7, 20) |
* @param scale |
* précision à appliquer sur le ht retourné |
* @param tts la valeur tts à convertir |
* @param taxe taux de la tva à appliquer (ex : 7, 20) |
* @param scale précision à appliquer sur le ht retourné |
* @return le ht avec la précision scale |
*/ |
public static final BigDecimal getHtFromTtc(BigDecimal ttc, |
BigDecimal taxe, int scale) { |
public static final BigDecimal getHtFromTtc(BigDecimal ttc, BigDecimal taxe, int scale) { |
if (taxe.signum() == 0) { |
return ttc.setScale(scale, RoundingMode.HALF_UP); |
} |
BigDecimal tauxB = taxe.movePointLeft(2).add(BigDecimal.ONE); |
BigDecimal result = ttc.divide(tauxB, DecimalUtils.HIGH_PRECISION).setScale( |
scale, RoundingMode.HALF_UP); |
BigDecimal result = ttc.divide(tauxB, DecimalUtils.HIGH_PRECISION).setScale(scale, RoundingMode.HALF_UP); |
return result; |
} |
67,8 → 57,7 |
public static void main(String[] args) { |
BigDecimal ttcFromHt = getTtcFromHt(BigDecimal.ONE, new BigDecimal(20), |
6); |
BigDecimal ttcFromHt = getTtcFromHt(BigDecimal.ONE, new BigDecimal(20), 6); |
System.err.println(ttcFromHt); |
System.err.println(getHtFromTtc(ttcFromHt, new BigDecimal(20), 6)); |
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/HeadlessGestion.java |
---|
32,30 → 32,29 |
try { |
this.comptaPropsConfiguration.getUserManager().setCurrentUserID(userId); |
this.comptaPropsConfiguration.setUpSocieteDataBaseConnexion(companyId); |
// finish filling the configuration before going any further, otherwise the |
// SQLElementDirectory is not coherent |
this.comptaPropsConfiguration.getModuleManager().init(); |
} catch (Exception e) { |
e.printStackTrace(); |
throw new IllegalStateException("Unable to configure connection for userId: " + userId + " companyId: " + companyId); |
throw new IllegalStateException("Unable to configure connection for userId: " + userId + " companyId: " + companyId, e); |
} |
return this; |
} |
public HeadlessGestion setupGlobalState(int userId, int companyId) { |
setupGlobalState(userId, companyId); |
// setUpSocieteDataBaseConnexion() called by setup() needs the directory and elements need |
// Configuration.getInstance() |
setGlobalState(); |
setup(userId, companyId); |
return this; |
} |
public HeadlessGestion setGlobalState() { |
System.setProperty("java.awt.headless", "true"); |
TranslationManager.getInstance().addTranslationStreamFromClass(MainFrame.class); |
TranslationManager.getInstance().setLocale(Locale.getDefault()); |
// TODO remove |
Configuration.setInstance(this.comptaPropsConfiguration); |
System.out.println("HeadlessOpenConcerto ready"); |
System.out.println( |
"Connected to " + this.comptaPropsConfiguration.getServerIp() + " on " + this.comptaPropsConfiguration.getSystemRootName() + "/" + this.comptaPropsConfiguration.getSocieteBaseName()); |
return this; |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/graph/GraphArticleMargePanel.java |
---|
42,11 → 42,7 |
sel.addSelect(tableVFElement.getField("QTE"), "SUM"); |
@SuppressWarnings("unchecked") |
final List<Object[]> rowsArticle = (List<Object[]>) Configuration |
.getInstance() |
.getBase() |
.getDataSource() |
.execute( |
final List<Object[]> rowsArticle = (List<Object[]>) Configuration.getInstance().getBase().getDataSource().execute( |
sel.asString() + " GROUP BY \"SAISIE_VENTE_FACTURE_ELEMENT\".\"" + field + "\"" + ",\"SAISIE_VENTE_FACTURE_ELEMENT\".\"PA_HT\"" + ",\"SAISIE_VENTE_FACTURE_ELEMENT\".\"PV_HT\"", |
new ArrayListHandler()); |
/trunk/OpenConcerto/src/org/openconcerto/erp/importer/DataImporter.java |
---|
20,6 → 20,7 |
import org.openconcerto.sql.model.SQLBase; |
import org.openconcerto.sql.model.SQLField; |
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.users.UserManager; |
116,10 → 117,10 |
public void commit() throws SQLException { |
for (SQLRowValues row : this.valuesToInsert) { |
row.insert(); |
row.getGraph().store(StoreMode.INSERT, false); |
} |
for (SQLRowValues row : this.valuesToUpdate) { |
row.update(); |
row.getGraph().store(StoreMode.COMMIT, false); |
} |
doAfterImport(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/logo_paypal_106x29.png |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/logo_paypal_106x29.png |
---|
New file |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/PayPalPreferencePanel.java |
---|
New file |
0,0 → 1,280 |
/* |
* 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.preferences; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.preferences.SQLPreferences; |
import org.openconcerto.ui.DefaultGridBagConstraints; |
import org.openconcerto.ui.JLabelBold; |
import org.openconcerto.ui.preferences.JavaPrefPreferencePanel; |
import org.openconcerto.ui.preferences.PrefView; |
import org.openconcerto.utils.Base64; |
import org.openconcerto.utils.JImage; |
import org.openconcerto.utils.PrefType; |
import java.awt.Desktop; |
import java.awt.GridBagConstraints; |
import java.awt.GridBagLayout; |
import java.awt.event.ActionEvent; |
import java.awt.event.ActionListener; |
import java.io.IOException; |
import java.io.InputStream; |
import java.io.InputStreamReader; |
import java.io.OutputStream; |
import java.net.HttpURLConnection; |
import java.net.URI; |
import java.net.URISyntaxException; |
import java.net.URL; |
import java.net.URLConnection; |
import java.net.URLEncoder; |
import java.nio.charset.StandardCharsets; |
import java.util.HashMap; |
import java.util.Map; |
import java.util.StringJoiner; |
import javax.swing.JButton; |
import javax.swing.JCheckBox; |
import javax.swing.JComponent; |
import javax.swing.JLabel; |
import javax.swing.JOptionPane; |
import javax.swing.JPanel; |
import javax.swing.SwingConstants; |
public class PayPalPreferencePanel extends JavaPrefPreferencePanel { |
public static final String PAYPAL_INVOICE = "paypal.invoice"; |
public static final String PAYPAL_CLIENTID = "paypal.clientid"; |
public static final String PAYPAL_SECRET = "paypal.secret"; |
public static final String PAYPAL_INVOICE_X = "paypal.invoice.x"; |
public static final String PAYPAL_INVOICE_Y = "paypal.invoice.y"; |
// Usage : |
// SQLPreferences prefs = SQLPreferences.getMemCached(comptaConf.getRootSociete()); |
// prefs.getBoolean(PayPalPreferencePanel.PAYPAL_INVOICE, false)); |
public PayPalPreferencePanel() { |
super("Paypal", null); |
setPrefs(new SQLPreferences(((ComptaPropsConfiguration) Configuration.getInstance()).getRootSociete())); |
this.removeAll(); |
this.setLayout(new GridBagLayout()); |
GridBagConstraints c = new DefaultGridBagConstraints(); |
// Logo |
c.gridwidth = 3; |
c.weightx = 1; |
c.fill = GridBagConstraints.NONE; |
c.anchor = GridBagConstraints.WEST; |
final JImage img = new JImage(PayPalPreferencePanel.class.getResource("logo_paypal_106x29.png")); |
try { |
img.setHyperLink(new URI("https://www.paypal.fr")); |
} catch (URISyntaxException e2) { |
// No hyperlink |
} |
this.add(img, c); |
c.gridy++; |
c.fill = GridBagConstraints.HORIZONTAL; |
c.gridwidth = 3; |
this.add(new JLabel("Intégration du lien de paiement PayPal dans les factures PDF"), c); |
c.gridy++; |
this.add(new JLabel("Cette fonctionnalité nécessite la création d'un compte professionnel (gratuit)."), c); |
// Account creation |
final JButton b = new JButton("Créer votre compte maintenant"); |
b.addActionListener(new ActionListener() { |
@Override |
public void actionPerformed(ActionEvent e) { |
if (Desktop.isDesktopSupported()) { |
final String url = "https://www.paypal.com/fr/merchantsignup/create"; |
try { |
Desktop.getDesktop().browse(new URI(url)); |
} catch (IOException | URISyntaxException e1) { |
JOptionPane.showMessageDialog(PayPalPreferencePanel.this, url, "Erreur d'ouverture du navigateur", JOptionPane.WARNING_MESSAGE); |
} |
} |
} |
}); |
c.gridy++; |
c.fill = GridBagConstraints.NONE; |
this.add(b, c); |
c.gridy++; |
this.add(new JLabel(" "), c); |
c.gridy++; |
this.add(new JLabelBold("Paramètres de l'API"), c); |
c.gridy++; |
this.add(new JLabel("à créer depuis https://developer.paypal.com"), c); |
// Client ID |
c.gridx = 0; |
c.gridy++; |
c.fill = GridBagConstraints.HORIZONTAL; |
c.gridwidth = 1; |
c.weightx = 0; |
this.add(new JLabel("Client ID", SwingConstants.RIGHT), c); |
c.gridwidth = 2; |
c.gridx++; |
c.weightx = 1; |
PrefView<String> clientIdPrefView = new PrefView<>(PrefType.STRING_TYPE, "Client ID", PAYPAL_CLIENTID); |
this.addView(clientIdPrefView); |
this.add(clientIdPrefView.getVW().getComp(), c); |
// Secret |
c.gridx = 0; |
c.gridy++; |
c.fill = GridBagConstraints.HORIZONTAL; |
c.gridwidth = 1; |
c.weightx = 0; |
this.add(new JLabel("Secret", SwingConstants.RIGHT), c); |
c.gridwidth = 2; |
c.gridx++; |
c.weightx = 1; |
PrefView<String> secretPrefView = new PrefView<>(PrefType.STRING_TYPE, "Secret", PAYPAL_SECRET); |
this.addView(secretPrefView); |
this.add(secretPrefView.getVW().getComp(), c); |
// Enable |
c.gridx = 0; |
c.gridy++; |
c.fill = GridBagConstraints.NONE; |
c.gridwidth = 3; |
c.weightx = 0; |
c.anchor = GridBagConstraints.EAST; |
final JButton bVerify = new JButton("Vérifier les paramètres"); |
this.add(bVerify, c); |
// Enable |
c.gridx = 1; |
c.gridy++; |
c.fill = GridBagConstraints.NONE; |
c.gridwidth = 1; |
c.weightx = 0; |
c.anchor = GridBagConstraints.EAST; |
PrefView<Boolean> enabledPrefView = new PrefView<>(PrefType.BOOLEAN_TYPE, "intégration", PAYPAL_INVOICE); |
this.addView(enabledPrefView); |
final JComponent comp = enabledPrefView.getVW().getComp(); |
((JCheckBox) comp).setText("intégrer le lien de paiement dans les factures PDF"); |
this.add(comp, c); |
// Position |
c.gridy++; |
c.fill = GridBagConstraints.HORIZONTAL; |
this.add(new JLabel(" "), c); |
c.gridy++; |
c.gridx = 0; |
c.gridwidth = 3; |
this.add(new JLabelBold("Position du logo sur le PDF"), c); |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = 1; |
c.weightx = 0; |
this.add(new JLabel("X (0 - 440)", SwingConstants.RIGHT), c); |
c.gridx++; |
PrefView<Integer> xPrefView = new PrefView<>(PrefType.INT_TYPE, "X", PAYPAL_INVOICE_X); |
xPrefView.setDefaultValue(10); |
this.addView(xPrefView); |
this.add(xPrefView.getVW().getComp(), c); |
c.gridx = 0; |
c.gridy++; |
c.gridwidth = 1; |
c.weightx = 0; |
this.add(new JLabel("Y (0 - 780)", SwingConstants.RIGHT), c); |
c.gridx++; |
PrefView<Integer> yPrefView = new PrefView<>(PrefType.INT_TYPE, "Y", PAYPAL_INVOICE_Y); |
yPrefView.setDefaultValue(10); |
this.addView(yPrefView); |
this.add(yPrefView.getVW().getComp(), c); |
c.gridy++; |
c.weighty = 1; |
JPanel spacer = new JPanel(); |
this.add(spacer, c); |
bVerify.addActionListener(new ActionListener() { |
@Override |
public void actionPerformed(ActionEvent e) { |
boolean ok = false; |
try { |
ok = sendAuth(clientIdPrefView.getVW().getValue(), secretPrefView.getVW().getValue()); |
} catch (IOException e1) { |
e1.printStackTrace(); |
} |
if (ok) { |
JOptionPane.showMessageDialog(PayPalPreferencePanel.this, "Paramètres OK", "API Paypal", JOptionPane.INFORMATION_MESSAGE); |
} else { |
JOptionPane.showMessageDialog(PayPalPreferencePanel.this, "Paramètres incorrects", "API Paypal", JOptionPane.ERROR_MESSAGE); |
} |
} |
}); |
} |
@Override |
protected void addViews() { |
// Nothing to do here, panel is built in the constructor |
} |
public static void main(String[] args) throws IOException { |
String id = "Abb2mKqK0TSU6Jgf71CJjFx0u5x6_NmEzHduuvsCXjYCfYxRg9GZ7B6ptx3pijriuq9Apx9Jp-VTFveF"; |
String s = "ENR1EyKreAlPbLRI0ofm2NbW6nyk8W5cJUZ7mvaBMgoQ6gB6VBivZpQW6B96toCtLZ3ClCUVutN-Gal2"; |
sendAuth(id, s + ""); |
} |
static boolean sendAuth(String clientId, String secret) throws IOException { |
final URL url = new URL("https://api.paypal.com/v1/oauth2/token"); |
final URLConnection con = url.openConnection(); |
final HttpURLConnection http = (HttpURLConnection) con; |
http.setRequestMethod("POST"); |
http.setDoOutput(true); |
http.setDefaultUseCaches(false); |
String authString = clientId + ":" + secret; |
String authStringEnc = Base64.encodeBytes(authString.getBytes(), Base64.DONT_BREAK_LINES); |
con.setRequestProperty("Authorization", "Basic " + authStringEnc); |
// x-www-form-urlencoded |
final Map<String, String> arguments = new HashMap<>(); |
arguments.put("grant_type", "client_credentials"); |
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")); |
} |
byte[] out = sj.toString().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) { |
return false; |
} |
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); |
} |
String result = sb.toString(); |
return result.contains("access_token"); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/GestionCommercialeGlobalPreferencePanel.java |
---|
40,6 → 40,7 |
public static String CREATE_ECR_CHQ = "CreateEcritureCheque"; |
public static String CHIFFRAGE_COMMANDE_CLIENT = "ChiffrageCmdClient"; |
public static String IMPUT_ECART = "ImputEcart"; |
public static String FRAIS_DOCUMENT = "GestionFraisDocuments"; |
public GestionCommercialeGlobalPreferencePanel() { |
super("Gestion des pièces commerciales", null); |
88,6 → 89,10 |
ecoColumns.setDefaultValue(Boolean.FALSE); |
this.addView(ecoColumns); |
PrefView<Boolean> fraisDoc = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Gérer des frais sur la création des documents clients", FRAIS_DOCUMENT); |
fraisDoc.setDefaultValue(Boolean.FALSE); |
this.addView(fraisDoc); |
PrefView<Boolean> ecoTotal = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Afficher le total de l'éco-contribution", AbstractArticleItemTable.SHOW_TOTAL_ECO_CONTRIBUTION); |
ecoTotal.setDefaultValue(Boolean.FALSE); |
this.addView(ecoTotal); |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/SocietePreferencePanel.java |
---|
19,13 → 19,21 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.ui.DefaultGridBagConstraints; |
import org.openconcerto.ui.preferences.DefaultPreferencePanel; |
import org.openconcerto.utils.checks.ValidListener; |
import org.openconcerto.utils.checks.ValidObject; |
import org.openconcerto.utils.checks.ValidState; |
import java.awt.GridBagConstraints; |
import java.awt.GridBagLayout; |
import javax.swing.JOptionPane; |
import javax.swing.SwingUtilities; |
public class SocietePreferencePanel extends DefaultPreferencePanel { |
private SQLComponent sc; |
private boolean valid = true; |
private String validText = ""; |
public SocietePreferencePanel() { |
this.setLayout(new GridBagLayout()); |
40,7 → 48,15 |
this.sc.uiInit(); |
this.sc.select(((ComptaPropsConfiguration) Configuration.getInstance()).getSocieteID()); |
this.add(this.sc, c); |
this.sc.addValidListener(new ValidListener() { |
@Override |
public void validChange(ValidObject src, ValidState newValue) { |
valid = newValue.isValid(); |
validText = newValue.getValidationText(); |
} |
}); |
} |
public String getTitleName() { |
return "Société"; |
47,10 → 63,27 |
} |
public void storeValues() { |
if (valid) { |
this.sc.update(); |
} else { |
final String t; |
if (this.validText == null) { |
t = "valeurs non valides"; |
} else { |
t = this.validText; |
} |
SwingUtilities.invokeLater(new Runnable() { |
public void restoreToDefaults() { |
@Override |
public void run() { |
JOptionPane.showMessageDialog(SocietePreferencePanel.this, t); |
} |
}); |
} |
} |
public void restoreToDefaults() { |
// nothing |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/GestionArticleGlobalPreferencePanel.java |
---|
17,6 → 17,7 |
package org.openconcerto.erp.preferences; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.core.common.ui.AbstractVenteArticleItemTable; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.preferences.SQLPreferences; |
import org.openconcerto.ui.preferences.JavaPrefPreferencePanel; |
35,6 → 36,7 |
public static String SHOW_PRODUCT_BAR_CODE = "ShowProductBarCode"; |
public static String ITEM_PACKAGING = "ItemPackaging"; |
public static String FILTER_BY_FAMILY = "FilterByFamily"; |
public static String STOCK_MULTI_DEPOT = "MultiDepot"; |
public static String CAN_EXPAND_NOMENCLATURE_VT = "CanExpandNomenclature"; |
public static String CAN_EXPAND_NOMENCLATURE_HA = "CanExpandNomenclaturePurchase"; |
46,6 → 48,10 |
@Override |
protected void addViews() { |
PrefView<Boolean> viewShowDevise = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Gérer plusieurs devises", AbstractVenteArticleItemTable.ARTICLE_SHOW_DEVISE); |
viewShowDevise.setDefaultValue(Boolean.FALSE); |
this.addView(viewShowDevise); |
PrefView<Boolean> viewExpandNom = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Permettre d'applatir, d'exposer, d'éclater les articles dans les pièces commerciales de vente", |
CAN_EXPAND_NOMENCLATURE_VT); |
viewExpandNom.setDefaultValue(Boolean.TRUE); |
72,6 → 78,10 |
view.setDefaultValue(Boolean.TRUE); |
this.addView(view); |
PrefView<Boolean> viewMultiStock = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Activer la gestion multidépôt", STOCK_MULTI_DEPOT); |
viewMultiStock.setDefaultValue(Boolean.FALSE); |
this.addView(viewMultiStock); |
PrefView<Boolean> view2 = new PrefView<Boolean>(PrefType.BOOLEAN_TYPE, "Gérer différentes unités de vente", UNITE_VENTE); |
view2.setDefaultValue(Boolean.TRUE); |
this.addView(view2); |
/trunk/OpenConcerto/src/org/openconcerto/erp/preferences/TemplatePreferencePanel.java |
---|
13,11 → 13,11 |
package org.openconcerto.erp.preferences; |
import org.openconcerto.erp.config.ComptaPropsConfiguration; |
import org.openconcerto.erp.generationDoc.AbstractLocalTemplateProvider; |
import org.openconcerto.erp.generationDoc.DefaultLocalTemplateProvider; |
import org.openconcerto.erp.generationDoc.TemplateManager; |
import org.openconcerto.erp.generationDoc.TemplateProvider; |
import org.openconcerto.sql.users.UserManager; |
import org.openconcerto.sql.users.rights.UserRightsManager; |
import org.openconcerto.ui.DefaultGridBagConstraints; |
import org.openconcerto.ui.preferences.DefaultPreferencePanel; |
48,7 → 48,6 |
import javax.swing.JTable; |
import javax.swing.JTextField; |
import javax.swing.ListSelectionModel; |
import javax.swing.SwingUtilities; |
import javax.swing.UIManager; |
import javax.swing.event.ListSelectionEvent; |
import javax.swing.event.ListSelectionListener; |
57,7 → 56,6 |
public class TemplatePreferencePanel extends DefaultPreferencePanel { |
private JTextField textTemplate; |
private JFileChooser fileChooser = null; |
private JButton bModify; |
private JButton bUndo; |
71,18 → 69,36 |
/******************************************************************************************* |
* Emplacement |
******************************************************************************************/ |
if (!ComptaPropsConfiguration.getInstanceCompta().isOnCloud()) { |
this.add(new JLabel("Modèles des documents"), cPanel); |
cPanel.gridx++; |
cPanel.weightx = 1; |
this.textTemplate = new JTextField(); |
this.add(this.textTemplate, cPanel); |
this.textTemplate.setEditable(false); |
final JButton buttonTemplate = new JButton("..."); |
cPanel.gridx++; |
cPanel.weightx = 0; |
cPanel.fill = GridBagConstraints.NONE; |
this.add(buttonTemplate, cPanel); |
buttonTemplate.addActionListener(new ActionListener() { |
public void actionPerformed(ActionEvent e) { |
final JFileChooser fileChooser = new JFileChooser(); |
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); |
fileChooser.setCurrentDirectory(new File(TemplatePreferencePanel.this.textTemplate.getText())); |
if (fileChooser.showDialog(TemplatePreferencePanel.this, "Sélectionner") == JFileChooser.APPROVE_OPTION) { |
File selectedFile = fileChooser.getSelectedFile(); |
if (selectedFile.exists()) { |
TemplatePreferencePanel.this.textTemplate.setForeground(UIManager.getColor("TextField.foreground")); |
} else { |
TemplatePreferencePanel.this.textTemplate.setForeground(Color.RED); |
} |
TemplatePreferencePanel.this.textTemplate.setText(selectedFile.getPath()); |
} |
} |
}); |
} |
final JPanel templates = createTemplateList(); |
templates.setOpaque(false); |
cPanel.gridy++; |
93,13 → 109,6 |
cPanel.gridx = 0; |
this.add(templates, cPanel); |
buttonTemplate.addActionListener(new ActionListener() { |
public void actionPerformed(ActionEvent e) { |
directoryChoose("template"); |
} |
}); |
this.textTemplate.setEditable(false); |
setValues(); |
} |
118,7 → 127,11 |
bUndo.setOpaque(false); |
c.gridx++; |
p.add(bUndo, c); |
if (ComptaPropsConfiguration.getInstanceCompta().isOnCloud()) { |
bSync = new JButton("Synchroniser vers le cloud"); |
} else { |
bSync = new JButton("Synchroniser"); |
} |
bSync.setEnabled(false); |
bSync.setOpaque(false); |
if (!UserRightsManager.getCurrentUserRights().haveRight("SYNC_TEMPLATE")) { |
175,10 → 188,18 |
if (provider instanceof AbstractLocalTemplateProvider) { |
final String templateId = dm.getTemplateId(row); |
File f = ((AbstractLocalTemplateProvider) provider).getFileTemplate(templateId, null, null); |
String path = "invalid path"; |
if (f != null) { |
try { |
path = f.getCanonicalPath(); |
} catch (IOException e) { |
path = f.getAbsolutePath(); |
} |
} |
if (f == null || !f.exists()) { |
tableCellRendererComponent.setBackground(Color.ORANGE); |
if (f != null) { |
setToolTipText(f.getAbsolutePath() + " not found"); |
setToolTipText(path + " not found"); |
} else { |
setToolTipText("no file for template " + templateId); |
} |
188,7 → 209,7 |
} else { |
tableCellRendererComponent.setBackground(table.getBackground()); |
} |
setToolTipText(f.getAbsolutePath()); |
setToolTipText(path); |
} |
} |
return tableCellRendererComponent; |
256,7 → 277,7 |
} |
public void storeValues() { |
if (this.textTemplate != null) { |
final File z = new File("."); |
final File f = new File(this.textTemplate.getText()); |
try { |
272,6 → 293,7 |
TemplateNXProps.getInstance().store(); |
} |
} |
public void restoreToDefaults() { |
282,6 → 304,7 |
} |
private void setValues() { |
if (this.textTemplate != null) { |
try { |
final File f = new File(TemplateNXProps.getInstance().getStringProperty("LocationTemplate")); |
if (f.exists()) { |
295,33 → 318,8 |
e.printStackTrace(); |
} |
} |
private void directoryChoose(final String type) { |
if (this.fileChooser == null) { |
this.fileChooser = new JFileChooser(); |
this.fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); |
} |
this.fileChooser.setCurrentDirectory(new File(TemplatePreferencePanel.this.textTemplate.getText())); |
SwingUtilities.invokeLater(new Runnable() { |
public void run() { |
if (TemplatePreferencePanel.this.fileChooser.showDialog(TemplatePreferencePanel.this, "Sélectionner") == JFileChooser.APPROVE_OPTION) { |
if (type.equalsIgnoreCase("template")) { |
File selectedFile = TemplatePreferencePanel.this.fileChooser.getSelectedFile(); |
if (selectedFile.exists()) { |
TemplatePreferencePanel.this.textTemplate.setForeground(UIManager.getColor("TextField.foreground")); |
} else { |
TemplatePreferencePanel.this.textTemplate.setForeground(Color.RED); |
} |
TemplatePreferencePanel.this.textTemplate.setText(selectedFile.getPath()); |
} |
} |
} |
}); |
} |
public void modifyTemplate(final TemplateTableModel dm, final JTable table) { |
int row = table.getSelectedRow(); |
dm.unsync(row); |
/trunk/OpenConcerto/src/org/openconcerto/erp/config/SQLElementNames_en.xml |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/erp/config/SQLElementNames_fr.xml |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/erp/config/SQLElementNames_pl.xml |
---|
File deleted |
/trunk/OpenConcerto/src/org/openconcerto/erp/config/InstallationPanel.java |
---|
19,6 → 19,7 |
import org.openconcerto.erp.core.sales.quote.element.EtatDevisSQLElement; |
import org.openconcerto.erp.modules.ModuleManager; |
import org.openconcerto.erp.modules.ModuleReference; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.changer.convert.AddFK; |
import org.openconcerto.sql.changer.convert.ChangeIDToInt; |
import org.openconcerto.sql.changer.correct.CorrectOrder; |
138,6 → 139,20 |
System.setProperty(SQLSchema.NOAUTO_CREATE_METADATA, "false"); |
final ComptaPropsConfiguration conf = ComptaPropsConfiguration.create(true); |
final DBSystemRoot systemRoot = conf.getSystemRoot(); |
if (systemRoot.getChild(conf.getRootNameValue().getValue()) == null) { |
conf.destroy(); |
SwingUtilities.invokeLater(new Runnable() { |
@Override |
public void run() { |
up.setEnabled(true); |
bar.setValue(bar.getMaximum()); |
JOptionPane.showMessageDialog(InstallationPanel.this, "Votre base de données n'est pas initialisée"); |
} |
}); |
return; |
} |
updateDatabase(conf); |
conf.destroy(); |
198,7 → 213,6 |
@Override |
public void actionPerformed(ActionEvent e) { |
// TODO Auto-generated method stub |
try { |
if (finderPanel.getServerConfig().createUserIfNeeded(login.getText(), mdp.getText())) { |
JOptionPane.showMessageDialog(InstallationPanel.this, "L'utilisateur openconcerto a été correctement ajouté."); |
206,7 → 220,6 |
JOptionPane.showMessageDialog(InstallationPanel.this, "L'utilisateur openconcerto existe déjà dans la base."); |
} |
} catch (Exception e1) { |
// TODO Auto-generated catch block |
e1.printStackTrace(); |
JOptionPane.showMessageDialog(InstallationPanel.this, "Une erreur est survenue pendant la connexion au serveur, vérifiez vos paramètres de connexion."); |
} |
882,11 → 895,14 |
for (final SQLTable t : root.getTables()) { |
final AlterTable alter = new AlterTable(t); |
for (final SQLField f : t.getFields()) { |
if (f.getType().getType() == Types.VARCHAR && f.getType().getSize() == Integer.MAX_VALUE) { |
// on PG, CLOB are text and the JDBC driver returns Types.VARCHAR, not CLOB. So test |
// if the type name contains "char", since we only want unbounded varchar, not |
// text/clob. |
if (f.getType().getType() == Types.VARCHAR && f.getType().getSize() == Integer.MAX_VALUE && f.getTypeDecl().contains("char")) { |
UpdateBuilder build = new UpdateBuilder(t); |
build.set(f.getName(), "''"); |
build.setWhere(new Where(f, "=", (Object) null)); |
build.setObject(f.getName(), ""); |
build.setWhere(Where.isNull(f)); |
builds.add(build); |
final String fName = f.getName(); |
1241,7 → 1257,190 |
checkDepartementExists(root, "Aisne", "Laon", "Picardie", "02"); |
if (root.contains("TARIF_AGENCE")) { |
SQLTable tableCmdFA = root.getTable("COMMANDE"); |
if (!tableCmdFA.contains("INCOTERM")) { |
AlterTable t = new AlterTable(tableCmdFA); |
t.addVarCharColumn("INCOTERM", 256); |
tableCmdFA.getBase().getDataSource().execute(t.asString()); |
tableCmdFA.getSchema().updateVersion(); |
tableCmdFA.fetchFields(); |
} |
SQLTable tableArticleA = root.getTable("ARTICLE"); |
if (!tableArticleA.contains("CLOSED_KIT")) { |
AlterTable t = new AlterTable(tableArticleA); |
t.addBooleanColumn("CLOSED_KIT", Boolean.FALSE, true); |
tableArticleA.getBase().getDataSource().execute(t.asString()); |
tableArticleA.getSchema().updateVersion(); |
tableArticleA.fetchFields(); |
} |
if (!tableArticleA.contains("CLOSED_KIT_DESC")) { |
AlterTable t = new AlterTable(tableArticleA); |
t.addVarCharColumn("CLOSED_KIT_DESC", 4096); |
tableArticleA.getBase().getDataSource().execute(t.asString()); |
tableArticleA.getSchema().updateVersion(); |
tableArticleA.fetchFields(); |
} |
SQLTable tableCmdFEltA = root.getTable("COMMANDE_ELEMENT"); |
if (!tableCmdFEltA.contains("INCOTERM")) { |
AlterTable t = new AlterTable(tableCmdFEltA); |
t.addVarCharColumn("INCOTERM", 256); |
tableCmdFEltA.getBase().getDataSource().execute(t.asString()); |
tableCmdFEltA.getSchema().updateVersion(); |
tableCmdFEltA.fetchFields(); |
} |
if (root.getTable("VILLE") == null) { |
// INSERT INTO "OpenConcerto49"."VILLE" ("CODE_POSTAL","NOM") SELECT |
// "CODE_POSTAL", |
// "VILLE" FROM "OpenConcerto49"."ADRESSE" a WHERE a."ARCHIVE"=0 |
final SQLCreateTable createTableVille = new SQLCreateTable(root, "VILLE"); |
createTableVille.addVarCharColumn("NOM", 2048); |
createTableVille.addVarCharColumn("CODE_POSTAL", 2048); |
createTableVille.addLongColumn("X_LAMBERT", 0L, true); |
createTableVille.addLongColumn("Y_LAMBERT", 0L, true); |
createTableVille.addLongColumn("POPULATION", 0L, true); |
try { |
root.getBase().getDataSource().execute(createTableVille.asString()); |
insertUndef(createTableVille); |
root.refetchTable("VILLE"); |
root.getSchema().updateVersion(); |
} catch (SQLException ex2) { |
throw new IllegalStateException("Erreur lors de la création de la table " + "VILLE", ex2); |
} |
} |
if (root.getTable("ARTICLE_PRIX_MIN_VENTE") == null) { |
final SQLCreateTable createTablePrixMin = new SQLCreateTable(root, "ARTICLE_PRIX_MIN_VENTE"); |
createTablePrixMin.addForeignColumn("ARTICLE"); |
createTablePrixMin.addIntegerColumn("QTE", 1); |
createTablePrixMin.addDecimalColumn("PRIX", 16, 8, BigDecimal.ZERO, true); |
createTablePrixMin.addDateAndTimeColumn("DATE"); |
try { |
root.getBase().getDataSource().execute(createTablePrixMin.asString()); |
insertUndef(createTablePrixMin); |
root.refetchTable("ARTICLE_PRIX_MIN_VENTE"); |
root.getSchema().updateVersion(); |
} catch (SQLException ex2) { |
throw new IllegalStateException("Erreur lors de la création de la table " + "ARTICLE_PRIX_MIN_VENTE", ex2); |
} |
} |
{ |
final SQLTable tableTarifAgence = root.getTable("TARIF_AGENCE"); |
AlterTable tTarifAgence = new AlterTable(tableTarifAgence); |
boolean updateTarifAgence = false; |
if (!tableTarifAgence.contains("PRC_AGENCE")) { |
updateTarifAgence = true; |
tTarifAgence.addDecimalColumn("PRC_AGENCE", 16, 8, BigDecimal.ZERO, true); |
} |
if (!tableTarifAgence.contains("CLOSED_KIT")) { |
updateTarifAgence = true; |
tTarifAgence.addBooleanColumn("CLOSED_KIT", false, true); |
} |
if (!tableTarifAgence.contains("PRIX_MIN_VENTE")) { |
updateTarifAgence = true; |
tTarifAgence.addDecimalColumn("PRIX_MIN_VENTE", 16, 8, BigDecimal.ZERO, true); |
} |
if (updateTarifAgence) { |
tableTarifAgence.getBase().getDataSource().execute(tTarifAgence.asString()); |
tableTarifAgence.getSchema().updateVersion(); |
tableTarifAgence.fetchFields(); |
} |
} |
{ |
final SQLTable tableClient = root.getTable("CLIENT"); |
AlterTable tClient = new AlterTable(tableClient); |
boolean updateClient = false; |
if (!tableClient.contains("ALG_REGISTRE")) { |
updateClient = true; |
tClient.addVarCharColumn("ALG_REGISTRE", 512); |
} |
if (!tableClient.contains("ALG_MATRICULE")) { |
updateClient = true; |
tClient.addVarCharColumn("ALG_MATRICULE", 512); |
} |
if (!tableClient.contains("ALG_ARTICLE")) { |
updateClient = true; |
tClient.addVarCharColumn("ALG_ARTICLE", 512); |
} |
if (updateClient) { |
tableClient.getBase().getDataSource().execute(tClient.asString()); |
tableClient.getSchema().updateVersion(); |
tableClient.fetchFields(); |
} |
} |
final SQLTable tableMvtStock = root.getTable("MOUVEMENT_STOCK"); |
if (!tableMvtStock.contains("PRICE")) { |
AlterTable tMvt = new AlterTable(tableMvtStock); |
tMvt.addDecimalColumn("PRICE", 16, 6, BigDecimal.ZERO, true); |
tableMvtStock.getBase().getDataSource().execute(tMvt.asString()); |
tableMvtStock.getSchema().updateVersion(); |
tableMvtStock.fetchFields(); |
} |
final SQLTable tableArticle = root.getTable("ARTICLE"); |
if (!tableArticle.contains("AUTO_PRIX_MIN_VENTE_NOMENCLATURE")) { |
AlterTable tArt = new AlterTable(tableArticle); |
tArt.addBooleanColumn("AUTO_PRIX_MIN_VENTE_NOMENCLATURE", false, true); |
tableMvtStock.getBase().getDataSource().execute(tArt.asString()); |
tableMvtStock.getSchema().updateVersion(); |
tableMvtStock.fetchFields(); |
} |
SQLTable tableContact = root.getTable("CONTACT"); |
if (!tableContact.contains("TYPE")) { |
AlterTable t = new AlterTable(tableContact); |
t.addVarCharColumn("TYPE", 256); |
t.addVarCharColumn("SERVICE", 256); |
t.addVarCharColumn("PAYS", 256); |
t.addForeignColumn("ID_ADRESSE", root.getTable("ADRESSE")); |
tableContact.getBase().getDataSource().execute(t.asString()); |
tableContact.getSchema().updateVersion(); |
tableContact.fetchFields(); |
} |
if (!root.contains("PERSONNEL_AFHYMAT")) { |
final SQLCreateTable createTablePers = new SQLCreateTable(root, "PERSONNEL_AFHYMAT"); |
createTablePers.addVarCharColumn("NOM", 256); |
createTablePers.addVarCharColumn("PRENOM", 256); |
createTablePers.addVarCharColumn("FONCTION", 256); |
try { |
root.getBase().getDataSource().execute(createTablePers.asString()); |
insertUndef(createTablePers); |
root.refetchTable("PERSONNEL_AFHYMAT"); |
root.getSchema().updateVersion(); |
} catch (SQLException ex) { |
throw new IllegalStateException("Erreur lors de la création de la table " + "PERSONNEL_AFHYMAT", ex); |
} |
final SQLCreateTable createTable = new SQLCreateTable(root, "PERSONNEL_AFHYMAT_COUT"); |
for (int i = 1; i <= 12; i++) { |
createTable.addDecimalColumn("SAL_MONTH_" + i, 16, 2, BigDecimal.ZERO, false); |
createTable.addDecimalColumn("COM_MONTH_" + i, 16, 2, BigDecimal.ZERO, false); |
} |
createTable.addIntegerColumn("ANNEE", 0); |
createTable.addForeignColumn("ID_PERSONNEL_AFHYMAT", root.getTable("PERSONNEL_AFHYMAT")); |
try { |
root.getBase().getDataSource().execute(createTable.asString()); |
insertUndef(createTable); |
root.refetchTable("PERSONNEL_AFHYMAT_COUT"); |
root.getSchema().updateVersion(); |
} catch (SQLException ex) { |
throw new IllegalStateException("Erreur lors de la création de la table " + "PERSONNEL_AFHYMAT_COUT", ex); |
} |
} |
List<String> tablesUiLocked = Arrays.asList("BON_DE_LIVRAISON", "COMMANDE_CLIENT", "SAISIE_VENTE_FACTURE", "AVOIR_CLIENT", "COMMANDE", "BON_RECEPTION", "FACTURE_FOURNISSEUR"); |
for (String tableName : tablesUiLocked) { |
final SQLTable table = root.getTable(tableName); |
1277,7 → 1476,6 |
} |
if (!root.getTable("ARTICLE").contains("TRANSPORT")) { |
final SQLTable tableArticle = root.getTable("ARTICLE"); |
AlterTable alterArticle = new AlterTable(tableArticle); |
alterArticle.addBooleanColumn("TRANSPORT", false, false); |
tableArticle.getBase().getDataSource().execute(alterArticle.asString()); |
1307,7 → 1505,6 |
{ |
if (root.getName().endsWith("54")) { |
final SQLTable tableArticle = root.getTable("ARTICLE"); |
AlterTable tArt = new AlterTable(tableArticle); |
if (!tableArticle.contains("LABEL_DOUANE")) { |
tArt.addVarCharColumn("LABEL_DOUANE", 512); |
2165,6 → 2362,7 |
root.getDBSystemRoot().getDataSource().execute(createTable.asString()); |
insertUndef(createTable); |
tableDevis.getSchema().updateVersion(); |
root.refetchTable("DEVISE_HISTORIQUE"); |
} catch (SQLException ex) { |
throw new IllegalStateException("Erreur lors de la création de la table TASK", ex); |
} |
3360,7 → 3558,7 |
patchFieldElt1Dot3(table, root); |
} |
private void updateSocieteSchema(final DBRoot root) throws IOException, Exception { |
private void updateSocieteSchema(final Configuration conf, final DBRoot root) throws IOException, Exception { |
final DBSystemRoot sysRoot = root.getDBSystemRoot(); |
final SQLDataSource ds = sysRoot.getDataSource(); |
System.out.println("InstallationPanel.InstallationPanel() UPDATE COMMERCIAL " + root); |
3464,7 → 3662,7 |
final List<ChangeTable<?>> changes = new ArrayList<ChangeTable<?>>(); |
final ModuleManager instance = new ModuleManager(); |
instance.setRoot(root); |
instance.setup(root, conf); |
final Collection<ModuleReference> refs = instance.getModulesInstalledRemotely(); |
final Set<String> allUsedTable = new HashSet<String>(); |
for (ModuleReference ref : refs) { |
3473,6 → 3671,10 |
} |
System.out.println("Tables created by modules:" + allUsedTable); |
final Set<String> notMigrated = instance.migrateOldTransientDirs(); |
if (!notMigrated.isEmpty()) |
System.out.println("Couldn't migrate old backed up/failed modules: " + notMigrated); |
final List<String> alterRequests = ChangeTable.cat(changes, root.getName()); |
try { |
for (final String req : alterRequests) { |
3956,24 → 4158,27 |
} |
public void updateDatabase(final ComptaPropsConfiguration conf) { |
try { |
final SQLDataSource ds = conf.getSystemRoot().getDataSource(); |
System.err.println("SystemRoot:" + conf.getSystemRoot()); |
System.err.println("Root:" + conf.getRoot()); |
final DBSystemRoot systemRoot = conf.getSystemRoot(); |
System.err.println("SystemRoot:" + systemRoot); |
final DBRoot rootCommon = conf.getRoot(); |
System.err.println("Root:" + rootCommon); |
final SQLDataSource ds = systemRoot.getDataSource(); |
// FixUnbounded varchar |
fixUnboundedVarchar(conf.getRoot()); |
fixUnboundedVarchar(rootCommon); |
// FIXME DROP CONSTRAINT UNIQUE ORDRE ON |
// CONTACT_FOURNISSEUR |
checkCompteDefault(conf.getRoot()); |
checkCompteDefault(rootCommon); |
updateSocieteTable(conf.getRoot()); |
updateVille(conf.getRoot().getTable("ADRESSE")); |
updateSocieteTable(rootCommon); |
updateVille(rootCommon.getTable("ADRESSE")); |
// Champ user 1.4.1 |
final SQLTable tableUser = conf.getRoot().getTable("USER_COMMON"); |
final SQLTable tableUser = rootCommon.getTable("USER_COMMON"); |
if (tableUser != null) { |
final AlterTable alter = new AlterTable(tableUser); |
boolean alterUser = false; |
3988,32 → 4193,32 |
if (alterUser) { |
final String req = alter.asString(); |
conf.getRoot().getDBSystemRoot().getDataSource().execute(req); |
conf.getRoot().refetchTable(tableUser.getName()); |
conf.getRoot().getSchema().updateVersion(); |
rootCommon.getDBSystemRoot().getDataSource().execute(req); |
rootCommon.refetchTable(tableUser.getName()); |
rootCommon.getSchema().updateVersion(); |
} |
} |
// Champ Paye |
final SQLTable tableCaisse = conf.getRoot().getTable("CAISSE_COTISATION"); |
final SQLTable tabl |