OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 179 → Rev 180

/trunk/OpenConcerto/src/org/openconcerto/ql/QLPrinterExample.java
18,15 → 18,19
 
public class QLPrinterExample {
public static void main(String[] args) {
QLPrinter prt = new QLPrinter("192.168.1.103");
QLPrinter prt = new QLPrinter("192.168.168.53");
prt.setHighQuality(true);
try {
 
prt.print(new File("Hello_720x300.png"));
String code = "123456789";
prt.printDataMatrixBarCode2D(10, code);
 
prt.print("Hello");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/ql/QLPrinter.java
23,10 → 23,12
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
 
import javax.imageio.ImageIO;
 
public class QLPrinter {
private static final int ESC = 0x1B;
private String host;
private boolean highQuality;
private boolean paperCutAuto;
49,7 → 51,7
 
/**
* Set print width (in milimeters)
* */
*/
public void setPrintWidth(int mm) {
this.printWidth = mm;
}
77,16 → 79,18
for (int i = 0; i < 200; i++) {
out.write(0x00);
}
// Init 0x1B 0x40
out.write(0x1B);
out.write(0x40);
// ?? : 0x1B 0x69 0x61 0x01
out.write(0x1B);
 
// Select ESCP/P Mode : 0x1B 0x69 0x61 0x01
out.write(ESC);
out.write(0x69);
out.write(0x61);
out.write(0x01);
// Init 0x1B 0x40
out.write(ESC);
out.write(0x40);
 
// Page Length
out.write(0x1B);
out.write(ESC);
out.write(0x69);
out.write(0x7A);
 
101,8 → 105,8
out.write(0);
out.write(0);
out.write(0);
// Paper Cut
out.write(0x1B);
// Paper Cut : ESC i
out.write(ESC);
out.write(0x69);
out.write(0x4D);
if (this.paperCutAuto) {
111,13 → 115,13
out.write(0x00);
}
 
// ?? : 0x1B 0x69 0x41 0x01
out.write(0x1B);
// ?? : 0x1B 0x69 0x41 0x01 :ESC i A
out.write(ESC);
out.write(0x69);
out.write(0x41);
out.write(0x01);
// Set Mode
out.write(0x1B);
// Set Mode : ESC i K
out.write(ESC);
out.write(0x69);
out.write(0x4B);
if (!this.highQuality) {
126,7 → 130,7
out.write(0x48);
}
// Set Margin
out.write(0x1B);
out.write(ESC);
out.write(0x69);
out.write(0x64);
out.write(0x00);
332,6 → 336,7
out.close();
in.close();
socket.close();
System.out.println("QLPrinter.print() done");
}
}
 
346,4 → 351,92
return cfA;
}
 
/**
* Print 2D barcode (DataMatrix)
*
* @param dotsPerCell (3 - 10)
* @param barcode : barcode (ascii)
* @throws IOException
*
*/
public void printDataMatrixBarCode2D(int dotsPerCell, String barcode) throws IOException {
if (barcode.length() > (144 * 144)) {
throw new IllegalArgumentException("barcode too long (max : 144x144:20736)");
}
 
ByteArrayOutputStream out = new ByteArrayOutputStream();
{
// Header: 0x00 : 200 fois
for (int i = 0; i < 200; i++) {
out.write(0x00);
}
 
}
 
// Select ESCP/P Mode : 0x1B 0x69 0x61 0x00
out.write(ESC);
out.write(0x69);
out.write(0x61);
out.write(0x00); // mode ESC/P standard
// Init 0x1B 0x40
out.write(ESC);
out.write(0x40);
 
// ESC i D
out.write(ESC);
out.write(0x69);
out.write(0x44);
//
out.write(dotsPerCell);
out.write(0); // square
out.write(0); // vertical size : auto
out.write(0); // horizontal size : auto
for (int i = 0; i < 5; i++) {
out.write(0); // reserved
}
// data
out.write(barcode.getBytes(StandardCharsets.US_ASCII));
out.write('\\');
out.write('\\');
out.write('\\');
// Page feed
out.write(0x0C);
 
out.flush();
 
final byte[] byteArray = out.toByteArray();
print(byteArray);
}
 
public void print(String string) throws IOException {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
// Select ESCP/P Mode : 0x1B 0x69 0x61 0x00
bOut.write(ESC);
bOut.write(0x69);
bOut.write(0x61);
bOut.write(0x0); // mode ESC/P standard
// Init 0x1B 0x40
bOut.write(ESC);
bOut.write(0x40);
 
// Init
bOut.write(ESC);
bOut.write(0x40);
// French characters
bOut.write(ESC);
bOut.write(0x52);
bOut.write(0x01);
// Normal
bOut.write(ESC);
bOut.write(0x21);
bOut.write(0);// Default
bOut.write(string.getBytes(StandardCharsets.US_ASCII));
bOut.write(0x0A);// Retour a la ligne
// Page feed
bOut.write(0x0C);
 
print(bOut.toByteArray());
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/OOXML.java
41,10 → 41,6
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
 
import org.jdom.Content;
import org.jdom.DocType;
import org.jdom.Document;
56,6 → 52,10
import org.jdom.xpath.XPath;
import org.xml.sax.SAXException;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
 
/**
* Various bits of OpenDocument XML.
*
69,6 → 69,7
* never return <code>null</code>, allowing to support unknown versions.
*/
public static final String LAST_FOR_UNKNOWN_PROP = OOXML.class.getPackage().getName() + ".lastOOXMLForUnknownVersion";
private static final boolean LAST_FOR_UNKNOWN = Boolean.getBoolean(LAST_FOR_UNKNOWN_PROP);
private static final XML_OO instanceOO = new XML_OO();
@GuardedBy("OOXML")
private static final SortedMap<String, XML_OD> instancesODByDate = new TreeMap<String, XML_OD>();
83,6 → 84,7
register(new XML_OD_1_0());
register(new XML_OD_1_1());
register(new XML_OD_1_2());
register(new XML_OD_1_3());
 
final List<OOXML> tmp = new ArrayList<OOXML>(instancesODByDate.size() + 1);
tmp.add(instanceOO);
106,7 → 108,7
* @see #LAST_FOR_UNKNOWN_PROP
*/
public static OOXML get(XMLFormatVersion version) {
return get(version, Boolean.getBoolean(LAST_FOR_UNKNOWN_PROP));
return get(version, LAST_FOR_UNKNOWN);
}
 
public static synchronized OOXML get(XMLFormatVersion version, final boolean lastForUnknown) {
741,11 → 743,17
}
}
 
private static final class XML_OD_1_2 extends XML_OD {
private static final class XML_OD_1_2 extends XML_OD_1_2plus {
public XML_OD_1_2() {
super("20110317", "1.2", "OpenDocument-v1.2-schema.rng", "OpenDocument-v1.2-manifest-schema.rng");
}
}
 
private static abstract class XML_OD_1_2plus extends XML_OD {
protected XML_OD_1_2plus(final String dateString, final String versionString, final String schemaFile, final String manifestSchemaFile) {
super(dateString, versionString, schemaFile, manifestSchemaFile);
}
 
@Override
public Document createManifestDoc() {
final Document res = super.createManifestDoc();
753,4 → 761,13
return res;
}
}
 
// https://issues.oasis-open.org/issues/?jql=project%20%3D%20OFFICE%20AND%20resolution%20%3D%20Fixed%20AND%20fixVersion%20%3D%20%22ODF%201.3%22
// - https://issues.oasis-open.org/browse/OFFICE-3860 : New attributes "min-decimal-places" and
// "forced-exponent-sign" parsed in DataStyle.formatNumberOrScientificNumber()
private static final class XML_OD_1_3 extends XML_OD_1_2plus {
public XML_OD_1_3() {
super("20191225", "1.3", "OpenDocument-schema-v1.3.rng", "OpenDocument-manifest-schema-v1.3.rng");
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/OOUtils.java
20,8 → 20,10
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.Locale;
 
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
120,4 → 122,33
public static Color decodeRGB(String color) {
return color == null ? null : Color.decode(color.trim());
}
 
public static final Locale getElementLocale(final Element elem) {
return getElementLocale(elem, elem.getNamespace());
}
 
public static final Locale getElementLocale(final Element elem, final Namespace ns) {
final Locale res;
final String country = elem.getAttributeValue("country", ns);
final String lang = elem.getAttributeValue("language", ns);
if (lang != null) {
res = new Locale.Builder().setLanguage(lang).setRegion(country).build();
} else {
res = null;
}
return res;
}
 
public static final void setElementLocale(final Element elem, final Namespace ns, final Locale l) {
if (l == null)
elem.removeAttribute("country", ns);
else
elem.setAttribute("country", l.getCountry(), ns);
 
final String lang = l == null ? null : l.getLanguage();
if (lang == null || lang.isEmpty())
elem.removeAttribute("language", ns);
else
elem.setAttribute("language", lang, ns);
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODValueType.java
85,6 → 85,7
return FLOAT.parse(s);
}
},
// TODO support LocalDateTime
DATE("date-value", Date.class, Calendar.class) {
 
@Override
106,12 → 107,15
}
 
},
TIME("time-value", Duration.class, Calendar.class) {
TIME("time-value", Duration.class, java.time.Duration.class, Calendar.class) {
 
@Override
public String format(Object o) {
if (o instanceof Duration) {
return o.toString();
} else if (o instanceof java.time.Duration) {
// w/o days or larger : PTnHnMnS
return o.toString();
} else {
final Calendar cal = (Calendar) o;
return TimeUtils.timePartToDuration(cal).toString();
218,7 → 222,7
return BOOLEAN;
else if (o instanceof String)
return STRING;
else if (o instanceof Duration)
else if (o instanceof Duration || o instanceof java.time.Duration)
return TIME;
else if (DATE.canFormat(o.getClass()))
return DATE;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/text/TextNode.java
158,7 → 158,7
static private final String getCharacterContent(final List<Content> pElem, final XMLFormatVersion vers, final boolean ooMode, final boolean useSeparator, final Option option) {
if (pElem.isEmpty())
return "";
final OOXML xml = OOXML.get(vers, false);
final OOXML xml = vers.getXML();
 
final StringBuilder sb = new StringBuilder();
final Namespace textNS = xml.getVersion().getTEXT();
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODPackage.java
268,11 → 268,8
}
 
public static ODPackage createFromFile(final File f) throws IOException {
final FileInputStream ins = new FileInputStream(f);
try {
try (final FileInputStream ins = new FileInputStream(f)) {
return create(f, ins, f.getName());
} finally {
ins.close();
}
}
 
600,19 → 597,19
return this.locale == null ? Locale.getDefault() : this.locale;
}
 
public final String formatNumber(Number n, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getNumberInstance(getLocale()), n, defaultStyle);
public static final String formatNumber(Number n, final Locale locale, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getNumberInstance(locale), n, defaultStyle);
}
 
public final String formatPercent(Number n, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getPercentInstance(getLocale()), n, defaultStyle);
public static final String formatPercent(Number n, final Locale locale, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getPercentInstance(locale), n, defaultStyle);
}
 
public final String formatCurrency(Number n, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getCurrencyInstance(getLocale()), n, defaultStyle);
public static final String formatCurrency(Number n, final Locale locale, final CellStyle defaultStyle) {
return formatNumber(NumberFormat.getCurrencyInstance(locale), n, defaultStyle);
}
 
private final String formatNumber(NumberFormat format, Number n, final CellStyle defaultStyle) {
private static final String formatNumber(NumberFormat format, Number n, final CellStyle defaultStyle) {
synchronized (format) {
final int decPlaces = DataStyle.getDecimalPlaces(defaultStyle);
format.setMinimumFractionDigits(0);
1183,13 → 1180,13
final Object val = entry.getData();
if (val != null) {
if (val instanceof ODXMLDocument) {
final OutputStream o = z.createEntry(name);
try (final OutputStream o = z.createEntryStream(name)) {
outputter.output(((ODXMLDocument) val).getDocument(), o);
o.close();
}
} else if (val instanceof Document) {
final OutputStream o = z.createEntry(name);
try (final OutputStream o = z.createEntryStream(name)) {
outputter.output((Document) val, o);
o.close();
}
} else {
z.zip(name, (byte[]) val, entry.isCompressed());
}
1245,8 → 1242,7
if (pageCount != null && getContentType() != null && ContentType.TEXT.equals(getContentType().getType()))
this.getMeta().getMetaChild("document-statistic").setAttribute("page-count", pageCount, getVersion().getMETA());
 
final Zip z = new Zip(out);
 
try (final Zip z = new Zip(out)) {
// magic number, see section 17.4
z.zipNonCompressed(MIMETYPE_ENTRY, this.getMimeType().getBytes(MIMETYPE_ENC));
 
1253,8 → 1249,8
final Manifest manifest = createManifest(z);
 
z.zip(Manifest.ENTRY_NAME, new StringInputStream(manifest.asString()));
z.close();
}
}
 
/**
* Save the content of this package to our file, overwriting it if it exists.
1272,12 → 1268,8
f.getParentFile().mkdirs();
// ATTN at this point, we must have read all the content of this file
// otherwise we could save to File.createTempFile("oofd", null).deleteOnExit();
final FileOutputStream out = new FileOutputStream(f);
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out, 512 * 1024);
try {
try (final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(f), 512 * 1024);) {
this.save(bufferedOutputStream);
} finally {
bufferedOutputStream.close();
}
return f;
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODXMLDocument.java
17,6 → 17,7
package org.openconcerto.openoffice;
 
import org.openconcerto.openoffice.ODPackage.RootElement;
import org.openconcerto.utils.cache.LRUMap;
import org.openconcerto.utils.cc.IFactory;
import org.openconcerto.xml.JDOMUtils;
import org.openconcerto.xml.Validator;
26,7 → 27,6
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
113,13 → 113,8
this.content = content;
this.version = version;
this.childCreator = new ChildCreator(this.content.getRootElement(), ELEMS_ORDER.get(this.getVersion()));
this.styleNamesLast = new LinkedHashMap<String, Integer>(4, 0.75f, true) {
@Override
protected boolean removeEldestEntry(java.util.Map.Entry<String, Integer> eldest) {
return this.size() > 15;
this.styleNamesLast = new LRUMap<>(15, 4);
}
};
}
 
public ODXMLDocument(Document content) {
this(content, XMLFormatVersion.get(content.getRootElement()));
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODSingleXMLDocument.java
14,6 → 14,11
package org.openconcerto.openoffice;
 
import static org.openconcerto.openoffice.ODPackage.RootElement.CONTENT;
import static org.openconcerto.xml.Step.createAttributeStep;
import static org.openconcerto.xml.Step.createAttributeStepFromQualifiedName;
import static org.openconcerto.xml.Step.createElementStep;
import static org.openconcerto.xml.Step.createElementStepFromQualifiedName;
 
import org.openconcerto.openoffice.ODPackage.RootElement;
import org.openconcerto.openoffice.style.data.DataStyle;
import org.openconcerto.utils.Base64;
28,6 → 33,7
 
import java.awt.Point;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
46,7 → 52,6
import java.util.Map.Entry;
import java.util.Set;
 
import org.apache.commons.collections.Transformer;
import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.DocType;
1042,12 → 1047,8
*/
protected final void detachDuplicate(Element elem) throws JDOMException {
final String singularName = elem.getName().substring(0, elem.getName().length() - 1);
final List thisNames = getXPath("./text:" + singularName + "s/text:" + singularName + "/@text:name").selectNodes(getChild("body"));
org.apache.commons.collections.CollectionUtils.transform(thisNames, new Transformer() {
public Object transform(Object obj) {
return ((Attribute) obj).getValue();
}
});
final SimpleXMLPath<Attribute> simplePath = SimpleXMLPath.create(createElementStep(singularName + "s", "text"), createElementStep(singularName, "text"), createAttributeStep("name", "text"));
final List<String> thisNames = simplePath.selectValues(getChild("body"));
 
final Iterator iter = elem.getChildren().iterator();
while (iter.hasNext()) {
1202,24 → 1203,19
}
 
private List<String> mergeUnique(ODXMLDocument doc, String topElem, String elemToMerge, String attrFQName, ElementTransformer addTransf) throws JDOMException {
final Element other = doc.getChild(topElem);
if (other == null)
return Collections.emptyList();
List<String> added = new ArrayList<String>();
Element thisParent = this.getChild(topElem, true);
 
XPath xp = this.getXPath("./" + elemToMerge + "/@" + attrFQName);
final SimpleXMLPath<Attribute> simplePath = SimpleXMLPath.create(createElementStepFromQualifiedName(elemToMerge), createAttributeStepFromQualifiedName(attrFQName));
 
// les styles de ce document
List thisElemNames = xp.selectNodes(thisParent);
// on transforme la liste d'attributs en liste de String
org.apache.commons.collections.CollectionUtils.transform(thisElemNames, new Transformer() {
public Object transform(Object obj) {
return ((Attribute) obj).getValue();
}
});
final List<String> thisElemNames = simplePath.selectValues(thisParent);
 
// pour chaque style de l'autre document
Iterator otherElemNames = xp.selectNodes(doc.getChild(topElem)).iterator();
while (otherElemNames.hasNext()) {
Attribute attr = (Attribute) otherElemNames.next();
for (final Attribute attr : simplePath.selectNodes(other)) {
// on l'ajoute si non déjà dedans
if (!thisElemNames.contains(attr.getValue())) {
thisParent.addContent(addTransf.transform((Element) attr.getParent().clone()));
1409,7 → 1405,7
throw new IllegalStateException("Cannot convert to binary data element : " + hrefParent);
final Element binaryData = new Element("binary-data", getPackage().getVersion().getOFFICE());
 
binaryData.setText(Base64.encodeBytes(getPackage().getBinaryFile(href)));
binaryData.setText(Base64.encodeBytesBreakLines(getPackage().getBinaryFile(href)));
hrefParent.addContent(binaryData);
// If this element is present, an xlink:href attribute in its parent element
// shall be ignored. But LO doesn't respect that
1418,7 → 1414,11
}
 
final File f = this.getPackage().getContentType().addExt(fNoExt, true);
FileUtils.write(ODPackage.createOutputter().outputString(doc), f);
try (final FileOutputStream outs = new FileOutputStream(f)) {
// Use OutputStream parameter so that the encoding used for the Writer matches the
// XML declaration.
ODPackage.createOutputter().output(doc, outs);
}
return f;
}
 
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/BytesProducer.java
28,7 → 28,7
 
import org.jdom.Element;
 
abstract class BytesProducer {
public abstract class BytesProducer {
 
/**
* The data of an image to put in <code>frame</code>.
36,7 → 36,7
* @param frame the frame where this image will be put.
* @return the corresponding bytes.
*/
abstract byte[] getBytes(ODFrame<?> frame);
public abstract byte[] getBytes(ODFrame<?> frame);
 
/**
* The format of the data returned by {@link #getBytes(Element)}.
43,12 → 43,12
*
* @return the name of the format, <code>null</code> if unknown, eg "png".
*/
abstract String getFormat();
public abstract String getFormat();
 
// *** concrete subclasses
 
// a no-op Producer
static final class ByteArrayProducer extends BytesProducer {
static public final class ByteArrayProducer extends BytesProducer {
 
private final byte[] data;
private final boolean keepRatio;
104,7 → 104,7
}
 
// will generate a new png image (and can also keep ratio)
static final class ImageProducer extends BytesProducer {
static public final class ImageProducer extends BytesProducer {
 
private final Image img;
private final boolean keepRatio;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/CellStyle.java
132,10 → 132,11
super(pkg, tableColElem);
}
 
private final DataStyle getDataStyle(final Attribute name) {
final DataStyle getDataStyle(final Attribute name) {
return (DataStyle) Style.getReferencedStyle(getPackage(), name);
}
 
// see MutableCell#getDataStyle()
final DataStyle getDataStyle() {
return getDataStyle(this.getElement().getAttribute("data-style-name", this.getSTYLE()));
}
160,13 → 161,13
}
}
 
final List<?> styleMaps = res.getElement().getChildren("map", getSTYLE());
final List<Element> styleMaps = res.getMapChildren();
if (styleMaps.size() > 0) {
final Object converted = convertForCondition(returnCellValue, res);
// we can't compare() so don't try
if (converted != null) {
for (Object child : styleMaps) {
final Element styleMap = (Element) child;
for (Element child : styleMaps) {
final Element styleMap = child;
final Matcher matcher = conditionPatrn.matcher(styleMap.getAttributeValue("condition", getSTYLE()).trim());
if (!matcher.matches())
throw new IllegalStateException("Cannot parse " + JDOMUtils.output(styleMap));
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Lines.java
97,7 → 97,7
public Lines(final ODDocument doc, final String text) {
super();
this.doc = doc;
this.xml = OOXML.get(doc.getFormatVersion(), false);
this.xml = doc.getFormatVersion().getXML();
this.lines = new LinkedList<String>();
this.separators = new LinkedList<Sep>();
this.parse(text, isCalc());
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/MutableCell.java
13,9 → 13,14
package org.openconcerto.openoffice.spreadsheet;
 
import static org.openconcerto.utils.TimeUtils.SECONDS_PER_HOUR;
import static org.openconcerto.utils.TimeUtils.SECONDS_PER_MINUTE;
 
import org.openconcerto.openoffice.LengthUnit;
import org.openconcerto.openoffice.Log;
import org.openconcerto.openoffice.ODDocument;
import org.openconcerto.openoffice.ODFrame;
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.ODValueType;
import org.openconcerto.openoffice.StyleDesc;
import org.openconcerto.openoffice.XMLVersion;
29,6 → 34,8
import org.openconcerto.utils.TimeUtils.DurationNullsChanger;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.Tuple3;
import org.openconcerto.utils.cache.LRUMap;
import org.openconcerto.utils.cc.CachedTransformer;
 
import java.awt.Color;
import java.awt.Image;
35,8 → 42,10
import java.awt.Point;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Date;
59,10 → 68,40
*/
public class MutableCell<D extends ODDocument> extends Cell<D> {
 
static private final DateFormat TextPDateFormat = DateFormat.getDateInstance();
static private final DateFormat TextPTimeFormat = DateFormat.getTimeInstance();
static private final NumberFormat TextPMinuteSecondFormat = new DecimalFormat("00.###");
static private final CachedTransformer<Locale, DateFormat, RuntimeException> TextPDateFormat = new CachedTransformer<>(new LRUMap<>(20), (l) -> DateFormat.getDateInstance(DateFormat.DEFAULT, l),
false);
static private final CachedTransformer<Locale, DateFormat, RuntimeException> TextPTimeFormat = new CachedTransformer<>(new LRUMap<>(20), (l) -> DateFormat.getTimeInstance(DateFormat.DEFAULT, l),
false);
static private final CachedTransformer<Locale, NumberFormat, RuntimeException> TextPMinuteSecondFormat = new CachedTransformer<>(new LRUMap<>(20),
(l) -> new DecimalFormat("00.###", DecimalFormatSymbols.getInstance(l)), false);
static private final char TEXTP_SEP = ':';
 
// HH:mm:ss.SSS
static String textPDuration(final long hours, final int minutes, final BigDecimal secsAndNanos, final Locale locale) {
final StringBuilder res = new StringBuilder(16);
res.append(hours);
res.append(TEXTP_SEP);
res.append(TextPMinuteSecondFormat.get(locale).format(minutes));
res.append(TEXTP_SEP);
res.append(TextPMinuteSecondFormat.get(locale).format(secsAndNanos));
return res.toString();
}
 
static String textPDuration(final java.time.Duration d, final Locale locale) {
// -1H is treated as 23:00 in LO
if (d.isNegative())
throw new UnsupportedOperationException("Negative duration");
 
final long seconds = d.getSeconds();
// from Duration.toString()
final long hours = seconds / SECONDS_PER_HOUR;
final int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
final int secs = (int) (seconds % SECONDS_PER_MINUTE);
final BigDecimal secsAndNanos = BigDecimal.valueOf(secs).add(BigDecimal.valueOf(d.getNano()).movePointLeft(9));
 
return textPDuration(hours, minutes, secsAndNanos, locale);
}
 
static private boolean LO_MODE = true;
// no date part, all time part to zero
static private final DurationNullsChanger TIME_NULLS = new TimeUtils.DurationNullsBuilder(TimeUtils.EmptyFieldPolicy.SET_TO_ZERO).setToNull(TimeUtils.getDateFields()).build();
139,8 → 178,8
// Like LO, do not generate string-value
if (type != null && type != ODValueType.STRING) {
// LO cells don't support the full syntax of a duration (user meta fields do)
// instead it support only values without nYnMnD
if (type == ODValueType.TIME && getTimeValueMode()) {
// instead it support only values without nYnMnD (as does java.time.Duration)
if (type == ODValueType.TIME && getTimeValueMode() && !(val instanceof java.time.Duration)) {
final Duration d = val instanceof Duration ? (Duration) val : TimeUtils.timePartToDuration((Calendar) val);
val = TIME_NULLS.apply(getODDocument().getEpoch().normalizeToHours(d));
}
214,13 → 253,15
if (formatted.get0() != null) {
text = formatted.get0();
} else {
// either there were no format or formatting failed
// either there were no format, formatting failed or wasn't attempted because the data
// style cannot format vt
 
if (vt == ODValueType.FLOAT) {
text = getODDocument().getPackage().formatNumber((Number) obj, getDefaultStyle());
text = ODPackage.formatNumber((Number) obj, getDataLocale(), getDefaultStyle());
} else if (vt == ODValueType.PERCENTAGE) {
text = getODDocument().getPackage().formatPercent((Number) obj, getDefaultStyle());
text = ODPackage.formatPercent((Number) obj, getDataLocale(), getDefaultStyle());
} else if (vt == ODValueType.CURRENCY) {
text = getODDocument().getPackage().formatCurrency((Number) obj, getDefaultStyle());
text = ODPackage.formatCurrency((Number) obj, getDataLocale(), getDefaultStyle());
} else if (vt == ODValueType.DATE) {
final Date d;
if (obj instanceof Calendar) {
228,25 → 269,18
} else {
d = (Date) obj;
}
text = TextPDateFormat.format(d);
text = TextPDateFormat.get(getDataLocale()).format(d);
} else if (vt == ODValueType.TIME) {
if (obj instanceof Duration) {
final Duration normalized = getODDocument().getEpoch().normalizeToHours((Duration) obj);
text = "" + normalized.getHours() + ':' + TextPMinuteSecondFormat.format(normalized.getMinutes()) + ':' + TextPMinuteSecondFormat.format(TimeUtils.getSeconds(normalized));
text = textPDuration(normalized.getHours(), normalized.getMinutes(), TimeUtils.getSeconds(normalized), getDataLocale());
} else if (obj instanceof java.time.Duration) {
text = textPDuration((java.time.Duration) obj, getDataLocale());
} else {
text = TextPTimeFormat.format(((Calendar) obj).getTime());
text = TextPTimeFormat.get(getDataLocale()).format(((Calendar) obj).getTime());
}
} else if (vt == ODValueType.BOOLEAN) {
Locale l = null;
final CellStyle s = getStyle();
if (s != null) {
final DataStyle ds = s.getDataStyle();
if (ds != null)
l = ds.getLocale();
}
if (l == null)
l = getODDocument().getPackage().getLocale();
text = BooleanStyle.toString((Boolean) obj, l, lenient);
text = BooleanStyle.toString((Boolean) obj, getDataLocale(), lenient);
} else if (vt == ODValueType.STRING) {
text = obj.toString();
} else {
256,6 → 290,54
this.setValue(vt, obj, text);
}
 
/**
* The locale of the data style. NOTE this doesn't evaluate the map elements with the current
* cell value.
*
* @return the locale of the data style, or if none, the ODPackage locale.
*/
public final Locale getDataLocale() {
return this.getDataLocale(false);
}
 
public final Locale getDataLocale(final boolean local) {
Locale res = null;
final CellStyle s = getStyle();
if (s != null) {
final DataStyle ds = s.getDataStyle();
if (ds != null)
res = ds.getLocale(local);
}
if (local || res != null)
return res;
return getODDocument().getPackage().getLocale();
}
 
/**
* Set the locale for the data style. This is different from the locale of the
* {@link CellStyle#getTextProperties() text properties}. Like LibreOffice, this set the
* attributes of the main {@link DataStyle}, and all {@link #getDataStyle() mapped} ones.
*
* @param locale the new locale, <code>null</code> to remove attributes.
* @throws IllegalStateException if there's no {@link DataStyle}.
*/
public final void setDataLocale(final Locale locale) throws IllegalStateException {
final CellStyle s = getStyle();
if (s != null) {
final DataStyle ds = s.getDataStyle();
if (ds != null) {
ds.setLocale(locale);
// LO does this, and this avoids the need for mapped styles to have a reference to
// their parent.
for (final Element mapElem : ds.getMapChildren()) {
s.getDataStyle(mapElem.getAttribute("apply-style-name", mapElem.getNamespace())).setLocale(locale);
}
return;
}
}
throw new IllegalStateException("No data style for " + this);
}
 
// return null String if no data style exists, or if one exists but we couldn't use it
private Tuple3<String, ODValueType, Object> format(Object obj, ODValueType valueType, boolean onlyCast, boolean lenient) {
String res = null;
452,6 → 534,12
return this.getRow().getSheet().getTableCellPropertiesAt(this.getX(), this.getY());
}
 
public final ODFrame<D> addFrame(final Number x, final Number y, final Number w, final Number h, final LengthUnit unit) {
final Element elem = ODFrame.createEmpty(getNS(), x, y, w, h, unit);
this.getElement().addContent(elem);
return new ODFrame<>(getODDocument(), elem);
}
 
public void setImage(final File pic) throws IOException {
this.setImage(pic, false);
}
467,20 → 555,11
private void setImage(final String name, final BytesProducer data) {
final Namespace draw = this.getNS().getNS("draw");
final Element frame = this.getElement().getChild("frame", draw);
final Element imageElem = frame == null ? null : frame.getChild("image", draw);
 
if (imageElem != null) {
final Attribute refAttr = imageElem.getAttribute("href", this.getNS().getNS("xlink"));
this.getODDocument().getPackage().putFile(refAttr.getValue(), null);
 
if (data == null)
frame.detach();
else {
refAttr.setValue("Pictures/" + name + (data.getFormat() != null ? "." + data.getFormat() : ""));
this.getODDocument().getPackage().putFile(refAttr.getValue(), data.getBytes(new ODFrame<D>(getODDocument(), frame)));
}
if (frame != null) {
new ODFrame<>(getODDocument(), frame).setImage(name, data, false);
} else if (data != null)
throw new IllegalStateException("this cell doesn't contain an image: " + this);
throw new IllegalStateException("this cell doesn't contain a frame: " + this);
}
 
public final void setBackgroundColor(final Color color) {
/trunk/OpenConcerto/src/org/openconcerto/openoffice/Grep.java
72,6 → 72,10
this.pattern = Pattern.compile(pattern);
}
 
public final Pattern getPattern() {
return this.pattern;
}
 
public final void grep(final File dir) {
FileUtils.walk(dir, new IClosure<File>() {
@Override
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/ReportGeneration.java
39,13 → 39,14
import java.util.Map.Entry;
import java.util.Stack;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeoutException;
 
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.filter.Filter;
 
import net.jcip.annotations.GuardedBy;
import ognl.Ognl;
import ognl.OgnlException;
import ognl.OgnlRuntime;
87,9 → 88,11
// Inheritable to allow generators to spawn threads
private final InheritableThreadLocal<ReportPart> currentParts;
private final InheritableThreadLocal<DocumentGenerator> currentGenerator;
@GuardedBy("this")
private Throwable interruptCause;
// tous les générateurs s'exécuter dans ce groupe
private final ThreadGroup thg;
@GuardedBy("this")
private List<Thread> thg;
private final List<PropertyChangeListener> taskListeners;
private final PropertyChangeListener taskListener;
private Map<String, Object> commonData;
109,11 → 112,7
this.currentParts = new InheritableThreadLocal<ReportPart>();
this.currentGenerator = new InheritableThreadLocal<DocumentGenerator>();
this.interruptCause = null;
this.thg = new ThreadGroup("Generateurs") {
public void uncaughtException(Thread t, Throwable e) {
ReportGeneration.this.interrupt(e);
}
};
this.thg = null;
 
this.taskListeners = new ArrayList<PropertyChangeListener>();
this.taskListener = new PropertyChangeListener() {
198,6 → 197,7
public final Map<String, ODSingleXMLDocument> generateMulti() throws Throwable {
synchronized (this) {
this.interruptCause = null;
this.thg = new ArrayList<>();
}
 
Map<String, ODSingleXMLDocument> f = null;
206,17 → 206,34
return createDocument();
}
});
final Thread thr = new Thread(this.thg, future);
// Don't pass a ThreadGroup, since every thread created, including "cache timeout", JDBC
// threads will be in it. But these threads must out-live this generation.
final Thread thr = new Thread(null, future);
this.registerThread(thr);
thr.start();
try {
thr.join();
f = future.get();
} catch (Exception e) {
if (isInterruptedExn(e) || (e instanceof ExecutionException && isInterruptedExn(e.getCause())))
f = null;
else
assert f == null;
// If one thread was interrupted (or failed), interrupt the others
this.interrupt(e);
} finally {
// Make sure all threads are stopped and don't prevent this from being garbage
// collected.
final List<Thread> toJoin;
synchronized (this) {
toJoin = this.thg;
this.thg = null;
}
for (final Thread t : toJoin) {
// If no exception occurred, then should already be finished but if there was one in
// a thread, another thread might be stuck on some I/O for a while before it can
// process the interrupt.
t.join(4500);
if (t.isAlive())
throw new TimeoutException("Thread still not terminated : " + t);
}
}
 
final Map<String, ODSingleXMLDocument> res;
synchronized (this) {
236,14 → 253,20
return res;
}
 
public final synchronized void registerThread(final Thread thr) {
this.thg.add(thr);
}
 
protected final void interrupt(Throwable cause) {
synchronized (this) {
if (this.interruptCause == null) {
this.interruptCause = cause;
this.thg.interrupt();
for (final Thread thr : this.thg) {
thr.interrupt();
}
}
}
}
 
private Map<String, ODSingleXMLDocument> createDocument() throws IOException, OgnlException, InterruptedException {
// recompute common data for each run
276,6 → 299,7
if (part instanceof ForkReportPart) {
GenThread thread = new GenThread(part.getName(), ((ForkReportPart) part).getChildren());
forked.put(part.getName(), thread);
this.registerThread(thread);
thread.start();
} else if (part instanceof SubReportPart) {
final SubReportPart subReportPart = (SubReportPart) part;
/trunk/OpenConcerto/src/org/openconcerto/openoffice/generation/view/BaseGenerationRapport.java
59,9 → 59,12
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
 
import org.jdom.JDOMException;
 
import net.jcip.annotations.GuardedBy;
 
/**
* A panel to choose a ReportType, see the tasks of the generation, and optionnaly open the
* document. NOTE: you have to call {@link #enableGeneration(boolean)} before being able to
95,11 → 98,11
private JList<GenerationTask> tasksView;
private final JLabel status;
 
// le groupe dans lequel doivent être toutes les thread de la génération
private final ThreadGroup thg;
@GuardedBy("EDT")
private SwingWorker<Void, Void> generationWorker;
 
public BaseGenerationRapport() throws JDOMException, IOException {
this.thg = new ThreadGroup(this + " thread group");
this.generationWorker = null;
this.status = new JLabel();
this.setStatus("Inactif");
}
234,7 → 237,8
*/
public final void interrupt() {
// pas de threads active, quand pas génération
this.thg.interrupt();
if (this.generationWorker != null)
this.generationWorker.cancel(true);
}
 
class GenerateAction implements ActionListener {
246,21 → 250,22
enableGeneration(false);
final FileAction sel = (FileAction) BaseGenerationRapport.this.fileActionCombo.getSelectedItem();
// "génération..."
new Thread(BaseGenerationRapport.this.thg, new Runnable() {
BaseGenerationRapport.this.generationWorker = new SwingWorker<Void, Void>() {
@Override
public void run() {
protected Void doInBackground() throws Exception {
generate(sel);
return null;
}
 
@Override
protected void done() {
// toujours le faire, même si interrompu
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
enableGeneration(true);
}
});
};
BaseGenerationRapport.this.generationWorker.execute();
}
}).start();
}
}
 
protected final void enableGeneration(final boolean b) {
this.fileActionCombo.setEnabled(b);
267,7 → 272,6
this.genererButton.setEnabled(b);
}
 
// doit s'exécuter dans this.thg
protected final void generate(final FileAction sel) {
final ReportType type = (ReportType) this.typeRapportComboSelection.getSelectedItem();
final R rg = this.createGeneration(type);
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODFrame.java
13,6 → 13,7
package org.openconcerto.openoffice;
 
import org.openconcerto.openoffice.spreadsheet.BytesProducer;
import org.openconcerto.openoffice.text.TextNode;
 
import java.math.BigDecimal;
28,6 → 29,20
*/
public class ODFrame<D extends ODDocument> extends ImmutableDocStyledNode<GraphicStyle, D> {
 
static public Element createEmpty(XMLVersion ns, final Number w, final Number h, final LengthUnit unit) {
return createEmpty(ns, BigDecimal.ZERO, BigDecimal.ZERO, w, h, unit);
}
 
static public Element createEmpty(XMLVersion ns, final Number x, final Number y, final Number w, final Number h, final LengthUnit unit) {
final Namespace svgNS = ns.getNS("svg");
final Element res = new Element("frame", ns.getNS("draw"));
res.setAttribute("x", unit.format(x), svgNS);
res.setAttribute("y", unit.format(y), svgNS);
res.setAttribute("width", unit.format(w), svgNS);
res.setAttribute("height", unit.format(h), svgNS);
return res;
}
 
/**
* Parse SVG and OD length.
*
120,4 → 135,36
public final LengthUnit getUnit() {
return LengthUnit.MM;
}
 
public final void addImage(final String name, final BytesProducer data) {
final Element imageElem = new Element("image", getElement().getNamespace("draw"));
this.getElement().addContent(imageElem);
this.putImage(imageElem, name, data);
}
 
private final void putImage(final Element imageElem, final String name, final BytesProducer data) {
final String imgPath = "Pictures/" + name + (data.getFormat() != null ? "." + data.getFormat() : "");
imageElem.setAttribute("href", imgPath, this.getODDocument().getVersion().getNS("xlink"));
this.getODDocument().getPackage().putFile(imgPath, data.getBytes(this));
}
 
public final void setImage(final String name, final BytesProducer data, final boolean allowAdd) {
final Element imageElem = this.getElement().getChild("image", getElement().getNamespace("draw"));
if (imageElem != null) {
final String oldPath = imageElem.getAttributeValue("href", this.getODDocument().getVersion().getNS("xlink"));
this.getODDocument().getPackage().putFile(oldPath, null);
imageElem.removeChild("binary-data", this.getODDocument().getVersion().getOFFICE());
 
if (data == null) {
imageElem.detach();
} else {
this.putImage(imageElem, name, data);
}
} else if (data != null) {
if (allowAdd)
this.addImage(name, data);
else
throw new IllegalStateException("No image in " + this);
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/NumberStyle.java
44,6 → 44,8
res = (Number) value;
} else if (value instanceof Boolean) {
res = ((Boolean) value).booleanValue() ? 1 : 0;
} else if (value instanceof java.time.Duration) {
res = ODEpoch.getDays((java.time.Duration) value);
} else if ((value instanceof Duration || value instanceof Date || value instanceof Calendar)) {
if (value instanceof Duration) {
res = epoch.getDays((Duration) value);
84,11 → 86,11
if (elem.getName().equals("text")) {
sb.append(elem.getText());
} else if (elem.getName().equals("number") || elem.getName().equals("scientific-number")) {
sb.append(formatNumberOrScientificNumber(elem, n, defaultStyle));
sb.append(formatNumberOrScientificNumber(elem, n, defaultStyle, lenient));
} else if (elem.getName().equals("fraction")) {
// TODO fractions
reportError("Fractions not supported", lenient);
sb.append(getPackage().formatNumber(n, defaultStyle));
sb.append(ODPackage.formatNumber(n, getLocale(), defaultStyle));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DataStyle.java
17,6 → 17,7
import org.openconcerto.openoffice.ODEpoch;
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.ODValueType;
import org.openconcerto.openoffice.OOUtils;
import org.openconcerto.openoffice.Style;
import org.openconcerto.openoffice.StyleDesc;
import org.openconcerto.openoffice.StyleProperties;
51,18 → 52,29
/**
* The default number of decimal digits if neither defined in the style nor in default-style.
*/
public static final int DEFAULT_DECIMAL_PLACES = Integer.parseInt(System.getProperty("openDocument.defaultDecimalPlaces", "15"));
public static final int DEFAULT_DECIMAL_PLACES;
private static final Pattern QUOTE_PATRN = Pattern.compile("'", Pattern.LITERAL);
private static final Pattern EXP_PATTERN = Pattern.compile("E(\\d+)$");
 
public static int getDecimalPlaces(final CellStyle defaultStyle) {
if (defaultStyle != null) {
return defaultStyle.getTableCellProperties(null).getDecimalPlaces();
final int res = defaultStyle.getTableCellProperties(null).getDecimalPlaces();
// Ignore invalid value
return res < 0 ? DEFAULT_DECIMAL_PLACES : res;
} else {
return DEFAULT_DECIMAL_PLACES;
}
}
 
protected static final int parsePositive(final String attr, final boolean lenient) {
final int res = Integer.parseInt(attr);
if (res < 0) {
reportError("Negative value for " + attr, lenient);
return 0;
}
return res;
}
 
public static void addStringLiteral(final StringBuilder formatSB, final String s) {
formatSB.append('\'');
formatSB.append(QUOTE_PATRN.matcher(s).replaceAll("''"));
83,6 → 95,12
l.add(BooleanStyle.class);
DATA_STYLES = Collections.unmodifiableSet(l);
assert DATA_STYLES_DESCS.length == DATA_STYLES.size() : "Discrepancy between classes and descs";
 
final String decPlacesProp = System.getProperty("openDocument.defaultDecimalPlaces");
final int decPlacesParsed = decPlacesProp == null ? -1 : Integer.parseInt(decPlacesProp);
// Ignore invalid value
DEFAULT_DECIMAL_PLACES = decPlacesParsed < 0 ? 15 : decPlacesParsed;
assert DEFAULT_DECIMAL_PLACES >= 0;
}
 
public static abstract class DataStyleDesc<S extends DataStyle> extends StyleDesc<S> {
182,19 → 200,32
}
 
public final Locale getLocale() {
return this.getLocale(this.getElement());
return this.getLocale(false);
}
 
protected final Locale getLocale(final Element elem) {
final Locale res = DateStyle.getElementLocale(elem);
return res != null ? res : this.getPackage().getLocale();
public final Locale getLocale(final boolean local) {
return this.getLocale(this.getElement(), local);
}
 
protected final String formatNumberOrScientificNumber(final Element elem, final Number n, CellStyle defaultStyle) {
return this.formatNumberOrScientificNumber(elem, n, 1, defaultStyle);
protected final Locale getLocale(final Element elem, final boolean local) {
final Locale res = OOUtils.getElementLocale(elem);
return local || res != null ? res : this.getPackage().getLocale();
}
 
protected final String formatNumberOrScientificNumber(final Element elem, final Number n, final int multiplier, CellStyle defaultStyle) {
public final void setLocale(final Locale l) {
OOUtils.setElementLocale(this.getElement(), this.getElement().getNamespace(), l);
}
 
@SuppressWarnings("unchecked")
public final List<Element> getMapChildren() {
return this.getElement().getChildren("map", getSTYLE());
}
 
protected final String formatNumberOrScientificNumber(final Element elem, final Number n, CellStyle defaultStyle, final boolean lenient) {
return this.formatNumberOrScientificNumber(elem, n, 1, defaultStyle, lenient);
}
 
protected final String formatNumberOrScientificNumber(final Element elem, final Number n, final int multiplier, CellStyle defaultStyle, final boolean lenient) {
final Namespace numberNS = this.getElement().getNamespace();
final StringBuilder numberSB = new StringBuilder();
 
221,9 → 252,10
}
 
// e.g. if it's "--", 12,3 is displayed "12,3" and 12 is displayed "12,--"
final String decReplacement = elem.getAttributeValue("decimal-replacement", numberNS);
// From v1.3 §19.356.2 decimal-replacement can be empty
final String decReplacement = elem.getAttributeValue("decimal-replacement", numberNS, "");
final boolean decSeparatorAlwaysShown;
if (decReplacement != null && !NumberUtils.hasFractionalPart(n)) {
if (!decReplacement.isEmpty() && !NumberUtils.hasFractionalPart(n)) {
decSeparatorAlwaysShown = true;
numberSB.append('.');
// escape quote in replacement
231,30 → 263,47
} else {
decSeparatorAlwaysShown = false;
// see 19.343.2
final Attribute decPlacesAttr = elem.getAttribute("decimal-places", numberNS);
final int decPlaces;
final char decChar;
if (decPlacesAttr != null) {
decChar = '0';
decPlaces = Integer.parseInt(decPlacesAttr.getValue());
final String decPlacesAttr = elem.getAttributeValue("decimal-places", numberNS, "");
final String minDecPlacesAttr = elem.getAttributeValue("min-decimal-places", numberNS, "");
final int forcedPlaces, nonZeroPlaces;
if (!decPlacesAttr.isEmpty()) {
final int decPlaces = parsePositive(decPlacesAttr, lenient);
if (minDecPlacesAttr.isEmpty()) {
forcedPlaces = decPlaces;
nonZeroPlaces = 0;
} else {
forcedPlaces = parsePositive(minDecPlacesAttr, lenient);
if (forcedPlaces > decPlaces) {
DataStyle.reportError("min-decimal-places greater than decimal-places : " + minDecPlacesAttr + " > " + decPlacesAttr, lenient);
nonZeroPlaces = 0;
} else {
nonZeroPlaces = decPlaces - forcedPlaces;
}
}
} else {
// default style specifies the maximum
decChar = '#';
decPlaces = getDecimalPlaces(defaultStyle);
forcedPlaces = 0;
nonZeroPlaces = getDecimalPlaces(defaultStyle);
}
 
if (decPlaces > 0) {
if (forcedPlaces + nonZeroPlaces > 0) {
numberSB.append('.');
for (int i = 0; i < decPlaces; i++)
numberSB.append(decChar);
for (int i = 0; i < forcedPlaces; i++)
numberSB.append('0');
for (int i = 0; i < nonZeroPlaces; i++)
numberSB.append('#');
}
}
 
final Attribute minExpAttr = elem.getAttribute("min-exponent-digits", numberNS);
final boolean forcedExpSign;
if (minExpAttr != null) {
forcedExpSign = Boolean.parseBoolean(elem.getAttributeValue("forced-exponent-sign", numberNS, "true"));
numberSB.append('E');
for (int i = 0; i < Integer.parseInt(minExpAttr.getValue()); i++)
numberSB.append('0');
} else {
forcedExpSign = false;
}
 
final DecimalFormatSymbols symbols = new DecimalFormatSymbols(this.getLocale());
267,8 → 316,8
decFormat.setGroupingSize(DEFAULT_GROUPING_SIZE);
decFormat.setDecimalSeparatorAlwaysShown(decSeparatorAlwaysShown);
String res = decFormat.format(NumberUtils.divide(n, factor));
// java only puts the minus sign, OO also puts the plus sign
if (minExpAttr != null) {
// There's no way to force the plus sign in DecimalFormat
if (forcedExpSign) {
final Matcher m = EXP_PATTERN.matcher(res);
if (m.find())
res = res.substring(0, m.start()) + "E+" + m.group(1);
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/CurrencyStyle.java
58,12 → 58,12
// ATTN OpenOffice Fix (it generates <text>-</text>, so we have to use the
// absolute value)
final int multiplier = n.doubleValue() > 0 ? 1 : -1;
sb.append(formatNumberOrScientificNumber(elem, n, multiplier, defaultStyle));
sb.append(formatNumberOrScientificNumber(elem, n, multiplier, defaultStyle, lenient));
} else if (elem.getName().equals("currency-symbol")) {
if (elem.getTextTrim().length() > 0) {
sb.append(elem.getText());
} else {
sb.append(new DecimalFormatSymbols(this.getLocale(elem)).getCurrencySymbol());
sb.append(new DecimalFormatSymbols(this.getLocale(elem, false)).getCurrencySymbol());
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DateStyle.java
54,18 → 54,6
return !"long".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
}
 
static final Locale getElementLocale(final Element elem) {
final Locale res;
final String country = elem.getAttributeValue("country", elem.getNamespace());
final String lang = elem.getAttributeValue("language", elem.getNamespace());
if (lang != null) {
res = new Locale(lang, country == null ? "" : country);
} else {
res = null;
}
return res;
}
 
private static final Calendar getCalendar(final Element elem, Calendar defaultCal) {
final Calendar res;
final String cal = elem.getAttributeValue("calendar", elem.getNamespace());
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/OD 1.3.fods
New file
0,0 → 1,51
<?xml version="1.0" encoding="UTF-8"?>
 
<office:document xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ooo="http://openoffice.org/2004/office" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
<office:styles>
<style:default-style style:family="table-cell">
<style:paragraph-properties style:tab-stop-distance="1.25cm"/>
<style:text-properties style:font-name="Liberation Sans" fo:language="fr" fo:country="FR" style:font-name-asian="Noto Sans CJK SC" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="FreeSans" style:language-complex="hi" style:country-complex="IN"/>
</style:default-style>
<number:number-style style:name="N108">
<number:number number:decimal-places="2" number:min-decimal-places="1" number:min-integer-digits="1" number:decimal-replacement="" number:grouping="true"/>
</number:number-style>
<style:style style:name="Default" style:family="table-cell"/>
</office:styles>
<office:automatic-styles>
<style:style style:name="co1" style:family="table-column">
<style:table-column-properties fo:break-before="auto" style:column-width="2.258cm"/>
</style:style>
<style:style style:name="ro1" style:family="table-row">
<style:table-row-properties style:row-height="0.452cm" fo:break-before="auto" style:use-optimal-row-height="true"/>
</style:style>
<style:style style:name="ta1" style:family="table" style:master-page-name="Default">
<style:table-properties table:display="true" style:writing-mode="lr-tb"/>
</style:style>
<style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N108"/>
</office:automatic-styles>
<office:body>
<office:spreadsheet>
<table:calculation-settings table:automatic-find-labels="false" table:use-regular-expressions="false" table:use-wildcards="true"/>
<table:table table:name="Feuille1" table:style-name="ta1">
<table:table-column table:style-name="co1" table:default-cell-style-name="ce1"/>
<table:table-row table:style-name="ro1">
<table:table-cell office:value-type="float" office:value="1.236" calcext:value-type="float">
<text:p>1,24</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell office:value-type="float" office:value="1" calcext:value-type="float">
<text:p>1,0</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name="ro1" table:number-rows-repeated="1048571">
<table:table-cell/>
</table:table-row>
<table:table-row table:style-name="ro1">
<table:table-cell/>
</table:table-row>
</table:table>
<table:named-expressions/>
</office:spreadsheet>
</office:body>
</office:document>
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/TimeStyle.java
65,7 → 65,13
 
@Override
public String format(Object o, CellStyle defaultStyle, boolean lenient) {
final Duration d = o instanceof Calendar ? TimeUtils.timePartToDuration((Calendar) o) : (Duration) o;
final Duration d;
if (o instanceof Calendar)
d = TimeUtils.timePartToDuration((Calendar) o);
else if (o instanceof java.time.Duration)
d = TimeUtils.getTypeFactory().newDurationDayTime(o.toString());
else
d = (Duration) o;
final Namespace numberNS = this.getElement().getNamespace();
final StringBuilder sb = new StringBuilder();
 
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/PercentStyle.java
54,7 → 54,7
if (elem.getName().equals("text")) {
sb.append(elem.getText());
} else if (elem.getName().equals("number")) {
sb.append(formatNumberOrScientificNumber(elem, n, 100, defaultStyle));
sb.append(formatNumberOrScientificNumber(elem, n, 100, defaultStyle, lenient));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODEpoch.java
14,6 → 14,8
package org.openconcerto.openoffice;
 
import org.openconcerto.utils.TimeUtils;
import org.openconcerto.utils.cache.LRUMap;
import org.openconcerto.utils.cc.CachedTransformer;
 
import java.math.BigDecimal;
import java.math.BigInteger;
22,8 → 24,6
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;
 
import javax.xml.datatype.DatatypeConstants;
43,12 → 43,7
static private final DateFormat DATE_FORMAT;
static private final ODEpoch DEFAULT_EPOCH;
@GuardedBy("cache")
static private final Map<String, ODEpoch> cache = new LinkedHashMap<String, ODEpoch>(4, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, ODEpoch> eldest) {
return this.size() > 16;
}
};
static private final CachedTransformer<String, ODEpoch, ParseException> cache = new CachedTransformer<>(new LRUMap<>(16, 4), ODEpoch::new);
 
static {
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
70,16 → 65,19
return DEFAULT_EPOCH;
} else {
synchronized (cache) {
ODEpoch res = cache.get(date);
if (res == null) {
res = new ODEpoch(date);
cache.put(date, res);
return cache.transformChecked(date);
}
return res;
}
}
 
public static final BigDecimal getDays(final java.time.Duration d) {
return getDays(d.toMillis());
}
 
public static final BigDecimal getDays(final long millis) {
return BigDecimal.valueOf(millis).divide(MS_PER_DAY, MathContext.DECIMAL128);
}
 
static private final Calendar parse(final String date) throws ParseException {
synchronized (DATE_FORMAT) {
final Calendar cal = (Calendar) DATE_FORMAT.getCalendar().clone();
139,7 → 137,7
// can't use Duration.normalizeWith() since it doesn't handle DST, i.e. going from winter to
// summer at midnight will miss a day
final long diff = TimeUtils.normalizeLocalTime(cal) - this.epochUTC.getTimeInMillis();
return BigDecimal.valueOf(diff).divide(MS_PER_DAY, MathContext.DECIMAL128);
return getDays(diff);
}
 
public final Calendar getDate(final BigDecimal days) {
/trunk/OpenConcerto/src/org/openconcerto/ui/DefaultGridBagConstraints.java
13,11 → 13,11
package org.openconcerto.ui;
 
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
 
import javax.swing.JComponent;
import javax.swing.UIManager;
 
public class DefaultGridBagConstraints extends GridBagConstraints {
43,11 → 43,11
return new Insets(2, 3, 2, 2);
}
 
public static void lockMinimumSize(JComponent c) {
public static void lockMinimumSize(Component c) {
c.setMinimumSize(new Dimension(c.getPreferredSize()));
}
 
public static void lockMaximumSize(JComponent c) {
public static void lockMaximumSize(Component c) {
c.setMaximumSize(new Dimension(c.getPreferredSize()));
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/WrapLayout.java
New file
0,0 → 1,184
/*
* 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;
 
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
 
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
 
/**
* FlowLayout subclass that fully supports wrapping of components.
*/
public class WrapLayout extends FlowLayout {
 
/**
* Constructs a new <code>WrapLayout</code> with a left alignment and a default 5-unit
* horizontal and vertical gap.
*/
public WrapLayout() {
super(FlowLayout.LEFT);
}
 
/**
* Constructs a new <code>FlowLayout</code> with the specified alignment and a default 5-unit
* horizontal and vertical gap. The value of the alignment argument must be one of
* <code>WrapLayout</code>, <code>WrapLayout</code>, or <code>WrapLayout</code>.
*
* @param align the alignment value
*/
public WrapLayout(int align) {
super(align);
}
 
/**
* Creates a new flow layout manager with the indicated alignment and the indicated horizontal
* and vertical gaps.
* <p>
* The value of the alignment argument must be one of <code>WrapLayout</code>,
* <code>WrapLayout</code>, or <code>WrapLayout</code>.
*
* @param align the alignment value
* @param hgap the horizontal gap between components
* @param vgap the vertical gap between components
*/
public WrapLayout(int align, int hgap, int vgap) {
super(align, hgap, vgap);
}
 
/**
* Returns the preferred dimensions for this layout given the <i>visible</i> components in the
* specified target container.
*
* @param target the component which needs to be laid out
* @return the preferred dimensions to lay out the subcomponents of the specified container
*/
@Override
public Dimension preferredLayoutSize(Container target) {
return layoutSize(target, true);
}
 
/**
* Returns the minimum dimensions needed to layout the <i>visible</i> components contained in
* the specified target container.
*
* @param target the component which needs to be laid out
* @return the minimum dimensions to lay out the subcomponents of the specified container
*/
@Override
public Dimension minimumLayoutSize(Container target) {
Dimension minimum = layoutSize(target, false);
minimum.width -= (getHgap() + 1);
return minimum;
}
 
/**
* Returns the minimum or preferred dimension needed to layout the target container.
*
* @param target target to get layout size for
* @param preferred should preferred size be calculated
* @return the dimension to layout the target container
*/
private Dimension layoutSize(Container target, boolean preferred) {
synchronized (target.getTreeLock()) {
// Each row must fit with the width allocated to the containter.
// When the container width = 0, the preferred width of the container
// has not yet been calculated so lets ask for the maximum.
 
Container container = target;
 
while (container.getSize().width == 0 && container.getParent() != null) {
container = container.getParent();
}
 
int targetWidth = container.getSize().width;
if (targetWidth == 0) {
targetWidth = Integer.MAX_VALUE;
}
int hgap = getHgap();
int vgap = getVgap();
Insets insets = target.getInsets();
int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
int maxWidth = targetWidth - horizontalInsetsAndGap;
 
// Fit components into the allowed width
 
Dimension dim = new Dimension(0, 0);
int rowWidth = 0;
int rowHeight = 0;
final int nmembers = target.getComponentCount();
for (int i = 0; i < nmembers; i++) {
Component m = target.getComponent(i);
 
if (m.isVisible()) {
Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
// Can't add the component to current row. Start a new row.
if (rowWidth + d.width > maxWidth) {
addRow(dim, rowWidth, rowHeight);
rowWidth = 0;
rowHeight = 0;
}
 
// Add a horizontal gap for all components after the first
if (rowWidth != 0) {
rowWidth += hgap;
}
 
rowWidth += d.width;
rowHeight = Math.max(rowHeight, d.height);
}
}
 
addRow(dim, rowWidth, rowHeight);
 
dim.width += horizontalInsetsAndGap;
dim.height += insets.top + insets.bottom + vgap * 2;
 
// When using a scroll pane or the DecoratedLookAndFeel we need to
// make sure the preferred size is less than the size of the
// target containter so shrinking the container size works
// correctly. Removing the horizontal gap is an easy way to do this.
 
final Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
if (scrollPane != null && target.isValid()) {
dim.width -= (hgap + 1);
}
return dim;
}
}
 
/*
* A new row has been completed. Use the dimensions of this row to update the preferred size for
* the container.
*
* @param dim update the width and height when appropriate
*
* @param rowWidth the width of the row to add
*
* @param rowHeight the height of the row to add
*/
private void addRow(Dimension dim, int rowWidth, int rowHeight) {
dim.width = Math.max(dim.width, rowWidth);
 
if (dim.height > 0) {
dim.height += getVgap();
}
 
dim.height += rowHeight;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITable.java
517,7 → 517,7
if (this.hasRow()) {
final int size = this.getRowsCount();
if (jsonContext.size() != size) {
System.err.println("LightUITable.setValueFromContext() - Incorrect line count in JSON");
throw new IllegalStateException("LightUITable.setValueFromContext() - Incorrect line count in JSON, row count:" + size + " context:" + jsonContext.size() + " (" + value + ")");
} else {
 
for (int i = 0; i < size; i++) {
/trunk/OpenConcerto/src/org/openconcerto/ui/FormLayouter.java
146,9 → 146,9
}
 
/**
* Ajout un composant sur une ligne Si comp est null, un titre est créé.
* Ajout un composant sur une ligne.
*
* @param desc le label du champ.
* @param desc le label du champ, <code>null</code> if <code>comp</<code> should use its area.
* @param comp le composant graphique d'edition.
* @param w la largeur, entre 1 et la largeur de ce layout, ou 0 pour toute la largeur.
* @return the created label.
158,11 → 158,20
public JLabel add(String desc, Component comp, int w) {
w = this.checkArgs(comp, w);
 
final int realWidth = this.getRealFieldWidth(w);
int realWidth = this.getRealFieldWidth(w);
final JLabel lab;
final int fieldX;
if (desc == null) {
lab = null;
fieldX = this.getLabelX();
realWidth += this.getFieldX() - fieldX;
} else {
lab = new JLabel(desc);
// Guillaume : right alignment like the Mac
final JLabel lab = new JLabel(desc);
this.co.add(lab, this.constraints.xy(this.getLabelX(), this.getY(), CellConstraints.RIGHT, this.getRowAlign()));
this.co.add(comp, this.constraints.xyw(this.getFieldX(), this.getY(), realWidth, CellConstraints.DEFAULT, this.getRowAlign()));
fieldX = this.getFieldX();
}
this.co.add(comp, this.constraints.xyw(fieldX, this.getY(), realWidth, CellConstraints.DEFAULT, this.getRowAlign()));
this.x += w;
return lab;
}
/trunk/OpenConcerto/src/org/openconcerto/ui/group/Group.java
21,6 → 21,11
import java.util.Comparator;
import java.util.List;
 
/**
* Allow to customize UI layout.
*
* @author guillaume
*/
public class Group extends Item {
 
public static Group copy(final Group g, final Group newParent) {
63,11 → 68,33
}
}
 
public final Group toImmutable() {
return this.toImmutable(true);
}
 
public final Group toImmutable(final boolean onlyDesc) {
if (this.isFrozen())
return this;
 
final Group res;
if (onlyDesc) {
res = copy(this, null);
res.freeze();
} else {
final List<String> p = this.getAbsolutePath();
final Group copy = copy(this.getRoot(), null);
copy.freeze();
res = copy.followPath(p, false);
}
assert res.isFrozen();
return res;
}
 
@Override
public synchronized void freeze() {
super.freeze();
protected synchronized void _freeze() {
super._freeze();
for (final Tuple2<Item, Integer> child : this.list) {
child.get0().freeze();
child.get0()._freeze();
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/group/Item.java
15,6 → 15,10
 
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
 
import net.jcip.annotations.GuardedBy;
 
66,7 → 70,13
throw new IllegalStateException("Frozen cannot " + op);
}
 
public synchronized void freeze() {
public synchronized final void freeze() {
if (this.getParent() != null)
throw new IllegalStateException("Can only freeze from the root down");
this._freeze();
}
 
protected synchronized void _freeze() {
this.frozen = true;
}
 
113,14 → 123,26
this.localHint = new LayoutHints(localHint == null ? LayoutHints.DEFAULT_FIELD_HINTS : localHint);
}
 
public final Group getRoot() {
public final void applyUntilRoot(final Consumer<Item> cons) {
Item current = this;
while (current.getParent() != null) {
while (current != null) {
cons.accept(current);
current = current.getParent();
}
return current instanceof Group ? (Group) current : null;
}
 
public final List<String> getAbsolutePath() {
final LinkedList<String> res = new LinkedList<>();
this.applyUntilRoot((item) -> res.addFirst(item.getId()));
return res;
}
 
public final Group getRoot() {
final AtomicReference<Item> current = new AtomicReference<>();
this.applyUntilRoot((item) -> current.set(item));
return current.get() instanceof Group ? (Group) current.get() : null;
}
 
protected void printTree(final StringBuilder builder, final int localOrder, final int level) {
for (int i = 0; i < level - 1; i++) {
builder.append(" ");
/trunk/OpenConcerto/src/org/openconcerto/ui/group/LayoutHints.java
17,7 → 17,7
 
@Immutable
public class LayoutHints {
private final boolean visible;
private boolean visible;
private final boolean largeWidth;
private final boolean largeHeight;
private boolean foldable = false;
39,6 → 39,7
public static final LayoutHints DEFAULT_GROUP_HINTS = new LayoutHints(true, false, false, false, true, true);
public static final LayoutHints DEFAULT_SEPARATED_GROUP_HINTS = new LayoutHints(true, false, true, true, true, true);
public static final LayoutHints DEFAULT_NOLABEL_SEPARATED_GROUP_HINTS = new LayoutHints(true, false, false, true, true, true);
public static final LayoutHints DEFAULT_SEPARATED_VERY_LARGE_HINTS = new LayoutHints(false, false, true, true, true, false, false, true);
 
public LayoutHints(boolean largeWidth, boolean largeHeight, boolean showLabel) {
this(largeWidth, largeHeight, showLabel, false, false, false);
157,9 → 158,13
}
 
public boolean isVisible() {
return visible;
return this.visible;
}
 
public void setVisible(boolean b) {
this.visible = b;
}
 
@Override
public int hashCode() {
final int prime = 31;
187,4 → 192,5
return this.fillHeight == other.fillHeight && this.fillWidth == other.fillWidth && this.largeHeight == other.largeHeight && this.largeWidth == other.largeWidth
&& this.separated == other.separated && this.showLabel == other.showLabel && this.split == other.split && this.visible == other.visible;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/component/InteractionMode.java
76,6 → 76,10
return comp;
}
 
public final InteractionMode and(InteractionMode m) {
return from(this.isEnabled() && m.isEnabled(), this.isEditable() && m.isEditable());
}
 
/**
* Try to infer the mode of the passed component. This method has special cases for known
* component (.e.g {@link JTextComponent}) otherwise generic components are presumed to not have
/trunk/OpenConcerto/src/org/openconcerto/ui/WindowUtils.java
New file
0,0 → 1,68
/*
* 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;
 
import org.openconcerto.utils.Platform;
 
import java.awt.Toolkit;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.function.Supplier;
 
public class WindowUtils {
private WindowUtils() {
}
 
/**
* Allow to set WM_CLASS for X11 windows.
*
* @param nameSupplier which name to use.
* @param pidSuffix <code>true</code> if the name should be suffixed by the PID of the VM. That
* way, there is one group of windows per launch.
*/
static public void setWMClass(final Supplier<String> nameSupplier, final boolean pidSuffix) {
// Set WM_CLASS to have a meaningful name and avoid grouping together all windows of all VMs
final Class<?> xtoolkit = Toolkit.getDefaultToolkit().getClass();
// https://bugs.openjdk.java.net/browse/JDK-6528430
// need system property to override default WM_CLASS
// #183739 - provide proper app name on Linux
// org/netbeans/core/windows/view/ui/MainWindow.java
if (xtoolkit.getName().equals("sun.awt.X11.XToolkit")) {
try {
final Field awtAppClassName = xtoolkit.getDeclaredField("awtAppClassName");
awtAppClassName.setAccessible(true);
 
String pid = null;
// use PID to have one group of windows per launch
if (pidSuffix) {
try {
final Platform p = Platform.getInstance();
if (p.supportsPID())
pid = p.getPID();
} catch (Exception e1) {
e1.printStackTrace();
}
}
final String suppliedName = Objects.requireNonNull(nameSupplier.get(), "Null name").trim();
if (suppliedName.isEmpty())
throw new IllegalArgumentException("Empty name");
final String name = suppliedName + (pid == null ? "" : " [" + pid + "]");
 
awtAppClassName.set(null, name);
} catch (Exception x) {
x.printStackTrace();
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/statements/Include.java
36,7 → 36,10
 
private static final String PREFIX = "[IOD";
 
// Cache whole file to avoid disk access since there can be a lot of sections in a single file
private final ICache<File, ODSingleXMLDocument, File> cache;
// Cache the Parsed of just one section in the above file
// { filePath#sectionName -> Parsed }
private final ICache<String, Parsed<ODSingleXMLDocument>, File> parsedCache;
 
public Include() {
45,6 → 48,13
this.parsedCache = new ICache<String, Parsed<ODSingleXMLDocument>, File>(180);
}
 
@Override
public void destroy() {
this.cache.getSupp().die();
this.parsedCache.getSupp().die();
super.destroy();
}
 
public boolean matches(Element elem) {
if (!elem.getQualifiedName().equals("text:a"))
return false;
129,9 → 139,10
private Parsed<ODSingleXMLDocument> createParsed(final File ref, final String sectionName, final Parsed<?> parsed) throws JDOMException, IOException, TemplateException {
final ODSingleXMLDocument docToAdd = getXMLDocument(ref).clone();
 
// replace the body with just sectionName
final XPath sectionXP = docToAdd.getXPath("//text:section[@text:name = '" + sectionName + "']");
final Element section = (Element) sectionXP.selectSingleNode(docToAdd.getDocument());
// ajouter la section car souvent des if s'y réfèrent.
// ajouter la section elle-même car souvent des if s'y réfèrent.
docToAdd.getBody().setContent(section.detach());
 
final Material<ODSingleXMLDocument> from = Material.from(docToAdd);
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/statements/Statement.java
72,6 → 72,9
*/
public abstract void execute(Processor<?> processor, Element elem, DataModel model) throws TemplateException;
 
public void destroy() {
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + this.getName();
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/Template.java
37,7 → 37,7
* template.createDocument(vars, new FileOutputStream(&quot;document.sxw&quot;));
* </pre>
*/
public class Template {
public class Template implements AutoCloseable {
 
protected final Parsed<ODPackage> contentTemplate;
 
62,6 → 62,11
this.contentTemplate = new Parsed<ODPackage>(Material.from(contents));
}
 
@Override
public void close() throws Exception {
this.contentTemplate.destroy();
}
 
/**
* Generates a document merging template and data.
*
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/TemplateGenerator.java
80,7 → 80,9
try {
this.transform(pkg.toSingle());
// MAYBE fireStatusChange with the number of tag done out of the total
return new Template(pkg).createDocument(new OGNLDataModel(data));
try (final Template template = new Template(pkg)) {
return template.createDocument(new OGNLDataModel(data));
}
} catch (Exception exn) {
throw ExceptionUtils.createExn(IOException.class, "generation error in " + this, exn);
}
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/engine/Parsed.java
114,4 → 114,9
}
return new Processor<E>(this, data).process().getWhole();
}
 
public void destroy() {
for (final Statement st : this.statements.values())
st.destroy();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ITextArticleWithCompletion.java
16,6 → 16,8
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
357,13 → 359,42
 
MultipleSQLSelectExecutor mult = new MultipleSQLSelectExecutor(this.tableArticle.getDBSystemRoot(), listSel);
 
List<List<SQLRow>> resultList = mult.execute();
List<List<? extends SQLRowAccessor>> resultList = new ArrayList<>();
resultList.addAll(mult.execute());
 
for (List<SQLRow> list : resultList) {
// Recherche dans les codes fournisseurs
SQLTable tableCodeArt = this.tableArticle.getDBRoot().getTable("CODE_FOURNISSEUR");
SQLRowValues rowValsCodeF = new SQLRowValues(tableCodeArt);
rowValsCodeF.putNulls("CODE");
rowValsCodeF.putRowValues("ID_ARTICLE").putNulls(this.tableArticle.getFieldsName());
 
for (SQLRow sqlRow : list) {
final String codeText = aText;
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowValsCodeF);
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect input) {
 
Where wCodeFContains = new Where(tableCodeArt.getField("CODE"), "LIKE", "%" + codeText + "%");
input.setWhere(wCodeFContains);
input.setLimit(SQL_RESULT_LIMIT);
return input;
}
});
List<SQLRowValues> resultCodeF = fetcher.fetch();
resultList.add(2, resultCodeF);
 
for (List<? extends SQLRowAccessor> list : resultList) {
 
for (SQLRowAccessor sqlRow : list) {
 
StringBuffer buf = new StringBuffer();
if (sqlRow.getTable().getName().equals("CODE_FOURNISSEUR")) {
SQLRowAccessor rArt = sqlRow.getForeign("ID_ARTICLE");
buf.append(sqlRow.getString("CODE") + " -- ");
buf.append(rArt.getString("CODE") + " -- ");
buf.append(rArt.getString("NOM"));
result.add(new IComboSelectionItem(rArt, buf.toString()));
} else {
if (sqlRow.getString("CODE_BARRE") != null && sqlRow.getString("CODE_BARRE").trim().length() > 0) {
buf.append(sqlRow.getString("CODE_BARRE") + " -- ");
}
372,6 → 403,7
result.add(new IComboSelectionItem(sqlRow, buf.toString()));
}
}
}
 
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/request/RSTransformer.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
56,6 → 56,7
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.request.SQLCache;
import org.openconcerto.sql.request.SQLFieldTranslator;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.ui.light.CustomRowEditor;
import org.openconcerto.sql.ui.light.GroupToLightUIConvertor;
127,6 → 128,7
import java.util.SortedMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.function.Supplier;
 
import javax.swing.JComponent;
import javax.swing.JOptionPane;
202,7 → 204,7
@GuardedBy("this")
private SQLCache<SQLRow, Object> modelCache;
 
private final Map<String, JComponent> additionalFields;
private final Map<String, Supplier<? extends JComponent>> additionalFields;
private final List<SQLTableModelColumn> additionalListCols;
@GuardedBy("this")
private List<String> mdPath;
242,7 → 244,7
this.modelCache = null;
 
// the components should always be in the same order
this.additionalFields = new LinkedHashMap<String, JComponent>();
this.additionalFields = new LinkedHashMap<>();
this.additionalListCols = new ArrayList<SQLTableModelColumn>();
this.mdPath = Collections.emptyList();
}
3014,19 → 3016,23
* @return <code>true</code> if no view existed.
*/
public final boolean putAdditionalField(final String field) {
return this.putAdditionalField(field, (JComponent) null);
return this.putAdditionalField(field, null);
}
 
public final boolean putAdditionalField(final String field, final JTextComponent comp) {
return this.putAdditionalField(field, (JComponent) comp);
public final boolean putAdditionalTextField(final String field, final Supplier<? extends JTextComponent> comp) {
return this.putAdditionalField(field, comp);
}
 
public final boolean putAdditionalField(final String field, final SQLTextCombo comp) {
return this.putAdditionalField(field, (JComponent) comp);
public final boolean putAdditionalTextCombo(final String field, final Supplier<? extends SQLTextCombo> comp) {
return this.putAdditionalField(field, comp);
}
 
public final boolean putAdditionalCombo(final String field, final Supplier<? extends SQLRequestComboBox> comp) {
return this.putAdditionalField(field, comp);
}
 
// private as only a few JComponent are OK
private final boolean putAdditionalField(final String field, final JComponent comp) {
private final boolean putAdditionalField(final String field, final Supplier<? extends JComponent> comp) {
if (this.additionalFields.containsKey(field)) {
return false;
} else {
3035,7 → 3041,7
}
}
 
public final Map<String, JComponent> getAdditionalFields() {
public final Map<String, Supplier<? extends JComponent>> getAdditionalFields() {
return Collections.unmodifiableMap(this.additionalFields);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
84,6 → 84,7
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Supplier;
 
import javax.swing.JCheckBox;
import javax.swing.JComponent;
429,11 → 430,11
|| (this.getMode() != Mode.INSERTION && CollectionUtils.containsAny(this.getElement().getInsertOnlyFields(), fieldsNames));
}
 
@Override
protected final void inited() {
super.inited();
if (!(this instanceof GroupSQLComponent)) {
 
for (final Entry<String, JComponent> e : this.getElement().getAdditionalFields().entrySet()) {
for (final Entry<String, Supplier<? extends JComponent>> e : this.getElement().getAdditionalFields().entrySet()) {
final SpecParser spec;
// FIXME Required à spécifier directement depuis le module
if (this.requiredNames != null && this.requiredNames.contains(e.getKey())) {
441,14 → 442,16
} else {
spec = new SpecParser(null, true);
}
final JComponent comp = e.getValue();
if (comp == null)
final Supplier<? extends JComponent> comp = e.getValue();
if (comp == null) {
// infer component
this.addViewJComponent(e.getKey(), spec);
else
this.addView(comp, e.getKey(), spec);
} else {
// create component
this.addView(comp.get(), e.getKey(), spec);
}
}
}
// assure that added views are consistent with our editable status
this.updateChildrenEditable();
for (final SQLRowItemView v : this.getRequest().getViews()) {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java
195,15 → 195,17
}
 
/**
* Search for an SQLElement whose class is <code>clazz</code>.
* Search for an SQLElement which is an {@link Class#isInstance(Object) instance of}
* <code>clazz</code>.
*
* @param <S> type of SQLElement
* @param clazz the class.
* @return the corresponding SQLElement, or <code>null</code> if none can be found.
* @throws IllegalArgumentException if there's more than one match.
* @see #getElementsOfClass(Class, boolean)
*/
public final <S extends SQLElement> S getElement(Class<S> clazz) {
return this.getElementOfClass(clazz, false);
return this.getElementOfClass(clazz, true);
}
 
public final <S extends SQLElement> S getElementOfClass(Class<S> clazz, final boolean allowSubclass) {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java
168,8 → 168,7
}
if (this.hasAdditionnalFields) {
if ((currentGroup == this.group && this.additionnalFieldsGroup == null) || (currentGroup == this.additionnalFieldsGroup)) {
final Map<String, JComponent> additionalFields = this.getElement().getAdditionalFields();
for (String field : additionalFields.keySet()) {
for (String field : this.getElement().getAdditionalFields().keySet()) {
Item item = new Item(field, new LayoutHints(false, false, true, false, true, false));
int fill = c.fill;
double weightx = c.weightx;
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowMode.java
14,11 → 14,7
package org.openconcerto.sql.model;
 
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.IPredicate;
 
import java.util.Collection;
 
/**
* Allow to specify which rows we're interested in.
*
92,14 → 88,4
public SQLRow filter(SQLRow r) {
return this.check(r) ? r : null;
}
 
public void filter(Collection<SQLRow> rows) {
CollectionUtils.filter(rows, new IPredicate<SQLRow>() {
@Override
public boolean evaluateChecked(SQLRow r) {
return check(r);
}
});
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/ResultSetFullnameHelper.java
19,9 → 19,6
import java.util.HashMap;
import java.util.Map;
 
import org.apache.commons.collections.Factory;
import org.apache.commons.collections.map.LazyMap;
 
/**
* A class to help find fields by their fullname in resultset. Some jdbc drivers only accept the
* short name of fields, eg you execute "select B.DESIGNATION from BATIMENT B" but you can only
33,15 → 30,11
public final class ResultSetFullnameHelper {
private final ResultSet delegate;
private ResultSetMetaData rsMD;
private final Map tablesMap;
private final Map<String, Map<String, Integer>> tablesMap;
 
public ResultSetFullnameHelper(ResultSet rs) {
this.delegate = rs;
this.tablesMap = LazyMap.decorate(new HashMap(), new Factory() {
public Object create() {
return new HashMap();
}
});
this.tablesMap = new HashMap<>();
this.rsMD = null;
}
 
74,12 → 67,12
* @throws SQLException if an error occur while retrieving metadata.
*/
public final int getIndex(String tableName, String fieldName) throws SQLException {
final Map m = (Map) this.tablesMap.get(tableName);
final Map<String, Integer> m = this.tablesMap.computeIfAbsent(tableName, (k) -> new HashMap<>());
if (!m.containsKey(fieldName)) {
final int index = this.searchIndex(tableName, fieldName);
m.put(fieldName, index < 1 ? null : new Integer(index));
}
final Integer val = (Integer) m.get(fieldName);
final Integer val = m.get(fieldName);
return val == null ? -1 : val.intValue();
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLInjector.java
169,6 → 169,24
rowVals.put(field.getName(), value);
}
 
private String cleanRef(String value) {
List<String> l = StringUtils.fastSplit(value, ',');
Set<String> s = new HashSet<>(l);
String nom = "";
if (s.size() > 1) {
Set<String> refAdded = new HashSet<>();
for (String string : s) {
if (string.trim().length() > 0 && !refAdded.contains(string.trim())) {
nom += string + ",";
refAdded.add(string.trim());
}
}
} else if (s.size() == 1) {
nom = s.iterator().next();
}
return nom;
}
 
protected void transfertReference(SQLRowAccessor srcRow, SQLRowValues rowVals, final SQLTable tableElementDestination, String refField, String from, String to) {
 
String label = rowVals.getString(to);
176,7 → 194,7
 
if (prefs.getBoolean("TransfertRef", true) || !to.equals("NOM")) {
if (label != null && label.trim().length() > 0) {
rowVals.put(to, label + ", " + srcRow.getString(from));
rowVals.put(to, cleanRef(label + ", " + srcRow.getString(from)));
} else {
rowVals.put(to, srcRow.getString(from));
}
198,17 → 216,7
String label = rowVals.getString("NOM");
if (label != null && label.trim().length() > 0) {
final String value = label + ", " + srcRow.getString("NUMERO");
List<String> l = StringUtils.fastSplit(value, ',');
Set<String> s = new HashSet<>(l);
String nom = "";
if (s.size() > 1) {
for (String string : s) {
nom += string + ",";
}
} else if (s.size() == 1) {
nom = s.iterator().next();
}
rowVals.put("NOM", nom);
rowVals.put("NOM", cleanRef(value));
} else {
rowVals.put("NOM", srcRow.getString("NUMERO"));
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntax.java
673,8 → 673,8
/**
* Get the default clause.
*
* @param def the default, e.g. "0".
* @return the default clause, e.g. "DEFAULT 0".
* @param def the default, e.g. "0" or <code>null</code>.
* @return the default clause, e.g. " DEFAULT 0" or " ".
*/
public final String getDefaultClause(final String def) {
if (def == null)
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxMS.java
23,7 → 23,6
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.ProcessStreams;
import org.openconcerto.utils.ProcessStreams.Action;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.StringUtils;
import org.openconcerto.utils.Tuple2;
395,8 → 394,7
pb.command().add("-E");
}
 
final Process p = pb.start();
ProcessStreams.handle(p, Action.REDIRECT);
final Process p = ProcessStreams.redirect(pb).start();
try {
final int returnCode = p.waitFor();
if (returnCode != 0)
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLResultSet.java
13,6 → 13,8
package org.openconcerto.sql.model;
 
import org.openconcerto.utils.cc.CachedTransformer;
 
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
36,9 → 38,6
import java.util.HashMap;
import java.util.Map;
 
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.LazyMap;
 
/**
* A resultSet that wraps onto another one, caching name to index translation, and using a
* ResultSetFullnameHelper.
120,23 → 119,14
 
private final ResultSet delegate;
private final ResultSetFullnameHelper helper;
private final Map indexes;
private final CachedTransformer<String, Integer, SQLException> indexes;
private int rowProcessedCount;
 
public SQLResultSet(ResultSet delegate) {
this.delegate = delegate;
this.helper = new ResultSetFullnameHelper(this);
this.indexes = LazyMap.decorate(new HashMap(), new Transformer() {
public Object transform(Object input) {
final String colName = (String) input;
try {
return new Integer(doFindColumn(colName));
} catch (SQLException e) {
return e;
this.indexes = new CachedTransformer<>(new HashMap<>(), this::doFindColumn);
}
}
});
}
 
private ResultSet getDelegate() {
return this.delegate;
171,17 → 161,12
}
 
public int findColumn(String columnName) throws SQLException {
final Object res = this.indexes.get(columnName);
if (res instanceof SQLException)
throw (SQLException) res;
else {
final int index = ((Number) res).intValue();
final int index = this.indexes.get(columnName).intValue();
if (index < 1)
throw new SQLException(columnName + " not found");
else
return index;
}
}
 
private int doFindColumn(String columnName) throws SQLException {
try {
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/correct/FixSharedPrivate.java
25,6 → 25,7
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.model.graph.Path;
34,6 → 35,7
import org.openconcerto.utils.cc.ITransformer;
 
import java.sql.SQLException;
import java.util.EnumSet;
import java.util.List;
 
/**
70,6 → 72,14
}
 
@Override
protected EnumSet<SQLSystem> getCompatibleSystems() {
// When executing deleteReq :
// - if PRIVATE_REFS is temporary : "Can't reopen table"
// - if not : "You can't specify target table 'PRIVATE_REFS' for update in FROM clause"
return EnumSet.complementOf(EnumSet.of(SQLSystem.MYSQL));
}
 
@Override
protected void changeImpl(final SQLTable t) throws SQLException {
getStream().print(t);
final SQLElement elem = this.getDir().getElement(t);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableModel.java
153,6 → 153,10
this.list.add(e);
}
 
public void setValidationField(SQLField validationField) {
this.validationField = validationField;
}
 
public synchronized int getColumnCount() {
return this.nbColumn;
}
/trunk/OpenConcerto/src/org/openconcerto/utils/DropperQueue.java
15,12 → 15,12
 
import org.openconcerto.utils.cc.IClosure;
 
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
223,13 → 223,11
}
 
public final void eachItemDo(final IClosure<T> c) {
this.itemsDo(new IClosure<Collection<T>>() {
@Override
public void executeChecked(Collection<T> items) {
this.itemsDo((items) -> {
for (final T t : items) {
c.executeChecked(t);
}
}
return null;
});
}
 
240,11 → 238,19
* @param c what to do with our queue.
*/
public final void itemsDo(IClosure<? super Deque<T>> c) {
this.itemsDo((q) -> {
c.executeChecked(q);
return null;
});
}
 
public final <R> R itemsDo(Function<? super Deque<T>, R> c) {
this.itemsLock.lock();
try {
c.executeChecked(this.items);
final R res = c.apply(this.items);
if (!this.items.isEmpty())
this.notEmpty.signal();
return res;
} finally {
this.itemsLock.unlock();
}
/trunk/OpenConcerto/src/org/openconcerto/utils/sync/SimpleSyncClient.java
204,8 → 204,12
}
 
public DirContent getDir(final String path) throws Exception {
if (path == null) {
throw new IllegalArgumentException("null path");
}
 
final HttpsURLConnection con = openConnection("/getDir");
final Response res = checkResponseCode(send(con, NetUtils.urlEncode("rp", path, "type", "json")));
final Response res = checkResponseCode(send(con, NetUtils.urlEncode("rp", path, "type", "json"), false));
if (!res.isSuccess())
return null;
final JSONParser p = new JSONParser(JSONParser.MODE_STRICTEST);
222,8 → 226,14
static private final Set<Integer> GETFILE_OK_CODES = CollectionUtils.createSet(200, 404);
 
public Response getFile(final String path, final String fileName, final FileConsumer fileConsumer) throws IOException {
if (path == null) {
throw new IllegalArgumentException("null path");
}
if (fileName == null) {
throw new IllegalArgumentException("null fileName");
}
final HttpsURLConnection con = openConnection("/get");
send(con, NetUtils.urlEncode("rn", fileName, "rp", path));
send(con, NetUtils.urlEncode("rn", fileName, "rp", path), false);
final Response res = checkResponseCode(con, GETFILE_OK_CODES);
if (res.getCode() == 404) {
fileConsumer.accept(null, null);
240,6 → 250,13
// throwsException() and always throws. The return value is true if the file existed and was
// saved.
public boolean saveFile(final String path, final String fileName, final Path localFile) throws IOException {
if (path == null) {
throw new IllegalArgumentException("null path");
}
if (fileName == null) {
throw new IllegalArgumentException("null fileName");
}
 
final AtomicBoolean missing = new AtomicBoolean(true);
final Response res = this.getFile(path, fileName, (fileAttrs, in) -> {
missing.set(fileAttrs == null);
253,8 → 270,14
}
 
public Response deleteFile(final String path, final String fileName) throws IOException {
if (path == null) {
throw new IllegalArgumentException("null path");
}
if (fileName == null) {
throw new IllegalArgumentException("null fileName");
}
final HttpsURLConnection con = openConnection("/delete");
return checkResponseCode(send(con, NetUtils.urlEncode("rn", fileName, "rp", path)));
return checkResponseCode(send(con, NetUtils.urlEncode("rn", fileName, "rp", path), false));
}
 
public final Response renameFile(final String path, final String fileName, final String newFileName) throws IOException {
262,8 → 285,20
}
 
public final Response renameFile(final String path, final String fileName, final String newPath, final String newFileName) throws IOException {
if (path == null) {
throw new IllegalArgumentException("null path");
}
if (fileName == null) {
throw new IllegalArgumentException("null fileName");
}
if (newPath == null) {
throw new IllegalArgumentException("null newPath");
}
if (newFileName == null) {
throw new IllegalArgumentException("null newFileName");
}
final HttpsURLConnection con = openConnection("/rename");
return checkResponseCode(send(con, NetUtils.urlEncode("rn", fileName, "rp", path, "newPath", newPath, "newName", newFileName)));
return checkResponseCode(send(con, NetUtils.urlEncode("rn", fileName, "rp", path, "newPath", newPath, "newName", newFileName), false));
}
 
public Response sendFile(String path, File localFile) throws IOException {
271,6 → 306,10
}
 
public Response sendFile(String path, File localFile, final boolean overwrite) throws IOException {
if (path == null) {
throw new IllegalArgumentException("null path");
}
 
final long size = localFile.length();
if (size >= Integer.MAX_VALUE)
throw new OutOfMemoryError("Required array size too large : " + size);
/trunk/OpenConcerto/src/org/openconcerto/utils/i18n/translation/messages_th.properties
New file
0,0 → 1,4
true_key=\u0E08\u0E23\u0E34\u0E07
false_key=\u0E40\u0E17\u0E47\u0E08
yes_key=\u0E43\u0E0A\u0E48
no_key=\u0E44\u0E21\u0E48
/trunk/OpenConcerto/src/org/openconcerto/utils/PEMImporter.java
58,6 → 58,12
* @param the password to set to protect the private key
*/
public static KeyStore createKeyStore(File privateKeyPem, File certificatePem, final String password) throws IOException, GeneralSecurityException {
if (!privateKeyPem.exists()) {
throw new IllegalArgumentException("private key file missing : " + privateKeyPem.getAbsolutePath());
}
if (!certificatePem.exists()) {
throw new IllegalArgumentException("certificate file missing : " + certificatePem.getAbsolutePath());
}
final X509Certificate[] cert = createCertificates(certificatePem);
final KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ITransformerWrapper.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IFactoryWrapper.java
File deleted
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/BiConsumerExn.java
New file
0,0 → 1,19
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.cc;
 
@FunctionalInterface
public interface BiConsumerExn<T, U, X extends Exception> {
public void accept(T input, U input2) throws X;
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/CachedTransformer.java
New file
0,0 → 1,60
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.cc;
 
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cache.LRUMap;
import org.openconcerto.utils.cache.Memoizer;
 
import java.util.Map;
 
import net.jcip.annotations.NotThreadSafe;
 
/**
* Allow to cache the result of a function.
*
* @author sylvain
*
* @param <K> the type of the function parameter.
* @param <V> the type of the function result.
* @param <X> the type of the function exception.
* @see LRUMap to limit cache size.
* @see Memoizer for a thread-safe class with concurrent creation of entries.
*/
@NotThreadSafe
public class CachedTransformer<K, V, X extends Exception> implements ITransformerExn<K, V, X> {
 
private final Map<K, V> map;
private final boolean allowNullValue;
private final ITransformerExn<K, V, X> function;
 
public CachedTransformer(final Map<K, V> map, final ITransformerExn<K, V, X> function) {
this(map, function, false);
}
 
public CachedTransformer(final Map<K, V> map, final ITransformerExn<K, V, X> function, final boolean allowNullValue) {
this.map = map;
this.function = function;
this.allowNullValue = allowNullValue;
}
 
@Override
public final V transformChecked(K key) throws X {
return this.get(key);
}
 
public V get(K key) throws X {
return CollectionUtils.computeIfAbsent(this.map, key, this.function, this.allowNullValue);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/Factory.java
13,20 → 13,15
package org.openconcerto.utils.cc;
 
import org.apache.commons.collections.FactoryUtils;
public abstract class Factory<E> implements IFactory<E>, ITransformer<Object, E> {
 
public abstract class Factory<E> implements IFactory<E>, ITransformer<Object, E>, org.apache.commons.collections.Factory {
 
public static final <N> IFactory<N> constantFactory(final N constantToReturn) {
return new IFactoryWrapper<N>(FactoryUtils.constantFactory(constantToReturn));
if (constantToReturn == null)
return ConstantFactory.nullFactory();
return new ConstantFactory<N>(constantToReturn);
}
 
@Override
public final Object create() {
return this.createChecked();
}
 
@Override
public final E transformChecked(Object input) {
return this.createChecked();
};
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ExnTransformer.java
15,8 → 15,6
 
import org.openconcerto.utils.ExceptionUtils;
 
import org.apache.commons.collections.Transformer;
 
/**
* Transformer able to throw an exception.
*
26,13 → 24,8
* @param <T> return type
* @param <X> exception type
*/
public abstract class ExnTransformer<E, T, X extends Exception> implements Transformer, ITransformerExn<E, T, X> {
public abstract class ExnTransformer<E, T, X extends Exception> implements ITransformerExn<E, T, X> {
 
@SuppressWarnings("unchecked")
public final Object transform(Object input) {
return this.transformCheckedWithExn((E) input, IllegalStateException.class);
}
 
/**
* Execute this transformer, making sure that an exception of type <code>exnClass</code> is
* thrown.
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ExnClosure.java
23,10 → 23,6
*/
public abstract class ExnClosure<E, X extends Exception> extends ExnTransformer<E, Object, X> implements IExnClosure<E, X> {
 
public final void execute(Object input) {
this.transform(input);
}
 
/**
* Execute this closure, making sure that an exception of type <code>exnClass</code> is thrown.
*
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/Transformer.java
15,7 → 15,7
 
import java.util.Map;
 
public abstract class Transformer<E, T> implements ITransformer<E, T>, IClosure<E>, org.apache.commons.collections.Transformer {
public abstract class Transformer<E, T> implements ITransformer<E, T>, IClosure<E> {
 
private static final ITransformer<Object, Object> nopTransf = new ITransformer<Object, Object>() {
@Override
30,7 → 30,7
}
 
public static final <K, V> ITransformer<K, V> fromMap(final Map<K, V> map) {
return new Transformer<K, V>() {
return new ITransformer<K, V>() {
@Override
public V transformChecked(K input) {
return map.get(input);
38,13 → 38,10
};
}
 
@SuppressWarnings("unchecked")
public final Object transform(Object input) {
return this.transformChecked((E) input);
}
 
@Override
public abstract T transformChecked(E input);
 
@Override
public final void executeChecked(E input) {
this.transformChecked(input);
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IPredicate.java
13,10 → 13,8
package org.openconcerto.utils.cc;
 
import org.apache.commons.collections.Predicate;
public abstract class IPredicate<E> {
 
public abstract class IPredicate<E> implements Predicate {
 
private static final IPredicate<Object> truePred = new IPredicate<Object>() {
@Override
public boolean evaluateChecked(Object input) {
51,12 → 49,6
return (IPredicate<N>) NotNullPred;
}
 
@SuppressWarnings("unchecked")
@Override
public boolean evaluate(Object object) {
return this.evaluateChecked((E) object);
}
 
public abstract boolean evaluateChecked(E input);
 
public final <F extends E> IPredicate<F> cast() {
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/Closure.java
13,7 → 13,7
package org.openconcerto.utils.cc;
 
public abstract class Closure<E> implements IClosure<E>, ITransformer<E, Object>, org.apache.commons.collections.Closure {
public abstract class Closure<E> implements IClosure<E>, ITransformer<E, Object> {
 
private static final IClosure<Object> nop = new IClosure<Object>() {
@Override
26,16 → 26,12
return (IClosure<N>) nop;
}
 
@SuppressWarnings("unchecked")
public final void execute(Object input) {
this.executeChecked((E) input);
}
 
@Override
public abstract void executeChecked(E input);
 
@Override
public final Object transformChecked(E input) {
this.executeChecked(input);
return null;
};
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ReentrantEventDispatcher.java
New file
0,0 → 1,84
/*
* 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;
 
import org.openconcerto.utils.cc.BiConsumerExn;
 
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Objects;
 
/**
* Allow to maintain the dispatching of events in order when a listener itself fires an event.
*
* @author sylvain
*
* @param <L> listener type.
* @param <E> event type.
* @param <X> exception type.
*/
public final class ReentrantEventDispatcher<L, E, X extends Exception> {
 
private final class DispatchingState extends Tuple3<Iterator<L>, BiConsumerExn<L, E, X>, E> {
public DispatchingState(final Iterator<L> iter, BiConsumerExn<L, E, X> callback, final E evt) {
super(Objects.requireNonNull(iter, "Missing iterator"), Objects.requireNonNull(callback, "Missing callback"), evt);
}
}
 
private final ThreadLocal<LinkedList<DispatchingState>> events = new ThreadLocal<LinkedList<DispatchingState>>() {
@Override
protected LinkedList<DispatchingState> initialValue() {
return new LinkedList<>();
}
};
 
private final BiConsumerExn<L, E, X> callback;
 
public ReentrantEventDispatcher() {
this(null);
}
 
public ReentrantEventDispatcher(final BiConsumerExn<L, E, X> callback) {
super();
this.callback = callback;
}
 
public final void fire(final Iterator<L> iter, final E evt) throws X {
this.fire(iter, this.callback, evt);
}
 
public final void fire(final Iterator<L> iter, final BiConsumerExn<L, E, X> callback, final E evt) throws X {
this.fire(new DispatchingState(iter, callback, evt));
}
 
private final void fire(final DispatchingState newTuple) throws X {
final LinkedList<DispatchingState> linkedList = this.events.get();
// add new event
linkedList.addLast(newTuple);
// process all pending events
DispatchingState currentTuple;
while ((currentTuple = linkedList.peekFirst()) != null) {
final Iterator<L> currentIter = currentTuple.get0();
final BiConsumerExn<L, E, X> currentCallback = currentTuple.get1();
final E currentEvt = currentTuple.get2();
while (currentIter.hasNext()) {
final L l = currentIter.next();
currentCallback.accept(l, currentEvt);
}
// not removeFirst() since the item might have been already removed
linkedList.pollFirst();
}
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/SleepingQueue.java
33,6 → 33,7
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.logging.Level;
 
import net.jcip.annotations.GuardedBy;
418,6 → 419,10
this.tasksQueue.itemsDo(c);
}
 
public final <R> R tasksDo(Function<? super Deque<RunnableFuture<?>>, R> c) {
return this.tasksQueue.itemsDo(c);
}
 
private void cancelCheck(RunnableFuture<?> t) {
if (t != null)
synchronized (this) {
/trunk/OpenConcerto/src/org/openconcerto/utils/StreamUtils.java
49,6 → 49,8
* @param in the source.
* @param out the destination.
* @throws IOException if an error occurs while reading or writing.
* @throws RTInterruptedException if interrupted (can only be checked between
* {@link InputStream#read(byte[], int, int)} reads).
*/
public static void copy(InputStream in, OutputStream out) throws IOException {
// TODO use in.transferTo(out) in Java 9
69,6 → 71,8
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;
if (Thread.interrupted())
throw new RTInterruptedException();
final int count = in.read(buffer, 0, (int) toRead);
if (count <= 0) {
// like Files.copy(InputStream, OutputStream), stop if reading 0 bytes
77,6 → 81,10
break;
}
totalCount += count;
// if interrupted while blocked in read(), then we don't want to use the data read after
// the interrupt.
if (Thread.interrupted())
throw new RTInterruptedException();
out.write(buffer, 0, count);
}
// < if end of stream
/trunk/OpenConcerto/src/org/openconcerto/utils/TimeUtils.java
25,6 → 25,7
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
 
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConstants;
32,13 → 33,20
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.Immutable;
 
public class TimeUtils {
 
static public final int SECONDS_PER_MINUTE = 60;
static public final int MINUTE_PER_HOUR = 60;
static public final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTE_PER_HOUR;
 
@GuardedBy("TimeUtils.class")
static private DatatypeFactory typeFactory = null;
static private List<Field> FIELDS_LIST = Arrays.asList(DatatypeConstants.YEARS, DatatypeConstants.MONTHS, DatatypeConstants.DAYS, DatatypeConstants.HOURS, DatatypeConstants.MINUTES,
static private final List<Field> FIELDS_LIST = Arrays.asList(DatatypeConstants.YEARS, DatatypeConstants.MONTHS, DatatypeConstants.DAYS, DatatypeConstants.HOURS, DatatypeConstants.MINUTES,
DatatypeConstants.SECONDS);
static private List<Field> DATE_FIELDS, TIME_FIELDS;
static private final List<Field> DATE_FIELDS, TIME_FIELDS;
 
static {
final int dayIndex = FIELDS_LIST.indexOf(DatatypeConstants.DAYS);
72,7 → 80,7
return f == DatatypeConstants.SECONDS ? BigDecimal.class : BigInteger.class;
}
 
static public final DatatypeFactory getTypeFactory() {
static public synchronized final DatatypeFactory getTypeFactory() {
if (typeFactory == null)
try {
typeFactory = DatatypeFactory.newInstance();
398,4 → 406,22
final long day2 = cal.getTimeInMillis();
return day1 == day2;
}
 
static public final boolean isEqual(final long amount1, final TimeUnit unit1, final long amount2, final TimeUnit unit2) {
final long finerAmount, coarserAmount;
final TimeUnit finer, coarser;
// don't truncate
if (unit1.compareTo(unit2) < 0) {
finerAmount = amount1;
finer = unit1;
coarserAmount = amount2;
coarser = unit2;
} else {
finerAmount = amount2;
finer = unit2;
coarserAmount = amount1;
coarser = unit1;
}
return finerAmount == finer.convert(coarserAmount, coarser);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/Platform.java
14,6 → 14,7
package org.openconcerto.utils;
 
import static org.openconcerto.utils.DesktopEnvironment.cmdSubstitution;
 
import org.openconcerto.utils.cc.ITransformer;
 
import java.io.BufferedReader;
23,6 → 24,8
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
43,8 → 46,10
final OSFamily os = OSFamily.getInstance();
if (os == OSFamily.Windows) {
return CYGWIN;
} else if (os == OSFamily.FreeBSD || os == OSFamily.Mac) {
} else if (os == OSFamily.FreeBSD) {
return FREEBSD;
} else if (os == OSFamily.Mac) {
return MACOS;
} else {
return LINUX;
}
57,12 → 62,23
public abstract String getPath(final File f);
 
public final String getPID() throws IOException {
// TODO remove reflection and getPreJava9PID() once on java 11
try {
final Class<?> phClass = Class.forName("java.lang.ProcessHandle");
final Object ph = phClass.getMethod("current").invoke(null);
return ((Number) phClass.getMethod("pid").invoke(ph)).toString();
} catch (ClassNotFoundException e) {
// fall back
} catch (Exception e) {
throw new IOException("Couldn't get PID", e);
}
return getPreJava9PID();
}
 
protected String getPreJava9PID() throws IOException {
final Process p = this.eval("echo -n $PPID");
final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
try {
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
return reader.readLine();
} finally {
reader.close();
}
}
 
102,12 → 118,8
 
public final void append(File f1, File f2) throws IOException {
final String c = "cat '" + f1.getAbsolutePath() + "' >> '" + f2.getAbsolutePath() + "'";
try {
this.eval(c).waitFor();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
this.waitForSuccess(this.eval(c), "append");
}
}
 
public Process cp_l(File src, File dest) throws IOException {
return Runtime.getRuntime().exec(new String[] { "cp", "-prl", src.getAbsolutePath(), dest.getAbsolutePath() });
138,14 → 150,23
protected final PingResult ping(final String command, final int totalCount, int requiredCount) throws IOException {
if (requiredCount <= 0)
requiredCount = totalCount;
final List<String> countAndLastLine = StringUtils.splitIntoLines(cmdSubstitution(eval(command)));
// Keep errors out of cmdSubstitution() (e.g. "ping: sendto: Message too long" when
// setDontFragment(true))
final Process proc = evalPB(command).redirectErrorStream(false).start();
final String output = cmdSubstitution(proc);
try {
this.waitForSuccess(proc, "ping");
final List<String> countAndLastLine = StringUtils.splitIntoLines(output);
if (countAndLastLine.size() != 2)
throw new IllegalStateException("Not 2 lines in " + countAndLastLine);
final int replied = Integer.parseInt(countAndLastLine.get(0));
assert replied <= totalCount;
final PingResult res = new PingResult(totalCount, replied, requiredCount, replied == 0 ? null : parsePingAverageRT(countAndLastLine.get(1).trim()));
return res;
final BigDecimal averageRTT = replied == 0 ? null : parsePingAverageRT(countAndLastLine.get(1).trim());
return new PingResult(totalCount, replied, requiredCount, averageRTT);
} catch (Exception e) {
throw new IllegalStateException("Couldn't use output :<<<\n" + output + "\n<<<", e);
}
}
 
/**
* Eval the passed string with bash.
155,17 → 176,31
* @throws IOException If an I/O error occurs.
*/
public final Process eval(String s) throws IOException {
return Runtime.getRuntime().exec(new String[] { this.getBash(), "-c", s });
return evalPB(s).start();
}
 
public final ProcessBuilder evalPB(String s) throws IOException {
return new ProcessBuilder(this.getBash(), "-c", s);
}
 
public final int exitStatus(Process p) {
return this.exitStatus(p, null);
}
 
public final int exitStatus(Process p, final String name) {
try {
return p.waitFor();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
throw new RTInterruptedException("Interrupted while waiting for" + (name == null ? "" : " '" + name + "'") + " process", e);
}
}
 
public final void waitForSuccess(final Process p, final String name) {
final int exitStatus = exitStatus(p, name);
if (exitStatus != 0)
throw new IllegalStateException(name + " unsuccessful : " + exitStatus);
}
 
public abstract boolean isAdmin() throws IOException;
 
private static abstract class UnixPlatform extends Platform {
175,6 → 210,20
return true;
}
 
@Override
public final String getPreJava9PID() throws IOException {
final String symlink = getSelfProcessSymlink();
if (symlink == null)
return super.getPreJava9PID();
 
// readSymbolicLink() seems to faster than getCanonicalFile() or toRealPath().
// Another way is using reflection for
// ManagementFactory.getRuntimeMXBean().jvm.getProcessId()
return Files.readSymbolicLink(Paths.get(symlink)).getFileName().toString();
}
 
protected abstract String getSelfProcessSymlink();
 
public final boolean isRunning(final int pid) throws IOException {
// --pid only works on Linux, -p also on Nexenta
final Process p = Runtime.getRuntime().exec(new String[] { "ps", "-p", String.valueOf(pid) });
220,7 → 269,7
protected BigDecimal parsePingAverageRT(String statsLine) {
final Matcher m = PING_STATS_PATTERN.matcher(statsLine);
if (!m.matches())
throw new IllegalArgumentException("Not matching " + PING_STATS_PATTERN + " : " + statsLine);
throw new IllegalArgumentException("Not matching " + PING_STATS_PATTERN + " :\n" + statsLine);
return new BigDecimal(m.group(2));
}
 
232,7 → 281,13
}
 
private static final Platform LINUX = new UnixPlatform() {
 
@Override
protected String getSelfProcessSymlink() {
return "/proc/self";
}
 
@Override
public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
if (routingTableIndex > 0)
throw new UnsupportedOperationException("On Linux, choosing a different routing table requires changing the system policy");
271,7 → 326,13
};
 
private static final Platform FREEBSD = new UnixPlatform() {
 
@Override
protected String getSelfProcessSymlink() {
return "/proc/curproc";
}
 
@Override
public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
final List<String> command = new ArrayList<String>(16);
command.add("setfib");
308,6 → 369,18
}
};
 
private static final Platform MACOS = new UnixPlatform() {
@Override
protected String getSelfProcessSymlink() {
return null;
}
 
@Override
protected PingResult ping(InetAddress host, PingBuilder pingBuilder, int routingTableIndex) throws IOException {
return FREEBSD.ping(host, pingBuilder, routingTableIndex);
}
};
 
private static final class CygwinPlatform extends Platform {
 
@Override
347,13 → 420,9
public boolean ping(InetAddress host, final int timeout) throws IOException {
// windows implem of isReachable() is buggy
// see http://bordet.blogspot.com/2006/07/icmp-and-inetaddressisreachable.html
try {
final int exit = Runtime.getRuntime().exec("ping -n 1 -w " + timeout + " " + host.getHostAddress()).waitFor();
final int exit = this.exitStatus(Runtime.getRuntime().exec("ping -n 1 -w " + timeout + " " + host.getHostAddress()), "ping");
return exit == 0;
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
 
@Override
public PingResult ping(final InetAddress host, final PingBuilder pingBuilder, final int routingTableIndex) throws IOException {
/trunk/OpenConcerto/src/org/openconcerto/utils/PropertiesUtils.java
53,27 → 53,22
}
 
public static final Properties createFromFile(final File f) throws IOException {
return create(new BufferedInputStream(new FileInputStream(f)));
try (final InputStream stream = new BufferedInputStream(new FileInputStream(f))) {
return create(stream);
}
}
 
public static final Properties createFromResource(final Class<?> ctxt, final String rsrc) throws IOException {
return create(ctxt.getResourceAsStream(rsrc));
try (final InputStream stream = ctxt.getResourceAsStream(rsrc)) {
return create(stream);
}
 
protected static final Properties create(final InputStream stream) throws IOException {
return create(stream, true);
}
 
public static final Properties create(final InputStream stream, final boolean close) throws IOException {
public static final Properties create(final InputStream stream) throws IOException {
if (stream != null) {
try {
final Properties res = new Properties();
res.load(stream);
return res;
} finally {
if (close)
stream.close();
}
} else {
return null;
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ProcessStreams.java
25,6 → 25,7
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Supplier;
 
/**
* Redirect streams of a process to System.out and System.err.
60,7 → 61,7
// Added to Java 9
public static final Redirect DISCARD = Redirect.to(StreamUtils.NULL_FILE);
 
static public final ProcessBuilder redirect(final ProcessBuilder pb) throws IOException {
static public final ProcessBuilder redirect(final ProcessBuilder pb) {
return pb.redirectErrorStream(true).redirectOutput(Redirect.INHERIT);
}
 
69,7 → 70,7
p.getInputStream().close();
p.getErrorStream().close();
} else if (action == Action.REDIRECT) {
new ProcessStreams(p);
new ProcessStreams(p, System.out, System.err);
} else if (action == Action.CONSUME) {
new ProcessStreams(p, StreamUtils.NULL_OS, StreamUtils.NULL_OS);
}
81,10 → 82,6
private final Future<?> out;
private final Future<?> err;
 
public ProcessStreams(final Process p) {
this(p, System.out, System.err);
}
 
/**
* Create a new instance and start reading from the passed process. If a passed
* {@link OutputStream} is <code>null</code>, then the corresponding {@link InputStream} is not
97,13 → 94,14
*/
public ProcessStreams(final Process p, final OutputStream out, final OutputStream err) {
this.latch = new CountDownLatch(2);
this.out = writeToAsync(p.getInputStream(), out);
this.err = writeToAsync(p.getErrorStream(), err);
this.out = writeToAsync(p::getInputStream, out);
this.err = writeToAsync(p::getErrorStream, err);
this.exec.submit(new Runnable() {
@Override
public void run() {
try {
ProcessStreams.this.latch.await();
} catch (InterruptedException e) {
} catch (final InterruptedException e) {
// ne rien faire
e.printStackTrace();
} finally {
121,7 → 119,7
this.stop(this.err);
}
 
private final void stop(Future<?> f) {
private final void stop(final Future<?> f) {
if (f == null)
return;
// TODO
129,20 → 127,20
f.cancel(false);
}
 
private final Future<?> writeToAsync(final InputStream ins, final Object outs) {
private final Future<?> writeToAsync(final Supplier<InputStream> insSupplier, final Object outs) {
if (outs == null) {
this.latch.countDown();
return null;
}
return this.exec.submit(new Callable<Object>() {
public Object call() throws InterruptedException, IOException {
try {
@Override
public Void call() throws InterruptedException, IOException {
try (final InputStream ins = insSupplier.get()) {
// PrintStream is also an OutputStream
if (outs instanceof PrintStream)
writeTo(ins, (PrintStream) outs);
else
StreamUtils.copy(ins, (OutputStream) outs);
ins.close();
return null;
} finally {
ProcessStreams.this.latch.countDown();
159,7 → 157,7
* @throws InterruptedException if current thread is interrupted.
* @throws IOException if I/O error.
*/
public static final void writeTo(InputStream ins, PrintStream outs) throws InterruptedException, IOException {
public static final void writeTo(final InputStream ins, final PrintStream outs) throws InterruptedException, IOException {
final BufferedReader r = new BufferedReader(new InputStreamReader(ins));
String encodedName;
while ((encodedName = r.readLine()) != null) {
/trunk/OpenConcerto/src/org/openconcerto/utils/protocol/JavaSourceFromString.java
13,15 → 13,36
package org.openconcerto.utils.protocol;
 
import org.openconcerto.utils.FileUtils;
 
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
 
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
 
/**
* From {@link JavaCompiler} javadoc.
*/
public class JavaSourceFromString extends SimpleJavaFileObject {
 
static public boolean compile(final File outputDir, final JavaFileObject... classes) throws IOException {
FileUtils.mkdir_p(outputDir);
 
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
try (final StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir));
return compiler.getTask(null, fileManager, null, null, null, Arrays.asList(classes)).call().booleanValue();
}
}
 
/**
* The source code of this "file".
*/
33,11 → 54,18
* @param name the name of the compilation unit represented by this file object
* @param code the source code for the compilation unit represented by this file object
*/
JavaSourceFromString(String name, String code) {
public JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
 
public final String getClassFile() {
// /pkg/Inner.java
final String name = this.getName();
// pkg/Inner.class
return name.substring(1, name.length() - Kind.SOURCE.extension.length()) + Kind.CLASS.extension;
}
 
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return this.code;
/trunk/OpenConcerto/src/org/openconcerto/utils/protocol/Helper.java
56,28 → 56,38
}
 
/**
* Wrap the passed URL into a {@link Handler jarjar} one. Needed since the jre cannot read files
* inside a jar inside a jar.
* Return a jar URL to the root of a jar file. Needed since the JRE cannot read files inside a
* jar inside a jar.
*
* @param u the URL to wrap, e.g. "jar:file:/C:/mylibs/Outer.jar!/Inner.jar".
* @return the wrapped URL, if necessary, i.e. if <code>u</code> references a jar in a jar, e.g.
* "jar:jarjar:file:/C:/mylibs/Outer.jar^/Inner.jar!/".
* @return the wrapped URL, e.g. "jar:jarjar:file:/C:/mylibs/Outer.jar^/Inner.jar!/".
*/
public static final URL toJarJar(URL u) {
return toJarJar(u, "");
public static final URL intoJar(final URL u) {
return intoJar(u, "");
}
 
public static final URL toJarJar(final URL u, final String s) {
public static final URL intoJar(final URL u, final String s) {
if (!u.getPath().endsWith(".jar"))
throw new IllegalArgumentException("Doesn't end with .jar :" + u);
 
final URL res;
// if it's a jar inside another jar
if ("jar".equals(u.getProtocol()) && u.getPath().endsWith(".jar")) {
if ("jar".equals(u.getProtocol())) {
try {
return new URL("jar:jar" + u.toString().replace('!', '^') + "!/" + s);
res = new URL("jar:jar" + u.toExternalForm().replace('!', '^') + "!/" + s);
} catch (MalformedURLException e) {
// shouldn't happen since we modify a valid URL
throw new IllegalStateException("Couldn't transform " + u, e);
throw new IllegalStateException("Couldn't transform to jarjar " + u, e);
}
} else
return u;
} else {
try {
res = new URL("jar:" + u.toExternalForm() + "!/" + s);
} catch (MalformedURLException e) {
// shouldn't happen since constructed from a valid URL
throw new IllegalStateException("Couldn't transform to jar URL " + u, e);
}
}
return res;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/protocol/jarjar/Handler.java
120,7 → 120,7
 
// check for !/
if ((index = indexOfBangSlash(spec)) == -1) {
throw new IllegalArgumentException("no " + JarJarURLConnection.SEPARATOR + " in spec");
throw new IllegalArgumentException("no " + JarJarURLConnection.SEPARATOR + " in spec: " + spec);
}
// test the inner URL
try {
/trunk/OpenConcerto/src/org/openconcerto/utils/prog/VMLauncher.java
15,6 → 15,7
 
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.OSFamily;
import org.openconcerto.utils.OSFamily.Unix;
import org.openconcerto.utils.ProcessStreams;
import org.openconcerto.utils.PropertiesUtils;
 
40,6 → 41,7
*/
public abstract class VMLauncher {
 
private static final String PROPERTIES_EXT = ".properties";
/**
* Boolean system property, if set to <code>true</code> then {@link #restart(Class, List)} will
* simply return <code>null</code>. Useful e.g. when using IDE launch configuration (to debug).
46,6 → 48,38
*/
static public final String NO_RESTART = "vm.noRestart";
 
// Explicitly passed to jpackage
static public final String APPDIR_SYSPROP = "jpackage.app.dir";
 
// Automatically set by the jpackage launcher (could be set explicitly using --java-options
// '-Djpackage.app-path=$APPDIR/../../bin/launcher' if jpackage ever changes that)
static public final String APP_EXE_SYSPROP = "jpackage.app-path";
 
// The path to the app directory with the jar
public static final File getJPackageAppDir() {
final String appPath = System.getProperty(APPDIR_SYSPROP, "");
return appPath.isEmpty() ? null : new File(appPath);
}
 
// The path to the executable
private static final String getJPackageAppPath() {
final String appPath = System.getProperty(APP_EXE_SYSPROP, "");
return appPath.isEmpty() ? null : appPath;
}
 
private static final void addJPackageSystemPropertyArgument(final List<String> args, final String propName) {
final String arg = getJPackageSystemPropertyArg(propName);
if (arg != null)
args.add(arg);
}
 
private static final String getJPackageSystemPropertyArg(final String propName) {
final String val = System.getProperty(propName);
if (val == null)
return null;
return "-D" + propName + "=" + val;
}
 
private static NativeLauncherFinder getNativeAppLauncher() {
final OSFamily os = OSFamily.getInstance();
final NativeLauncherFinder l;
53,6 → 87,8
l = new WinLauncherFinder();
} else if (os.equals(OSFamily.Mac)) {
l = new MacLauncherFinder();
} else if (os instanceof Unix) {
l = new UnixLauncherFinder();
} else {
l = UnknownLauncherFinder;
}
98,13 → 134,28
*
* @param args the program arguments.
* @return the command.
* @throws UnsupportedOperationException if {@link #getAppPath()} returns <code>null</code>.
*/
public abstract List<String> getCommand(final List<String> args);
public final List<String> getCommand(final List<String> args) throws UnsupportedOperationException {
final String appPath = this.getAppPath();
if (appPath == null)
throw new UnsupportedOperationException();
 
return getCommand(appPath, args);
}
 
protected List<String> getCommand(final String appPath, final List<String> args) {
final List<String> command = new ArrayList<String>(4 + args.size());
command.add(appPath);
command.addAll(args);
return command;
}
}
 
private static class MacLauncherFinder extends NativeLauncherFinder {
private static final String APP_EXT = ".app";
private static final Pattern MAC_PATTERN = Pattern.compile(Pattern.quote(APP_EXT) + "/Contents/Resources(/Java)?/[^/]+\\.jar$");
// jpackage uses "Contents/app"
private static final Pattern MAC_PATTERN = Pattern.compile(Pattern.quote(APP_EXT) + "/Contents/(Resources(/Java)?|app)/[^/]+\\.jar$");
 
@Override
public String getAppPath() {
112,8 → 163,7
if (matcher.matches()) {
final String appPath = getFirstItem().substring(0, matcher.start() + APP_EXT.length());
final File contentsDir = new File(appPath, "Contents");
final List<String> bundleContent = Arrays.asList(contentsDir.list());
if (bundleContent.contains("Info.plist") && bundleContent.contains("PkgInfo") && new File(contentsDir, "MacOS").isDirectory())
if (new File(contentsDir, "Info.plist").isFile() && new File(contentsDir, "MacOS").isDirectory())
return appPath;
}
return null;
120,12 → 170,12
}
 
@Override
public List<String> getCommand(List<String> args) {
protected List<String> getCommand(String appPath, List<String> args) {
final List<String> command = new ArrayList<String>(4 + args.size());
command.add("open");
// since we restarting we need to launch a new instance of us
command.add("-n");
command.add(getAppPath());
command.add(appPath);
command.add("--args");
command.addAll(args);
return command;
141,13 → 191,19
else
return null;
}
}
 
private static class UnixLauncherFinder extends NativeLauncherFinder {
 
private final String jpackageApp;
 
public UnixLauncherFinder() {
this.jpackageApp = getJPackageAppPath();
}
 
@Override
public List<String> getCommand(List<String> args) {
final List<String> command = new ArrayList<String>(4 + args.size());
command.add(getAppPath());
command.addAll(args);
return command;
public String getAppPath() {
return this.jpackageApp;
}
}
 
156,11 → 212,6
public String getAppPath() {
return null;
}
 
@Override
public List<String> getCommand(List<String> args) {
throw new UnsupportedOperationException();
}
};
 
public static final Process restart(final Class<?> mainClass, final String... args) throws IOException {
221,7 → 272,8
public static final String PROPS_VMARGS = "VMARGS";
public static final String ENV_PROGARGS = "JAVA_PROGARGS";
 
// handle DOS, Mac and Unix newlines
// Don't split on spaces to avoid dealing with quotes or escapes : vmArgs=-Dfoo bar\t-DotherProp
// Handle DOS, Mac and Unix newlines (and tabs).
private static final Pattern NL = Pattern.compile("\\p{Cntrl}+");
 
private File wd;
232,6 → 284,8
 
public final File getLauncherWD() {
if (this.wd == null) {
final File appDir = getJPackageAppDir();
if (appDir == null) {
final NativeLauncherFinder nativeAppLauncher = getNativeAppLauncher();
final String appPath = nativeAppLauncher.getAppPath();
if (appPath != null)
242,7 → 296,10
// support launch in an IDE
else
this.wd = FileUtils.getWD();
} else {
this.wd = appDir;
}
}
return this.wd;
}
 
306,6 → 363,9
final boolean debug = Boolean.getBoolean("launcher.debug");
final String javaBinary = getJavaBinary();
final File sameJava = new File(System.getProperty("java.home"), "bin/" + javaBinary);
// allow to know what binary (and thus java.home) was tested
if (debug)
System.err.println("sameJava : " + sameJava);
final String java = sameJava.canExecute() ? sameJava.getAbsolutePath() : javaBinary;
final File propFile = this.getPropFile(mainClass);
final Properties props = this.getProps(propFile);
320,21 → 380,31
}
command.addAll(this.getVMArguments());
 
// for java the last specified property wins
// For java the last specified property wins. MAYBE concat properties whose names start with
// PROPS_VMARGS, that way we could override just one of many e.g. VMARGS.garbageCollector.
if (propFile != null) {
final List<String> appProps = this.getProp(props, PROPS_VMARGS);
command.addAll(appProps);
if (debug) {
System.err.println("VM arguments from " + propFile + " : " + appProps);
}
// Don't use Properties(defaults) constructor since we want to combine values.
final File localFile = FileUtils.prependSuffix(propFile, "-local", PROPERTIES_EXT);
final File userFile = new File(System.getProperty("user.home"), ".java/ilm/" + propFile.getName());
final List<String> userProps = this.getProp(userFile, PROPS_VMARGS);
command.addAll(userProps);
for (final File f : Arrays.asList(localFile, userFile)) {
final List<String> moreProps = this.getProp(f, PROPS_VMARGS);
command.addAll(moreProps);
if (debug) {
System.err.println("appProps : " + appProps);
System.err.println("userProps ( from " + userFile + ") : " + userProps);
System.err.println("VM arguments from " + f + " : " + moreProps);
}
}
}
final String envVMArgs = System.getenv(ENV_VMARGS);
if (envVMArgs != null)
command.addAll(split(envVMArgs));
// launched app may also need this context
addJPackageSystemPropertyArgument(command, APPDIR_SYSPROP);
addJPackageSystemPropertyArgument(command, APP_EXE_SYSPROP);
 
command.add("-cp");
command.add(getClassPath());
399,6 → 469,6
 
protected File getPropFile(final String mainClass) {
final String className = mainClass.substring(mainClass.lastIndexOf('.') + 1);
return new File(getWD(), className + ".properties");
return new File(getWD(), className + PROPERTIES_EXT);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/NetUtils.java
184,6 → 184,9
return content;
}
 
/**
* Encode for POST message application/x-www-form-urlencoded
*/
static public final String urlEncode(final String... kv) {
final int size = kv.length;
if (size % 2 != 0)
195,6 → 198,9
return urlEncode(map);
}
 
/**
* Encode for POST message application/x-www-form-urlencoded
*/
static public final String urlEncode(final Map<String, ?> map) {
if (map.isEmpty())
return "";
205,9 → 211,9
// Avoid null and "null" confusion.
if (value != null) {
try {
sb.append(URLEncoder.encode(e.getKey(), charset));
sb.append(URLEncoder.encode(e.getKey(), charset).replace("+", "%20"));
sb.append('=');
sb.append(URLEncoder.encode(String.valueOf(value), charset));
sb.append(URLEncoder.encode(String.valueOf(value), charset).replace("+", "%20"));
sb.append('&');
} catch (UnsupportedEncodingException exn) {
throw new IllegalStateException("UTF-8 should be standard", exn);
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionUtils.java
16,6 → 16,7
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IPredicate;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.ITransformerExn;
import org.openconcerto.utils.cc.IdentityHashSet;
import org.openconcerto.utils.cc.IdentitySet;
import org.openconcerto.utils.cc.LinkedIdentitySet;
29,8 → 30,10
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
39,6 → 42,11
import java.util.NoSuchElementException;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.regex.Pattern;
 
/**
240,12 → 248,8
delete(l, from, -1);
}
 
public static <T> void filter(Collection<T> collection, IPredicate<? super T> predicate) {
org.apache.commons.collections.CollectionUtils.filter(collection, predicate);
}
 
public static <T> boolean exists(Collection<T> collection, IPredicate<? super T> predicate) {
return org.apache.commons.collections.CollectionUtils.exists(collection, predicate);
return collection.stream().anyMatch(predicate::evaluateChecked);
}
 
/**
285,6 → 289,27
return map;
}
 
// compared to computeIfAbsent() :
// 1. allow exceptions
// 2. allow nulls
static public <K, V, X extends Exception> V computeIfAbsent(final Map<K, V> map, final K key, final ITransformerExn<K, V, X> function, final boolean allowNullValue) throws X {
V res = map.get(key);
final boolean contains;
if (allowNullValue) {
contains = res != null || map.containsKey(key);
} else {
contains = res != null;
}
if (!contains) {
res = function.transformChecked(key);
if (res == null && !allowNullValue)
throw new IllegalStateException("Null value computed for key '" + key + "'");
map.put(key, res);
}
assert allowNullValue || res != null;
return res;
}
 
/**
* Compute the index that have changed (added or removed) between 2 lists. One of the lists MUST
* be a sublist of the other, ie the to go from one to the other we just add or remove items but
377,8 → 402,8
return !Collections.disjoint(coll1, coll2);
}
 
static public final <T> boolean identityContains(final Collection<T> coll, final T item) {
for (final T v : coll) {
static public final boolean identityContains(final Collection<?> coll, final Object item) {
for (final Object v : coll) {
if (item == v)
return true;
}
385,6 → 410,27
return false;
}
 
static public final boolean identityEquals(final List<?> coll1, final List<?> coll2) {
if (coll1 == coll2)
return true;
final int size = coll1.size();
if (size != coll2.size())
return false;
if (size == 0)
return true;
 
final Iterator<?> iter1 = coll1.iterator();
final Iterator<?> iter2 = coll2.iterator();
while (iter1.hasNext()) {
final Object elem1 = iter1.next();
final Object elem2 = iter2.next();
if (elem1 != elem2)
return false;
}
assert !iter2.hasNext();
return true;
}
 
/**
* Convert an array to a list of a different type.
*
902,6 → 948,82
}
}
 
public static final <T> List<T> toImmutableList(final Collection<? extends T> coll) {
return toImmutableList(coll, ArrayList::new);
}
 
public static final <T, C extends Collection<? extends T>> List<T> toImmutableList(final C coll, final Function<? super C, ? extends List<T>> createColl) {
if (coll.isEmpty())
return Collections.emptyList();
return Collections.unmodifiableList(createColl.apply(coll));
}
 
public static final <T> Set<T> toImmutableSet(final Collection<T> coll) {
if (coll instanceof SortedSet) {
// force TreeSet(SortedSet) to keep Comparator
// ATTN see eclipse bug below about wrong constructor, we need SortedSet<T>, not
// SortedSet<? extends T>, otherwise "Open Declaration" will match to TreeSet(SortedSet)
// but not at runtime.
return toImmutableSet((SortedSet<T>) coll, TreeSet::new);
} else if (coll instanceof IdentitySet) {
return toImmutableSet((IdentitySet<? extends T>) coll, LinkedIdentitySet::new);
} else {
// In doubt, keep order
// ATTN LinkedHashSet extends HashSet
return toImmutableSet(coll, coll.getClass() == HashSet.class ? HashSet::new : LinkedHashSet::new);
}
}
 
public static final <T, C extends Collection<? extends T>> Set<T> toImmutableSet(final C coll, final Function<? super C, ? extends Set<T>> createColl) {
if (coll.isEmpty())
return Collections.emptySet();
final Set<T> res = createColl.apply(coll);
return Collections.unmodifiableSet(res);
}
 
/**
* Return an immutable map equal to the passed one.
*
* @param <K> type of keys.
* @param <V> type of values.
* @param map the map, not "? extends K" to be able to copy {@link SortedMap}.
* @return an immutable map.
*/
public static final <K, V> Map<K, V> toImmutableMap(final Map<K, ? extends V> map) {
if (map instanceof SortedMap) {
// force TreeMap(SortedMap) to keep Comparator
// ATTN see eclipse bug below about wrong constructor
return toImmutableMap((SortedMap<K, ? extends V>) map, TreeMap::new);
} else if (map instanceof IdentityHashMap) {
return toImmutableMap((IdentityHashMap<? extends K, ? extends V>) map, IdentityHashMap::new);
} else {
// In doubt, keep order
// ATTN LinkedHashMap extends HashMap
return toImmutableMap(map, map.getClass() == HashMap.class ? HashMap::new : LinkedHashMap::new);
}
}
 
/**
* Return an immutable map with the same entries as the passed one. NOTE: <code>copyMap</code>
* <strong>must</strong> copy the entries so that a modification of <code>map</code> doesn't
* affect the copy.
*
* @param <K> type of keys.
* @param <V> type of values.
* @param <InMap> type of passed map, ATTN if {@link SortedMap} eclipse "Open Declaration"
* matches <code>TreeMap::new</code> to {@link TreeMap#TreeMap(SortedMap)} ignoring
* generic type (i.e. it is declared with "K" but we pass "? extends K") but
* {@link TreeMap#TreeMap(Map)} is (correctly) executed at runtime.
* @param map the map.
* @param copyFunction how to copy the passed map.
* @return an immutable map.
*/
public static final <K, V, InMap extends Map<? extends K, ? extends V>> Map<K, V> toImmutableMap(final InMap map, final Function<? super InMap, ? extends Map<K, V>> copyFunction) {
if (map.isEmpty())
return Collections.emptyMap();
return Collections.unmodifiableMap(copyFunction.apply(map));
}
 
public static <K, V> Map<K, V> createMap(K key, V val, K key2, V val2) {
// arguments are ordered, so should the result
final Map<K, V> res = new LinkedHashMap<K, V>();
/trunk/OpenConcerto/src/org/openconcerto/utils/Destroyable.java
New file
0,0 → 1,22
/*
* 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;
 
import java.util.concurrent.TimeUnit;
 
public interface Destroyable {
void destroy();
 
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
}
/trunk/OpenConcerto/src/org/openconcerto/utils/CollectionMap2Itf.java
16,17 → 16,46
import org.openconcerto.utils.CollectionMap2.Mode;
 
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
 
public interface CollectionMap2Itf<K, C extends Collection<V>, V> extends Map<K, C> {
 
public static interface ListMapItf<K, V> extends CollectionMap2Itf<K, List<V>, V> {
/**
* Change this instance and return an unmodifiable Map view. After this method, this
* instance shouldn't be modified, e.g. if a new entry (with a modifiable collection) is
* added then the returned object will be able to modify it. Contrary to
* {@link ListMap#unmodifiableMap(ListMapItf)}, the returned object doesn't allocate any
* memory.
*
* @return an unmodifiable Map view.
* @see CollectionMap2Itf#convertToUnmodifiableMap(Function)
*/
public default Map<K, List<V>> convertToUnmodifiableMap() {
return convertToUnmodifiableMap(Collections::unmodifiableList);
}
}
 
public static interface SetMapItf<K, V> extends CollectionMap2Itf<K, Set<V>, V> {
/**
* Change this instance and return an unmodifiable Map view. After this method, this
* instance shouldn't be modified, e.g. if a new entry (with a modifiable collection) is
* added then the returned object will be able to modify it. Contrary to
* {@link SetMap#unmodifiableMap(ListMapItf)}, the returned object doesn't allocate any
* memory.
*
* @return an unmodifiable Map view.
* @see CollectionMap2Itf#convertToUnmodifiableMap(Function)
*/
public default Map<K, Set<V>> convertToUnmodifiableMap() {
return convertToUnmodifiableMap(Collections::unmodifiableSet);
}
}
 
public Mode getMode();
 
116,4 → 145,24
public Set<K> removeAllEmptyCollections();
 
public Set<K> removeAllNullCollections();
 
public default void replaceAllNonNullValues(final Function<? super C, ? extends C> function) {
this.replaceAll((k, v) -> v == null ? null : function.apply(v));
}
 
/**
* Change this instance and return an unmodifiable Map view. After this method, this instance
* shouldn't be modified, e.g. if a new entry (with a modifiable collection) is added then the
* returned object will be able to modify it. The returned object doesn't allocate any memory.
*
* @param toUnmodifiable how to replace collections with unmodifiable views, never passed
* <code>null</code>.
* @return an unmodifiable Map view.
* @see SetMapItf#convertToUnmodifiableMap()
* @see ListMapItf#convertToUnmodifiableMap()
*/
public default Map<K, C> convertToUnmodifiableMap(final Function<? super C, ? extends C> toUnmodifiable) {
this.replaceAllNonNullValues(Objects.requireNonNull(toUnmodifiable));
return Collections.unmodifiableMap(this);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/tools/Outer.java
New file
0,0 → 1,77
/*
* 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.tools;
 
import org.openconcerto.utils.tools.SimpleURLClassLoader.URLCollector;
 
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.util.PropertyPermission;
 
public final class Outer {
 
public static void main(String[] args) throws Exception {
final String className = args[0];
final String fieldName = args[1];
 
org.openconcerto.utils.protocol.Helper.register();
 
// Install SecurityManager to test SecureClassLoader.getPermissions().
final ClassLoader mainLoader = Outer.class.getClassLoader();
Policy.setPolicy(new Policy() {
@Override
public boolean implies(ProtectionDomain domain, Permission permission) {
// our class loader gets all permission
if (domain != null && domain.getClassLoader() == mainLoader) {
return true;
}
return super.implies(domain, permission);
}
});
System.setSecurityManager(new SecurityManager());
 
final PermissionCollection innerPerms = new Permissions();
innerPerms.add(new RuntimePermission("accessDeclaredMembers"));
if (Boolean.getBoolean("property.read"))
innerPerms.add(new PropertyPermission("*", "read"));
innerPerms.setReadOnly();
System.out.print(new Outer(className).getFieldValue(innerPerms, fieldName));
}
 
private final String className;
 
public Outer(String className) {
super();
this.className = className;
}
 
public Object getFieldValue(final PermissionCollection perms, final String fieldName) throws ClassNotFoundException, ReflectiveOperationException {
// needed to test loading from jar inside a jar
if (!this.getClass().getResource(this.getClass().getSimpleName() + ".class").toExternalForm().startsWith("jar:file:"))
throw new IllegalStateException("Class not loaded from a jar");
final ClassLoader loader = new SimpleURLClassLoader(new URLCollector().addJar(this.getClass().getResource("/inner.jar"))) {
@Override
protected PermissionCollection getPermissions(CodeSource codesource) {
return perms;
}
};
final Class<?> loadedClass = loader.loadClass(this.className);
return loadedClass.getDeclaredField(fieldName).get(null);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/tools/SimpleURLClassLoader.java
New file
0,0 → 1,169
/*
* 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.tools;
 
import org.openconcerto.utils.Log;
import org.openconcerto.utils.StreamUtils;
 
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.SecureClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
 
/**
* Class loader which supports any URL. {@link URLClassLoader} only supports directories and jar
* files, but is more optimized (e.g. for finding which URL contains a resource)
*
* @author sylvain
*/
public class SimpleURLClassLoader extends SecureClassLoader {
 
static public final URL toURL(final File f) {
try {
return f.toURI().toURL();
} catch (MalformedURLException e) {
// shouldn't happen since constructed from a file
throw new IllegalStateException("Couldn't transform file to URL " + f, e);
}
}
 
static public class URLCollector {
private final List<URL> urls = new ArrayList<>();
 
public final List<URL> copyToUnmodifiableList() {
return Collections.unmodifiableList(new ArrayList<>(this.urls));
}
 
public final URLCollector add(final URL url) {
this.urls.add(url);
return this;
}
 
public final URLCollector addDirectory(final File dir) {
if (!dir.isDirectory())
throw new IllegalArgumentException("Not a directory : " + dir);
return this.add(toURL(dir));
}
 
public final URLCollector addJar(final File jar) {
if (!jar.isFile())
throw new IllegalArgumentException("Not a file : " + jar);
return this.addJar(toURL(jar));
}
 
public final URLCollector addJar(final URL u) {
return this.add(org.openconcerto.utils.protocol.Helper.intoJar(u));
}
 
public final URLCollector addJars(final Iterable<URL> jars) {
for (final URL jar : jars)
this.addJar(jar);
return this;
}
}
 
// from ResourceBundle.Control
static public final String toResourceName(String bundleName, String suffix) {
StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
return sb.toString();
}
 
static public final String toClassFile(String bundleName) {
return toResourceName(bundleName, "class");
}
 
private final List<URL> urls;
 
public SimpleURLClassLoader(final URLCollector urls) {
super();
this.urls = urls.copyToUnmodifiableList();
}
 
public SimpleURLClassLoader(final URLCollector urls, final ClassLoader parent) {
super(parent);
this.urls = urls.copyToUnmodifiableList();
}
 
protected URL createURL(final URL url, final String spec) throws MalformedURLException {
return new URL(url, spec);
}
 
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
for (final URL baseURL : this.urls) {
try {
final URL url = createURL(baseURL, toClassFile(name));
try (final InputStream ins = url.openConnection().getInputStream()) {
try {
final byte[] bytes = StreamUtils.read(ins);
return this.defineClass(name, bytes, 0, bytes.length, new CodeSource(url, (CodeSigner[]) null));
} catch (IOException readExn) {
// same behaviour as URLClassLoader.findClass()
throw new ClassNotFoundException(name, readExn);
}
}
} catch (IOException connectExn) {
Log.get().log(Level.FINE, connectExn, () -> "Couldn't connect to " + baseURL + " for " + name);
// next
}
}
return super.findClass(name);
}
 
@Override
protected URL findResource(String name) {
for (final URL baseURL : this.urls) {
try {
final URL url = createURL(baseURL, name);
boolean exists = false;
if (url.getProtocol().equals("file")) {
exists = new File(url.toURI()).exists();
} else {
// From sun.misc.URLClassPath.Loader
URLConnection uc = url.openConnection();
if (uc instanceof HttpURLConnection) {
HttpURLConnection hconn = (HttpURLConnection) uc;
hconn.setRequestMethod("HEAD");
exists = hconn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST;
} else {
// our best guess for the other cases
uc.setUseCaches(false);
try (final InputStream ins = uc.getInputStream()) {
exists = true;
} catch (IOException e) {
exists = false;
}
}
}
if (exists)
return url;
} catch (Exception e) {
// next
}
}
return super.findResource(name);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/net/HTTPClient.java
116,7 → 116,7
return this.getToken() != null;
}
 
protected final String getToken() {
public final String getToken() {
return this.token;
}
 
144,8 → 144,9
con.setRequestProperty("Accept-Encoding", "gzip");
if (this.getSocketFactory() != null)
con.setSSLSocketFactory(this.getSocketFactory());
if (getToken() != null)
if (getToken() != null) {
con.setRequestProperty("Authorization", "Bearer " + Base64.getEncoder().encodeToString(getToken().getBytes(StandardCharsets.UTF_8)));
}
return con;
}
 
153,12 → 154,13
return "gzip".equals(con.getContentEncoding()) ? new GZIPInputStream(con.getInputStream()) : con.getInputStream();
}
 
public final HttpsURLConnection send(final HttpsURLConnection con, final String params) throws IOException {
return this.send(con, params, true);
public final HttpsURLConnection send(final HttpsURLConnection con, final String formUrlEncodedParams) throws IOException {
return this.send(con, formUrlEncodedParams, true);
}
 
public final HttpsURLConnection send(final HttpsURLConnection con, final String params, final boolean allowGzip) throws IOException {
return this.send(con, params.getBytes(StandardCharsets.UTF_8), allowGzip);
public final HttpsURLConnection send(final HttpsURLConnection con, final String formUrlEncodedParams, final boolean allowGzip) throws IOException {
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
return this.send(con, formUrlEncodedParams.getBytes(StandardCharsets.UTF_8), allowGzip);
}
 
public final HttpsURLConnection send(final HttpsURLConnection con, final byte[] toSend, final boolean allowGzip) throws IOException {
/trunk/OpenConcerto/src/org/openconcerto/utils/Base64.java
35,11 → 35,11
* change some method calls that you were making to support the new options format (<tt>int</tt>s
* that you "OR" together).</li>
* <li>v1.5.1 - Fixed bug when decompressing and decoding to a byte[] using
* <tt>decode( String s, boolean gzipCompressed )</tt>. Added the ability to "suspend" encoding
* in the Output Stream so you can turn on and off the encoding if you need to embed base64 data in
* an otherwise "normal" stream (like an XML file).</li>
* <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself. This helps
* when using GZIP streams. Added the ability to GZip-compress objects before encoding them.</li>
* <tt>decode( String s, boolean gzipCompressed )</tt>. Added the ability to "suspend" encoding in
* the Output Stream so you can turn on and off the encoding if you need to embed base64 data in an
* otherwise "normal" stream (like an XML file).</li>
* <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself. This helps when
* using GZIP streams. Added the ability to GZip-compress objects before encoding them.</li>
* <li>v1.4 - Added helper methods to read/write files.</li>
* <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
* <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream where last
50,9 → 50,9
*
* <p>
* I am placing this code in the Public Domain. Do with it as you will. This software comes with no
* guarantees or warranties but with plenty of well-wishing instead! Please visit <a
* href="http://iharder.net/base64">http://iharder.net/base64</a> periodically to check for updates
* or to contribute improvements.
* guarantees or warranties but with plenty of well-wishing instead! Please visit
* <a href="http://iharder.net/base64">http://iharder.net/base64</a> periodically to check for
* updates or to contribute improvements.
* </p>
*
* @author Robert Harder
95,11 → 95,11
/** The 64 valid Base64 values. */
private final static byte[] ALPHABET;
private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */
{ (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
(byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e',
(byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't',
(byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8',
(byte) '9', (byte) '+', (byte) '/' };
{ (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O',
(byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd',
(byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's',
(byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7',
(byte) '8', (byte) '9', (byte) '+', (byte) '/' };
 
/** Determine which ALPHABET to use. */
static {
167,7 → 167,8
* Encodes up to the first three bytes of array <var>threeBytes</var> and returns a four-byte
* array in Base64 notation. The actual number of significant bytes in your array is given by
* <var>numSigBytes</var>. The array <var>threeBytes</var> needs only be as big as
* <var>numSigBytes</var>. Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
* <var>numSigBytes</var>. Code can reuse a byte array by passing a four-byte array as
* <var>b4</var>.
*
* @param b4 A reusable byte array to reduce array instantiation
* @param threeBytes the array to convert
181,13 → 182,13
} // end encode3to4
 
/**
* Encodes up to three bytes of the array <var>source</var> and writes the resulting four
* Base64 bytes to <var>destination</var>. The source and destination arrays can be manipulated
* Encodes up to three bytes of the array <var>source</var> and writes the resulting four Base64
* bytes to <var>destination</var>. The source and destination arrays can be manipulated
* anywhere along their length by specifying <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays are large enough to accomodate
* <var>srcOffset</var> + 3 for the <var>source</var> array or <var>destOffset</var> + 4 for
* the <var>destination</var> array. The actual number of significant bytes in your array is
* given by <var>numSigBytes</var>.
* <var>srcOffset</var> + 3 for the <var>source</var> array or <var>destOffset</var> + 4 for the
* <var>destination</var> array. The actual number of significant bytes in your array is given
* by <var>numSigBytes</var>.
*
* @param source the array to convert
* @param srcOffset the index where conversion begins
342,9 → 343,13
* @since 1.4
*/
public static String encodeBytes(byte[] source) {
return encodeBytes(source, 0, source.length, NO_OPTIONS);
return encodeBytes(source, 0, source.length, DONT_BREAK_LINES);
} // end encodeBytes
 
public static String encodeBytesBreakLines(byte[] source) {
return encodeBytes(source, NO_OPTIONS);
}
 
/**
* Encodes a byte array into Base64 notation.
* <p>
381,9 → 386,13
* @since 1.4
*/
public static String encodeBytes(byte[] source, int off, int len) {
return encodeBytes(source, off, len, NO_OPTIONS);
return encodeBytes(source, off, len, DONT_BREAK_LINES);
} // end encodeBytes
 
public static String encodeBytesBreakLines(byte[] source, int off, int len) {
return encodeBytes(source, off, len, NO_OPTIONS);
}
 
/**
* Encodes a byte array into Base64 notation.
* <p>
505,8 → 514,8
* of them) to <var>destination</var>. The source and destination arrays can be manipulated
* anywhere along their length by specifying <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays are large enough to accomodate
* <var>srcOffset</var> + 4 for the <var>source</var> array or <var>destOffset</var> + 3 for
* the <var>destination</var> array. This method returns the actual number of bytes that were
* <var>srcOffset</var> + 4 for the <var>source</var> array or <var>destOffset</var> + 3 for the
* <var>destination</var> array. This method returns the actual number of bytes that were
* converted from the Base64 encoding.
*
*
694,8 → 703,8
} // end decode
 
/**
* Attempts to decode Base64 data and deserialize a Java Object within. Returns <tt>null</tt>
* if there was an error.
* Attempts to decode Base64 data and deserialize a Java Object within. Returns <tt>null</tt> if
* there was an error.
*
* @param encodedObject The Base64 data to decode
* @return The decoded and deserialized object
909,8 → 918,8
/* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
 
/**
* A {@link Base64.InputStream} will read data from another <tt>java.io.InputStream</tt>,
* given in the constructor, and encode/decode to/from Base64 notation on the fly.
* A {@link Base64.InputStream} will read data from another <tt>java.io.InputStream</tt>, given
* in the constructor, and encode/decode to/from Base64 notation on the fly.
*
* @see Base64
* @since 1.3
1107,8 → 1116,8
/* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
 
/**
* A {@link Base64.OutputStream} will write data to another <tt>java.io.OutputStream</tt>,
* given in the constructor, and encode/decode to/from Base64 notation on the fly.
* A {@link Base64.OutputStream} will write data to another <tt>java.io.OutputStream</tt>, given
* in the constructor, and encode/decode to/from Base64 notation on the fly.
*
* @see Base64
* @since 1.3
/trunk/OpenConcerto/src/org/openconcerto/utils/Value.java
13,7 → 13,10
package org.openconcerto.utils;
 
import org.openconcerto.utils.cc.I2ExnFactory;
 
import java.util.Map;
import java.util.function.Supplier;
 
/**
* Null can be ambiguous, e.g. {@link Map#get(Object)}. This class allows to avoid the problem.
157,6 → 160,33
return def;
}
 
public final Value<V> asSome(final V def) {
if (this.hasValue())
return this;
else
return getSome(def);
}
 
// Same method names as Optional
 
public final V orElse(final V def) {
return this.getValue(def);
}
 
public final V orGet(final Supplier<? extends V> def) {
if (this.hasValue())
return this.getValue();
else
return def.get();
}
 
public final <X extends Exception, X2 extends Exception> V orThrowingGet(final I2ExnFactory<? extends V, X, X2> def) throws X, X2 {
if (this.hasValue())
return this.getValue();
else
return def.createChecked();
}
 
/**
* Return <code>null</code> if and only if this has no value.
*
/trunk/OpenConcerto/src/org/openconcerto/utils/QuickOrderedMap.java
New file
0,0 → 1,138
/*
* 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;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
 
/**
* Map optimisée pour les petites tailles (<50).
*
* Empreinte mémoire divisée 4 par rapport à HashMap.
*
* N'implemente pas Map pour ne pas exposer des méthodes sous-optimales
*
*/
public class QuickOrderedMap<K, V> {
 
private final ArrayList<Object> keysAndValues;
 
public QuickOrderedMap() {
this(10);
}
 
public QuickOrderedMap(int initialCapacity) {
this.keysAndValues = new ArrayList<>(initialCapacity * 2);
}
 
public int size() {
return this.keysAndValues.size() / 2;
}
 
public boolean isEmpty() {
return this.keysAndValues.isEmpty();
}
 
public boolean containsKey(K key) {
final int size = this.keysAndValues.size();
for (int i = 0; i < size; i += 2) {
if (this.keysAndValues.get(i).equals(key)) {
return true;
}
}
return false;
}
 
public boolean containsValue(V value) {
final int size = this.keysAndValues.size();
for (int i = 1; i < size; i += 2) {
if (this.keysAndValues.get(i).equals(value)) {
return true;
}
}
return false;
}
 
@SuppressWarnings("unchecked")
public K getKey(int index) {
return (K) this.keysAndValues.get(index * 2);
}
 
@SuppressWarnings("unchecked")
public V getValue(int index) {
return (V) this.keysAndValues.get(1 + index * 2);
}
 
@SuppressWarnings("unchecked")
public V get(K key) {
final int size = this.keysAndValues.size();
for (int i = 0; i < size; i += 2) {
if (this.keysAndValues.get(i).equals(key)) {
 
return (V) this.keysAndValues.get(i + 1);
}
}
return null;
}
 
@SuppressWarnings("unchecked")
public V put(K key, V value) {
final int size = this.keysAndValues.size();
for (int i = 0; i < size; i += 2) {
if (this.keysAndValues.get(i).equals(key)) {
final Object old = this.keysAndValues.get(i + 1);
this.keysAndValues.set(i + 1, value);
return (V) old;
}
}
this.keysAndValues.add(key);
this.keysAndValues.add(value);
return null;
}
 
@SuppressWarnings("unchecked")
public V remove(K key) {
final int size = this.keysAndValues.size();
for (int i = 0; i < size; i += 2) {
if (this.keysAndValues.get(i).equals(key)) {
this.keysAndValues.remove(i);
return (V) this.keysAndValues.remove(i);
}
}
return null;
}
 
public void putAll(Map<? extends K, ? extends V> m) {
final Set<? extends K> keySet = m.keySet();
if (!isEmpty()) {
for (Iterator<? extends K> iterator = keySet.iterator(); iterator.hasNext();) {
K key = iterator.next();
put(key, m.get(key));
}
} else {
for (Iterator<? extends K> iterator = keySet.iterator(); iterator.hasNext();) {
K key = iterator.next();
this.keysAndValues.add(key);
this.keysAndValues.add(m.get(key));
}
}
}
 
public void clear() {
this.keysAndValues.clear();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/TransformedComparator.java
14,12 → 14,9
package org.openconcerto.utils;
 
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.Transformer;
 
import java.util.Comparator;
 
import org.apache.commons.collections.ComparatorUtils;
 
/**
* A comparator that transforms before comparing.
*
26,29 → 23,22
* @author Sylvain
*
* @param <E> the type of the objects before being transformed.
* @param <T> the type of the objects after being transformed.
*/
public class TransformedComparator<E, T> implements Comparator<E> {
public class TransformedComparator<E> implements Comparator<E> {
 
public static final <T> TransformedComparator<T, T> from(final Comparator<T> comp) {
return new TransformedComparator<T, T>(Transformer.<T> nopTransformer(), comp);
}
private final Comparator<E> comp;
 
private final ITransformer<E, T> transf;
private final Comparator<T> comp;
 
@SuppressWarnings("unchecked")
public TransformedComparator(final ITransformer<E, T> transf) {
this(transf, ComparatorUtils.NATURAL_COMPARATOR);
public <T extends Comparable<T>> TransformedComparator(final ITransformer<E, T> transf) {
this(transf, Comparator.naturalOrder());
}
 
public TransformedComparator(final ITransformer<E, T> transf, final Comparator<T> comp) {
public <T> TransformedComparator(final ITransformer<E, T> transf, final Comparator<T> comp) {
super();
this.transf = transf;
this.comp = comp;
this.comp = (o1, o2) -> (comp.compare(transf.transformChecked(o1), transf.transformChecked(o2)));
}
 
@Override
public int compare(E o1, E o2) {
return this.comp.compare(this.transf.transformChecked(o1), this.transf.transformChecked(o2));
return this.comp.compare(o1, o2);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/NoneSelectedButtonGroup.java
23,7 → 23,9
if (selected) {
super.setSelected(model, selected);
} else {
if (model.isSelected()) {
clearSelection();
}
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/ConcurrentUtils.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;
 
public class ConcurrentUtils {
public static final boolean runLocked(final Object first, final Object second, final Runnable run) {
if (second == first)
return false;
final int thisHash = System.identityHashCode(first);
final int oHash = System.identityHashCode(second);
final Object o1, o2;
if (thisHash < oHash) {
o1 = first;
o2 = second;
} else if (thisHash > oHash) {
o1 = second;
o2 = first;
} else {
throw new IllegalStateException("Hash equal");
}
synchronized (o1) {
synchronized (o2) {
run.run();
}
}
return true;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cache/LRUMap.java
New file
0,0 → 1,52
/*
* 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.cache;
 
import java.util.LinkedHashMap;
 
public class LRUMap<K, V> extends LinkedHashMap<K, V> {
 
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int REHASH_GROWTH = 2;
private static final int MIN_CAPACITY = 4;
private static final int SIZE_THRESHOLD = (int) (MIN_CAPACITY * DEFAULT_LOAD_FACTOR * REHASH_GROWTH);
 
private int maxSize;
 
public LRUMap(final int maxSize) {
this(maxSize, maxSize <= SIZE_THRESHOLD ? MIN_CAPACITY : (int) (maxSize / DEFAULT_LOAD_FACTOR / REHASH_GROWTH + 1));
}
 
public LRUMap(final int maxSize, final int initialCapacity) {
this(maxSize, initialCapacity, DEFAULT_LOAD_FACTOR);
}
 
public LRUMap(final int maxSize, int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
this.setMaxSize(maxSize);
}
 
public final int getMaxSize() {
return this.maxSize;
}
 
public final void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
 
@Override
protected final boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
return this.size() > this.getMaxSize();
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cache/ICacheSupport.java
107,6 → 107,7
}
}
 
boolean interrupted = false;
if (didDie) {
// only CacheTimeOut are in our executor (plus the runnable for trimWatchers())
// and all items in a cache (even the running ones) have a timeout (but they don't all
118,6 → 119,15
}
}
 
// make sure that the currently executing runnable is done before checking
while (true) {
try {
if (this.getTimer().awaitTermination(1, TimeUnit.SECONDS))
break;
} catch (InterruptedException e) {
interrupted = true;
}
}
synchronized (this) {
purgeWatchers();
assert this.watchers.isEmpty() : this.watchers.size() + " item(s) were not removed : " + this.watchers.values();
124,6 → 134,8
}
}
 
if (interrupted)
Thread.currentThread().interrupt();
return didDie;
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/EmailClient.java
17,6 → 17,8
import org.openconcerto.utils.DesktopEnvironment.KDE;
import org.openconcerto.utils.DesktopEnvironment.Mac;
import org.openconcerto.utils.DesktopEnvironment.Windows;
import org.openconcerto.utils.DesktopEnvironment.XFCE;
import org.openconcerto.utils.OSFamily.Unix;
import org.openconcerto.utils.io.PercentEncoder;
 
import java.io.BufferedOutputStream;
294,6 → 296,12
// ~/.kde/share/config/emaildefaults or /etc/kde (ou /usr/share/config qui est un
// lien symbolique vers /etc/kde)
return XDG;
} else if (de instanceof XFCE) {
// .config/xfce4/helpers.rc contains "MailReader=desktopName"
// A custom one can be created in .local/share/xfce4/helpers/custom-MailReader.desktop
return XDG;
} else if (OSFamily.getInstance() instanceof Unix) {
return XDG;
}
 
return MailTo;
/trunk/OpenConcerto/src/org/openconcerto/utils/io/JSONConverter.java
152,6 → 152,12
}
 
public static <T> T getParameterFromJSON(final JSONObject json, final String key, final Class<T> type, T defaultValue) {
if (json == null) {
throw new IllegalArgumentException("null JSON");
}
if (key == null) {
throw new IllegalArgumentException("null key");
}
return json.containsKey(key) ? getObjectFromJSON(json.get(key), type) : defaultValue;
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/DesktopEnvironment.java
21,10 → 21,13
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileSystemView;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
32,6 → 35,9
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
/**
* A desktop environment like Gnome or MacOS.
*
38,6 → 44,7
* @author Sylvain CUAZ
* @see #getDE()
*/
@ThreadSafe
public abstract class DesktopEnvironment {
 
static public final class Gnome extends DesktopEnvironment {
212,8 → 219,8
static public final class Mac extends DEisOS {
 
// From CarbonCore/Folders.h
private static final String kDocumentsDirectory = "docs";
private static final String kPreferencesDirectory = "pref";
public static final String kDocumentsDirectory = "docs";
public static final String kPreferencesDirectory = "pref";
private static Class<?> FileManagerClass;
private static Short kUserDomain;
private static Method OSTypeToInt;
235,18 → 242,28
 
@Override
public File getDocumentsFolder() {
return getFolder(kDocumentsDirectory);
return new File(System.getProperty("user.home"), "Documents/");
}
 
@Override
public File getPreferencesFolder(String appName) {
return new File(getFolder(kPreferencesDirectory), appName);
}
 
// There was a warning until JRE v16, now "--add-exports
// java.desktop/com.apple.eio=ALL-UNNAMED" is needed. Further this needs the EDT which is
// undesirable just to get some paths.
// https://bugs.openjdk.java.net/browse/JDK-8187981
@Deprecated
public File getFolder(String type) {
try {
final Method findFolder = getFileManagerClass().getMethod("findFolder", Short.TYPE, Integer.TYPE);
final String path = (String) findFolder.invoke(null, kUserDomain, OSTypeToInt.invoke(null, type));
final RunnableFuture<String> f = new FutureTask<>(() -> (String) findFolder.invoke(null, kUserDomain, OSTypeToInt.invoke(null, type)));
// EDT needed at least for JRE v14-16 on macOS 10.15, otherwise the VM crashes :
// Problematic frame: __NSAssertMainEventQueueIsCurrentEventQueue_block_invoke or
// "The current event queue and the main event queue are not the same. This is
// probably because _TSGetMainThread was called for the first time off the main
// thread."
if (SwingUtilities.isEventDispatchThread())
f.run();
else
SwingUtilities.invokeLater(f);
final String path = f.get();
return new File(path);
} catch (RuntimeException e) {
throw e;
346,9 → 363,10
return new Unknown();
}
 
@GuardedBy("DesktopEnvironment.class")
private static DesktopEnvironment DE = null;
 
public static final DesktopEnvironment getDE() {
public synchronized static final DesktopEnvironment getDE() {
if (DE == null) {
DE = detectDE();
}
355,10 → 373,11
return DE;
}
 
public static final void resetDE() {
public synchronized static final void resetDE() {
DE = null;
}
 
@GuardedBy("this")
private String version;
 
private DesktopEnvironment() {
367,7 → 386,7
 
protected abstract String findVersion();
 
public final String getVersion() {
public synchronized final String getVersion() {
if (this.version == null)
this.version = this.findVersion();
return this.version;
378,17 → 397,6
return FileSystemView.getFileSystemView().getDefaultDirectory();
}
 
/**
* Where the configuration files are stored.
*
* @param appName the name of application.
* @return the preferences folder.
* @deprecated kept around to migrate existing files, but otherwise use {@link BaseDirs}.
*/
public File getPreferencesFolder(final String appName) {
return new File(System.getProperty("user.home"), "." + appName);
}
 
// on some systems arguments are not passed correctly by ProcessBuilder
public String quoteParamForExec(String s) {
return s;
/trunk/OpenConcerto/src/org/openconcerto/utils/FileUtils.java
14,8 → 14,8
package org.openconcerto.utils;
 
import org.openconcerto.utils.CollectionMap2.Mode;
import org.openconcerto.utils.DesktopEnvironment.Gnome;
import org.openconcerto.utils.OSFamily.Unix;
import org.openconcerto.utils.ProcessStreams.Action;
import org.openconcerto.utils.StringUtils.Escaper;
import org.openconcerto.utils.cc.ExnTransformer;
import org.openconcerto.utils.cc.IClosure;
45,9 → 45,11
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermissions;
61,6 → 63,7
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Pattern;
67,34 → 70,76
 
public final class FileUtils {
 
public static void main(String[] args) throws Exception {
final String cmd = args[0];
if ("browseFile".equals(cmd))
browseFile(new File(args[1]));
else if ("browse".equals(cmd))
browse(new URI(args[1]));
else
System.err.println("Unkown command : " + cmd);
}
 
private FileUtils() {
// all static
}
 
public static void browseFile(final File f) throws IOException {
browse(null, Objects.requireNonNull(f));
}
 
if (Desktop.isDesktopSupported()) {
Desktop d = Desktop.getDesktop();
if (d.isSupported(Desktop.Action.BROWSE)) {
d.browse(f.getCanonicalFile().toURI());
} else {
openNative(f);
private static void browse(URI uri, final File f) throws IOException {
assert (uri == null) != (f == null);
boolean handled = false;
final Desktop.Action action = Desktop.Action.BROWSE;
if (isDesktopDesirable(action) && Desktop.isDesktopSupported()) {
final Desktop d = Desktop.getDesktop();
if (d.isSupported(action)) {
if (uri == null)
uri = f.getCanonicalFile().toURI();
if (!uri.getScheme().equals("file") && DesktopEnvironment.getDE() instanceof Gnome) {
ProcessBuilder pb = null;
final String version = DesktopEnvironment.getDE().getVersion();
// Ubuntu 12.04, 14.04, 16.04
if (version.startsWith("3.4.") || version.startsWith("3.10.") || version.startsWith("3.18.")) {
pb = new ProcessBuilder("gvfs-mount", uri.toASCIIString());
// Ubuntu 18.04
} else if (version.startsWith("3.28")) {
// gio/gio-tool-mount.c#mount() calls g_file_mount_enclosing_volume.
// TODO find out how glib computes "the volume that contains the file
// location". E.g why does mount "davs://example.com/webdav/dir/dir" mounts
// "davs://example.com/webdav/".
// Return 0 if not yet mounted, 2 if it was already mounted.
pb = new ProcessBuilder("gio", "mount", uri.toASCIIString());
}
} else {
if (pb != null) {
try {
startDiscardingOutput(pb).waitFor();
} catch (InterruptedException e) {
throw new RTInterruptedException("Interrupted while waiting on mount for " + uri, e);
}
}
}
d.browse(uri);
handled = true;
}
}
if (!handled) {
// if the caller passed a file use it instead of our converted URI
if (f != null)
openNative(f);
else
openNative(uri);
}
}
 
public static void browse(URI uri) throws Exception {
final boolean windows = System.getProperty("os.name").startsWith("Windows");
if (windows) {
Desktop.getDesktop().browse(uri);
} else {
String[] cmdarray = new String[] { "xdg-open", uri.toString() };
final int res = Runtime.getRuntime().exec(cmdarray).waitFor();
if (res != 0)
throw new IOException("error (" + res + ") executing " + Arrays.asList(cmdarray));
public static boolean isDesktopDesirable(Desktop.Action action) {
// apparently the JRE just checks if gnome libs are available (e.g. open Nautilus in XFCE)
return !(action == Desktop.Action.BROWSE && OSFamily.getInstance() == OSFamily.Linux && !(DesktopEnvironment.getDE() instanceof Gnome));
}
 
public static void browse(URI uri) throws IOException {
browse(Objects.requireNonNull(uri), null);
}
 
public static void openFile(File f) throws IOException {
675,17 → 720,67
return Files.readAllBytes(f.toPath());
}
 
/**
* Write the passed string with default charset to the passed file, truncating it.
*
* @param s the string.
* @param f the file.
* @throws IOException if an error occurs.
* @deprecated use {@link #writeUTF8(Path, String, OpenOption...)} or
* {@link #write2Step(String, Path)}
*/
public static void write(String s, File f) throws IOException {
write(s, f, null, false);
write2Step(s, f, Charset.defaultCharset(), false);
}
 
public static void write(String s, File f, Charset charset, boolean append) throws IOException {
try (final FileOutputStream fileStream = new FileOutputStream(f, append);
final BufferedWriter w = new BufferedWriter(charset == null ? new OutputStreamWriter(fileStream) : new OutputStreamWriter(fileStream, charset))) {
w.write(s);
public static void writeUTF8(String s, File f) throws IOException {
writeUTF8(f.toPath(), s);
}
 
public static void writeUTF8(Path path, String s, OpenOption... options) throws IOException {
Files.write(path, s.getBytes(StandardCharsets.UTF_8), options);
}
 
public static void write2Step(String s, File f, Charset charset, boolean append) throws IOException {
write2Step(s, f.toPath(), charset, append);
}
 
public static void write2Step(final String s, final Path f) throws IOException {
// UTF_8 default like Files.newBufferedReader()
write2Step(s, f, StandardCharsets.UTF_8);
}
 
public static void write2Step(final String s, final Path f, final Charset charset) throws IOException {
write2Step(s, f, charset, false);
}
 
public static void write2Step(final String s, final Path f, final Charset charset, final boolean append) throws IOException {
// create temporary file in the same directory so we can move it
final Path tmpFile = Files.createTempFile(f.toAbsolutePath().getParent(), null, null);
try {
// 1. write elsewhere
final byte[] bs = charset == null ? s.getBytes() : s.getBytes(charset);
if (append) {
// REPLACE_EXISTING since tmpFile exists
Files.copy(f, tmpFile, StandardCopyOption.REPLACE_EXISTING);
Files.write(tmpFile, bs, StandardOpenOption.APPEND);
} else {
Files.write(tmpFile, bs);
}
// 2. move into place (cannot use ATOMIC_MOVE because f might exists ; and we would need
// to handle AtomicMoveNotSupportedException)
Files.move(tmpFile, f, StandardCopyOption.REPLACE_EXISTING);
// don't try to delete if move() successful
} catch (RuntimeException | Error | IOException e) {
try {
Files.deleteIfExists(tmpFile);
} catch (Exception e1) {
e.addSuppressed(e1);
}
throw e;
}
}
 
/**
* Create a writer for the passed file, and write the XML declaration.
*
810,7 → 905,7
// 2. it sets the system flag so "dir" doesn't show the shortcut (unless you add /AS)
// 3. the shortcut is recognized as a symlink thanks to a special attribute that can get
// lost (e.g. copying in eclipse)
ps = Runtime.getRuntime().exec(new String[] { "cscript", getShortCutFile().getAbsolutePath(), link.getAbsolutePath(), target.getCanonicalPath() });
ps = startDiscardingOutput("cscript", getShortCutFile().getAbsolutePath(), link.getAbsolutePath(), target.getCanonicalPath());
res = new File(link.getParentFile(), link.getName() + ".LNK");
} else {
final String rel = FileUtils.relative(link.getAbsoluteFile().getParentFile(), target);
817,11 → 912,9
// add -f to replace existing links
// add -n so that ln -sf aDir anExistantLinkToIt succeed
final String[] cmdarray = { "ln", "-sfn", rel, link.getAbsolutePath() };
ps = Runtime.getRuntime().exec(cmdarray);
ps = startDiscardingOutput(cmdarray);
res = link;
}
// no need for output, either it succeeds or it fails
ProcessStreams.handle(ps, Action.CLOSE);
try {
final int exitValue = ps.waitFor();
if (exitValue == 0)
885,6 → 978,8
* @param prefix the prefix string to be used in generating the directory's name.
* @return the newly-created directory.
* @throws IllegalStateException if the directory could not be created.
* @deprecated use
* {@link Files#createTempDirectory(String, java.nio.file.attribute.FileAttribute...)}
*/
public static File createTempDir(final String prefix) {
final File baseDir = new File(System.getProperty("java.io.tmpdir"));
918,13 → 1013,14
for (int i = 0; i < executables.length; i++) {
final String executable = executables[i];
try {
ProcessStreams.handle(Runtime.getRuntime().exec(new String[] { executable, f.getCanonicalPath() }), Action.CLOSE);
startDiscardingOutput(executable, f.getCanonicalPath());
return;
} catch (IOException e) {
exn.addSuppressed(new IOException("unable to open with " + executable, e));
// try the next one
}
}
throw ExceptionUtils.createExn(IOException.class, "unable to open " + f + " with: " + Arrays.asList(executables), exn);
throw new IOException("unable to open " + f, exn);
}
}
 
936,20 → 1032,27
* @throws IOException if f couldn't be opened.
*/
private static final void openNative(File f) throws IOException {
openNative(f.getCanonicalPath());
}
 
private static final void openNative(URI uri) throws IOException {
openNative(uri.toASCIIString());
}
 
private static final void openNative(String param) throws IOException {
final OSFamily os = OSFamily.getInstance();
final String[] cmdarray;
if (os == OSFamily.Windows) {
cmdarray = new String[] { "cmd", "/c", "start", "\"\"", f.getCanonicalPath() };
cmdarray = new String[] { "cmd", "/c", "start", "\"\"", param };
} else if (os == OSFamily.Mac) {
cmdarray = new String[] { "open", f.getCanonicalPath() };
cmdarray = new String[] { "open", param };
} else if (os instanceof Unix) {
cmdarray = new String[] { "xdg-open", f.getCanonicalPath() };
cmdarray = new String[] { "xdg-open", param };
} else {
throw new IOException("unknown way to open " + f);
throw new IOException("unknown way to open " + param);
}
try {
final Process ps = Runtime.getRuntime().exec(cmdarray);
ProcessStreams.handle(ps, Action.CLOSE);
final Process ps = startDiscardingOutput(cmdarray);
// can wait since the command return as soon as the native application is launched
// (i.e. this won't wait 30s for OpenOffice)
final int res = ps.waitFor();
960,11 → 1063,20
}
}
 
private static final Process startDiscardingOutput(final String... command) throws IOException {
return startDiscardingOutput(new ProcessBuilder(command));
}
 
private static final Process startDiscardingOutput(final ProcessBuilder pb) throws IOException {
final Process res = pb.redirectOutput(ProcessStreams.DISCARD).redirectError(ProcessStreams.DISCARD).start();
res.getOutputStream().close();
return res;
}
 
static final boolean gnomeRunning() {
try {
final Process ps = Runtime.getRuntime().exec(new String[] { "pgrep", "-u", System.getProperty("user.name"), "nautilus" });
final Process ps = startDiscardingOutput("pgrep", "-u", System.getProperty("user.name"), "nautilus");
// no need for output, use exit status
ProcessStreams.handle(ps, Action.CLOSE);
return ps.waitFor() == 0;
} catch (Exception e) {
return false;
/trunk/OpenConcerto/src/org/openconcerto/utils/Zip.java
13,10 → 13,13
package org.openconcerto.utils;
 
import org.openconcerto.utils.cc.ITransformerExn;
 
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
27,6 → 30,9
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Set;
import java.util.function.Function;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.zip.CRC32;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
40,7 → 46,7
* @author ILM Informatique
* @see org.openconcerto.utils.Unzip
*/
public class Zip {
public class Zip implements Closeable {
 
static public byte[] deflate(final String s) throws IOException {
return deflate(s.getBytes(StringUtils.UTF8));
121,10 → 127,16
createFrom(src, dest, entriesName).close();
}
 
static public Zip createJar(final OutputStream out) {
return new Zip(out, JarOutputStream::new, JarEntry::new);
}
 
// *** Instance
 
private final OutputStream outstream;
private final ITransformerExn<OutputStream, ZipOutputStream, IOException> createZipStream;
private ZipOutputStream zos;
private final Function<String, ZipEntry> createEntry;
// is an entry open, ie addEntry() has been called but closeEntry() not yet
private boolean entryOpen;
 
144,27 → 156,40
* @param out un stream dans lequel écrire.
*/
public Zip(OutputStream out) {
this(out, ZipOutputStream::new, ZipEntry::new);
}
 
public Zip(OutputStream out, final ITransformerExn<OutputStream, ZipOutputStream, IOException> createZipStream, final Function<String, ZipEntry> createEntry) {
this.outstream = out;
this.createZipStream = createZipStream;
this.zos = null;
this.createEntry = createEntry;
this.entryOpen = false;
}
 
@Override
public synchronized void close() throws IOException {
if (this.zos != null) {
// ferme aussi le FileOutputStream
this.zos.close();
} else {
this.outstream.close();
}
}
 
// *** Ecriture
 
private synchronized ZipOutputStream getOutStream() {
private synchronized ZipOutputStream getOutStream() throws IOException {
if (this.zos == null) {
this.zos = new ZipOutputStream(this.outstream);
this.zos = this.createZipStream.transformChecked(this.outstream);
}
return this.zos;
}
 
public ZipEntry createEntry(String name) {
return this.createEntry.apply(name);
}
 
/**
* Ajoute newFile dans ce fichier. Il sera enregistré dans le zip directement à la racine.
*
173,8 → 198,15
*/
public void zip(File newFile) throws IOException {
// on ne garde que la derniere partie du chemin
this.zip(newFile.getName(), newFile);
}
 
public void zip(final String entryName, final File newFile) throws IOException {
final ZipEntry entry = this.createEntry(entryName);
// TODO call ZipEntry.setCreationTime()
entry.setTime(newFile.lastModified());
try (final BufferedInputStream ins = new BufferedInputStream(new FileInputStream(newFile))) {
this.zip(newFile.getName(), ins);
this.zip(entry, ins);
}
}
 
185,9 → 217,13
* @param in l'ajout.
* @throws IOException si in ne peut etre zippé.
*/
public synchronized void zip(String name, InputStream in) throws IOException {
this.putNextEntry(name);
public void zip(String name, InputStream in) throws IOException {
this.zip(this.createEntry(name), in);
}
 
public synchronized void zip(final ZipEntry entry, InputStream in) throws IOException {
this.putNextEntry(entry);
 
byte b[] = new byte[512];
int len = 0;
while ((len = in.read(b)) != -1) {
215,7 → 251,7
* @throws IOException if an error occurs.
*/
public synchronized void zipNonCompressed(String name, byte[] in) throws IOException {
final ZipEntry entry = new ZipEntry(name);
final ZipEntry entry = createEntry(name);
entry.setMethod(ZipEntry.STORED);
final CRC32 crc = new CRC32();
crc.update(in);
235,7 → 271,7
* @return a stream to write to the entry.
* @throws IOException if a pb occurs.
*/
public synchronized OutputStream createEntry(String name) throws IOException {
public synchronized OutputStream createEntryStream(String name) throws IOException {
this.putNextEntry(name);
return new BufferedOutputStream(this.getOutStream()) {
public void close() throws IOException {
246,7 → 282,7
}
 
private final synchronized void putNextEntry(String name) throws IOException, FileNotFoundException {
this.putNextEntry(new ZipEntry(name));
this.putNextEntry(createEntry(name));
}
 
private final synchronized void putNextEntry(ZipEntry entry) throws IOException, FileNotFoundException {
/trunk/OpenConcerto/src/org/openconcerto/utils/function/FunctionalSupplier.java
New file
0,0 → 1,74
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.function;
 
import java.util.Objects;
import java.util.function.Supplier;
 
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
 
/**
* A Supplier that always returns the same value. Functional in the sense, that for the same input
* (indeed none in this case) it returns the same output.
*
* @author sylvain
* @param <T> the type of results supplied by this supplier.
*/
@ThreadSafe
public abstract class FunctionalSupplier<T> implements Supplier<T> {
// Not an interface to restrict implementations (even inadvertently with the :: notation)
 
@ThreadSafe
static final class LazyValue<T> extends FunctionalSupplier<T> {
 
private final Supplier<T> supplier;
@GuardedBy("this")
private boolean set;
@GuardedBy("this")
private T value;
 
LazyValue(final Supplier<T> supplier) {
super();
this.supplier = Objects.requireNonNull(supplier);
this.set = false;
}
 
@Override
public synchronized T get() {
if (!this.set) {
this.value = this.supplier.get();
this.set = true;
}
return this.value;
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " for " + this.supplier;
}
}
 
static public final <U> FunctionalSupplier<U> get(Supplier<U> orig) {
return orig instanceof FunctionalSupplier ? (FunctionalSupplier<U>) orig : new LazyValue<>(orig);
}
 
static public final <U> ConstantSupplier<U> getConstant(U value) {
return new ConstantSupplier<>(value);
}
 
// not public to restrict implementations
FunctionalSupplier() {
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/function/ConstantSupplier.java
New file
0,0 → 1,62
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.function;
 
import java.util.Objects;
 
import net.jcip.annotations.Immutable;
 
/**
* A supplier returning a constant value.
*
* @author sylvain
* @param <T> the type of results supplied by this supplier.
* @see FunctionalSupplier#getConstant(Object)
*/
@Immutable
public final class ConstantSupplier<T> extends FunctionalSupplier<T> {
private final T value;
 
ConstantSupplier(final T value) {
super();
this.value = value;
}
 
@Override
public T get() {
return this.value;
}
 
@Override
public int hashCode() {
return this.value == null ? 0 : this.value.hashCode();
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ConstantSupplier<?> other = (ConstantSupplier<?>) obj;
return Objects.equals(this.value, other.value);
}
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " of " + this.get();
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/Step.java
13,6 → 13,7
package org.openconcerto.xml;
 
import org.openconcerto.utils.Tuple2.List2;
import org.openconcerto.utils.cc.IPredicate;
import org.openconcerto.xml.SimpleXMLPath.Node;
 
50,6 → 51,11
return ANY_ATTRIBUTE;
}
 
public static Step<Attribute> createAttributeStepFromQualifiedName(final String qName) {
final List2<String> splitName = XMLUtils.splitQualifiedName(qName);
return createAttributeStep(splitName.get1(), splitName.get0());
}
 
public static Step<Attribute> createAttributeStep(final String name, final String ns) {
return createAttributeStep(name, ns, null);
}
67,6 → 73,11
return ANY_CHILD_ELEMENT;
}
 
public static Step<Element> createElementStepFromQualifiedName(final String qName) {
final List2<String> splitName = XMLUtils.splitQualifiedName(qName);
return createElementStep(splitName.get1(), splitName.get0());
}
 
public static Step<Element> createElementStep(final String name, final String ns) {
return createElementStep(name, ns, null);
}
160,6 → 171,13
return res;
}
 
final List<String> getValues(List<T> jdom) {
final List<String> res = new ArrayList<>();
for (final T n : jdom)
res.add(this.node.getValue(n));
return res;
}
 
@Override
public final String toString() {
return this.getClass().getSimpleName() + " " + this.getAxis() + " " + this.ns + ":" + this.name;
/trunk/OpenConcerto/src/org/openconcerto/xml/XMLUtils.java
13,6 → 13,8
package org.openconcerto.xml;
 
import org.openconcerto.utils.Tuple2.List2;
 
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
117,6 → 119,31
return sb.toString();
}
 
/**
* Split prefix and local name.
*
* @param qName a qualified name, e.g. "ns:foo" or "foo".
* @return first the prefix (<code>null</code> if none), then the local name
* @throws IllegalArgumentException if invalid syntax.
* @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Qualified Names</a>
*/
public static List2<String> splitQualifiedName(final String qName) throws IllegalArgumentException {
final int indexOfColon = qName.indexOf(':');
if (indexOfColon < 0)
return new List2<>(null, qName);
 
if (indexOfColon == 0)
throw new IllegalArgumentException("Starts with colon : '" + qName + "'");
final int l = qName.length();
assert indexOfColon < l;
if (indexOfColon == l - 1)
throw new IllegalArgumentException("Ends with colon : '" + qName + "'");
final int secondColon = qName.indexOf(':', indexOfColon + 1);
if (secondColon >= 0)
throw new IllegalArgumentException("Two colons : '" + qName + "'");
return new List2<>(qName.substring(0, indexOfColon), qName.substring(indexOfColon + 1));
}
 
public static final void skipToEndElement(final XMLStreamReader reader) throws XMLStreamException {
if (!reader.isStartElement())
throw new IllegalStateException("Not at a start of an element : " + reader.getEventType() + ", " + reader.getLocation());
/trunk/OpenConcerto/src/org/openconcerto/xml/SimpleXMLPath.java
152,6 → 152,22
return this.lastItem.nextNodes(currentNodes);
}
 
public final List<String> selectValues(final Object n) {
return this.selectValues(Collections.singletonList(n));
}
 
/**
* Return the string-value properties of the selected nodes.
*
* @param nodes the context.
* @return the string values.
* @see <a href="https://www.w3.org/TR/xpath-datamodel/#dm-string-value">string-value</a>
*/
public final List<String> selectValues(final List<?> nodes) {
final List<T> lastNodes = this.selectNodes(nodes);
return this.lastItem.getValues(lastNodes);
}
 
// encapsulate differences about JDOM nodes
static abstract class Node<T> {
 
183,6 → 199,9
// viva jdom who doesn't have a common interface for getName() and getNS()
abstract T filter(final T elem, final String name, final String ns);
 
// Returns the XPath 1.0 string value of the passed node
protected abstract String getValue(T n);
 
@Override
public final String toString() {
return this.getClass().getSimpleName();
209,7 → 228,12
return null;
return elem;
}
 
@Override
protected String getValue(Attribute n) {
return n.getValue();
}
}
 
static class ElementNode extends Node<Element> {
 
257,5 → 281,10
return null;
return elem;
}
 
@Override
protected String getValue(Element n) {
return n.getValue();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/xml/XPathUtils.java
47,11 → 47,7
*/
public final static String namespace(String qName) {
qName = basename(qName);
final int colonIndex = qName.lastIndexOf(':');
if (colonIndex < 0)
return null;
else
return qName.substring(0, colonIndex);
return XMLUtils.splitQualifiedName(qName).get0();
}
 
/**
63,7 → 59,7
*/
public final static String localName(String qName) {
qName = basename(qName);
return qName.substring(qName.lastIndexOf(':') + 1);
return XMLUtils.splitQualifiedName(qName).get1();
}
 
private XPathUtils() {
/trunk/OpenConcerto/src/org/openconcerto/xml/AbstractXMLDecoder.java
127,6 → 127,7
final String propAttr = getAttributeValue(elem, "property");
final String indexAttr = getAttributeValue(elem, "index");
final String methodAttr = getAttributeValue(elem, "method");
final String fieldAttr = getAttributeValue(elem, "field");
 
// statement or expression
final Object res = evalContainer(elem, context, ids, new ExnTransformer<List<Object>, Object, Exception>() {
157,8 → 158,11
throw new IllegalStateException("use index with neither List nor array: " + target);
} else if (methodAttr != null) {
res = invoke(target, methodAttr, args);
} else
} else if (fieldAttr != null) {
res = ((Class<?>) target).getField(fieldAttr).get(null);
} else {
res = getCtor((Class<?>) target, args).newInstance(args.toArray());
}
return res;
}
});
283,6 → 287,8
return cacheRes.getRes();
 
final Constructor res = findCtor(clazz, actualClasses);
if (res == null)
throw new IllegalStateException("No constructor in " + clazz + " for arguments " + actualClasses);
cacheCtor.put(key, res);
return res;
}
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListPanel.java
371,7 → 371,11
this.addAncestorListener(new AncestorListener() {
 
public void ancestorAdded(AncestorEvent event) {
if (!TodoListPanel.this.model.isAutoRefreshing()) {
TodoListPanel.this.model.addModelStateListener(TodoListPanel.this);
TodoListPanel.this.model.enableUpdate();
}
}
 
public void ancestorMoved(AncestorEvent event) {
}
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListModel.java
220,8 → 220,8
if (!isHistoryVisible()) {
Where w3 = new Where(tableTache.getField("FAIT"), "=", Boolean.FALSE);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
// Voir les taches qui ont été faite les 15 dernières secondes
cal.add(Calendar.SECOND, -15);
Where w4 = new Where(tableTache.getField("DATE_FAIT"), "<>", (Object) null);
w4 = w4.and(new Where(tableTache.getField("DATE_FAIT"), ">", cal.getTime()));
w3 = w3.or(w4);
394,6 → 394,17
fireTableRowsDeleted(row, row);
}
 
public boolean isAutoRefreshing() {
return !this.stop;
}
 
public void enableUpdate() {
if (this.stop == true) {
this.stop = false;
launchUpdaterThread();
}
}
 
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
synchronized (this.elements) {
/trunk/OpenConcerto/src/org/openconcerto/task/config/ComptaBasePropsConfiguration.java
43,7 → 43,6
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
67,16 → 66,7
} else if (wdFile.isFile()) {
confFile = wdFile;
} else {
// we added organisation name, so migrate preferences
final File prefsFolder = BaseDirs.create(info).getPreferencesFolder();
if (!prefsFolder.exists()) {
try {
final File oldDir = DesktopEnvironment.getDE().getPreferencesFolder(info.getName());
Configuration.migrateToNewDir(oldDir, prefsFolder);
} catch (IOException ex) {
throw new IllegalStateException("Couldn't migrate preferences dir", ex);
}
}
confFile = new File(prefsFolder, "main.properties");
}
return confFile;
/trunk/OpenConcerto/src/org/openconcerto/erp/config/translation_fr.xml
189,7 → 189,9
<!-- Matching -->
<action id="financing.accouning.entries.source.show" label="Voir la source" />
<action id="financing.accouning.entries.match" label="Lettrer" />
<action id="financing.accouning.entries.match.partial" label="Lettrer partiel" />
<action id="financing.accouning.entries.unmatch" label="Délettrer" />
<action id="financing.accouning.entries.unmatch.partial" label="Délettrer partiel" />
<!-- Invoice -->
<item id="sales.invoice.number" label="Numéro" />
<item id="sales.invoice.date" label="Date" />
250,8 → 252,18
<item id="customerrelationship.customer.identifier" label="Code" />
<item id="customerrelationship.customer.date" label="Date" />
<item id="customerrelationship.customer.customproduct" label="Réf. Art. Interne" />
<item id="customerrelationship.customer.customtarif" label="Remises client" />
<item id="customerrelationship.customer.customtarif" label="Remises client sur article" />
<item id="customerrelationship.customer.customfamilytarif" label="Remises client sur famille d'article" />
 
<!-- Agence -->
<item id="customerrelationship.customer.agency" label="Agences" />
<item id="customerrelationship.customer.agencies" label="Liste des agences" />
<item id="customerrelationship.customer.agency.designation" label="Designation" />
<item id="customerrelationship.customer.agency.phone1" label="Téléphone" />
<item id="customerrelationship.customer.agency.email" label="E-Mail" />
<item id="customerrelationship.customer.agency.fax" label="Fax" />
<item id="customerrelationship.customer.agency.customer" label="Client" />
<item id="customerrelationship.customer.agency.address" label="Adresse de l'agence" />
 
<!-- Currency -->
<item id="currency.USD" label="Dollar américain" />
/trunk/OpenConcerto/src/org/openconcerto/erp/config/mappingCompta_fr.xml
12,6 → 12,22
<FIELD name="MONTANT" label="Montant" />
<FIELD name="ID_MOUVEMENT" label="Mouvement" />
</element>
<element refid="customerrelationship.customer.category" nameClass="feminine" name="catégorie de client">
<FIELD name="name" label="Nom" />
</element>
<element refid="sales.customer.product.qty.price" nameClass="masculine" name="tarif client">
<FIELD name="QUANTITE" label="Quantité" />
<FIELD name="ID_ARTICLE" label="Article" />
<FIELD name="ID_CLIENT" label="Client" />
<FIELD name="POURCENT_REMISE" label="% remise" />
</element>
<element refid="sales.customer.product.family.qty.price" nameClass="masculine"
name="tarif famille d'article client">
<FIELD name="QUANTITE" label="Quantité" />
<FIELD name="ID_FAMILLE_ARTICLE" label="Famille article" />
<FIELD name="ID_CLIENT" label="Client" />
<FIELD name="POURCENT_REMISE" label="% remise" />
</element>
<element refid="address" nameClass="feminine" name="adresse">
<FIELD name="TYPE" label="Type" />
<FIELD name="LIBELLE" label="Libellé" />
291,6 → 307,7
<FIELD name="T_DEVISE" label="Total Devise" />
<FIELD name="ID_MODELE" label="Modèle" />
<FIELD name="T_ECO_CONTRIBUTION" label="Dont Eco-Contrib." />
<FIELD name="ID_TAXE_PORT" label="Taxe sur port" />
</element>
<element refid="sales.credit.item" nameClass="masculine" name="élément d'avoir" namePlural="éléments d'avoir">
<FIELD name="ID_DEPOT_STOCK" label="Dépôt Stock" />
365,6 → 382,7
<FIELD name="DATE" label="Date d'intervention" />
<FIELD name="DATE_FIN" label="Date de fin d'intervention" />
<FIELD name="POURCENT_SERVICE" label="Pourcentage service" />
<FIELD name="ID_TAXE_PORT" label="Taxe sur port" />
</element>
<element refid="supplychain.credit.note" nameClass="feminine" name="facture d'avoir fournisseur"
namePlural="factures d'avoir fournisseur">
467,7 → 485,7
<FIELD name="ID_TAXE" label="Taxe" />
<FIELD name="POIDS" label="Poids UV net" />
<FIELD name="PRIX_METRIQUE_VT_1" label="P.V. UV HT" />
<FIELD name="PRIX_METRIQUE_HA_1" label="P.A. UV² HT" />
<FIELD name="PRIX_METRIQUE_HA_1" label="P.A. UV HT" />
<FIELD name="VALEUR_METRIQUE_1" label="Longueur par défaut" />
<FIELD name="ID_METRIQUE_1" label="Métrique" />
<FIELD name="PRIX_METRIQUE_VT_2" label="P.V. HT au mètre" />
486,6 → 504,7
<FIELD name="ID_STYLE" label="Style" />
<FIELD name="SERVICE" label="Service" />
<FIELD name="ID_MODE_VENTE_ARTICLE" label="Mode de vente" />
<FIELD name="ID_FAMILLE_ARTICLE" label="Famille" />
</element>
<element refid="sales.shipment.delivery.note" nameClass="masculine" name="bon de livraison"
namePlural="bons de livraison">
516,6 → 535,7
<FIELD name="ID_MODELE" label="Modèle" />
<FIELD name="T_ECO_CONTRIBUTION" label="Dont Eco-Contrib." />
<FIELD name="invoiceProgress" label="Avancement facturation" />
<FIELD name="ID_COMMERCIAL" label="Commercial" />
</element>
<element refid="sales.shipment.item" nameClass="masculine" name="élément de bon de livraison"
namePlural="éléments de bon de livraison">
1011,7 → 1031,7
</element>
<element refid="humanresources.payroll.contract.employe" nameClass="masculine" name="contrat salarié"
namePlural="contrats salariés">
 
<FIELD name="ID_DIPLOME_PREPARE" label="Diplôme préparé (S21.G00.30.025)" />
<FIELD name="ID_CODE_AMENAGEMENT_PARTIEL" label="Aménagement temps partiel (S21.G00.40.078)" />
<FIELD name="ID_CODE_SUSPENSION" label="Motif de suspension (S21.G00.65.001)" />
<FIELD name="DATE_FIN_SUSPENSION" label="Fin de supension (S21.G00.65.003)" />
1216,8 → 1236,10
<FIELD name="T_PA_HT" label="Total achat HT" />
<FIELD name="T_POIDS" label="Poids total net" />
<FIELD name="ID_MODE_VENTE_ARTICLE" label="Mode de vente" />
 
<FIELD name="POURCENT_ACOMPTE" label="% Acompte" />
<FIELD name="LIVRE" label="Livré" />
<FIELD name="QTE_LIVREE" label="Qté livrée" />
<FIELD name="LIVRE_FORCED" label="Livraison forcée" />
</element>
<element refid="humanresources.employe.salesman" nameClass="masculine" name="commercial">
<FIELD name="ID_POLE_PRODUIT" label="Pôle produit" />
1310,6 → 1332,7
<FIELD name="ID_FABRICANT" label="Fabricant" />
<FIELD name="ID_UNITE_VENTE" label="Unité de vente" />
<FIELD name="QTE" label="Quantité" />
<FIELD name="QTE_RECUE" label="Qté recues" />
<FIELD name="QTE_UNITAIRE" label="Quantité unitaire" />
<FIELD name="REPERE" label="Repère" />
<FIELD name="EN_STOCK" label="En stock" />
1713,6 → 1736,7
</element>
<element refid="sales.order.facturation" nameClass="masculine" name="terme de facturation de commande client"
namePlural="termes de facturation commandes clients">
<FIELD name="NOM" label="Désignation" />
<FIELD name="ID_SAISIE_VENTE_FACTURE" label="Facture" />
<FIELD name="ID_COMMANDE_CLIENT" label="Commande" />
<FIELD name="ID_TYPE_REGLEMENT" label="Type règlement" />
1729,7 → 1753,8
namePlural="factures fournisseur">
<FIELD name="DATE_REGLEMENT" label="Date de règlement" />
<FIELD name="TVA_ADJUSTMENT" label="Ajustement de TVA" />
<FIELD name="ID_AVOIR_FOURNISSEUR" label="Avoir" />
<FIELD name="ID_AVOIR_FOURNISSEUR" label="Avoir N°1" />
<FIELD name="ID_AVOIR_FOURNISSEUR_2" label="Avoir N°2" />
<FIELD name="NET_A_PAYER" label="Net à payer" />
<FIELD name="ID_TAXE_PORT" label="Taxe sur port" />
<FIELD name="PORT_HT" label="Frais de port HT" />
1770,6 → 1795,7
<FIELD name="ID_CODE_FOURNISSEUR" label="Code Fournisseur" />
<FIELD name="ID_UNITE_VENTE" label="Unité de vente" />
<FIELD name="ID_ARTICLE" label="Article" />
<FIELD name="ID_FAMILLE_ARTICLE" label="Famille" />
<FIELD name="ID_DEVISE" label="Devise" />
<FIELD name="PA_DEVISE" label="PA Devise" />
<FIELD name="PA_DEVISE_T" label="PA Devise Total" />
2041,6 → 2067,7
<FIELD name="DATE" label="Date" />
<FIELD name="ID_ARTICLE" label="Article" />
<FIELD name="REEL" label="Réel" />
<FIELD name="ID_STOCK" label="Stock" />
</element>
<element refid="finance.accounting.account.kind" nameClass="feminine" name="nature du compte"
namePlural="natures du compte">
2338,7 → 2365,7
<FIELD name="ANALYTIQUE" label="Analytique" />
<FIELD name="NUMERO" label="N° compte" />
<FIELD name="NOM" label="Compte" />
<FIELD name="NOM_ECRITURE" label="libellé écriture" />
<FIELD name="NOM_ECRITURE" label="Libellé écriture" />
<FIELD name="DEBIT" label="Débit" />
<FIELD name="CREDIT" label="Crédit" />
<FIELD name="ID_ECRITURE" label="Ecriture" />
/trunk/OpenConcerto/src/org/openconcerto/erp/config/fieldmapping.xml
7,7 → 7,14
<field id="customerrelationship.country" name="ID_PAYS" />
<field id="customerrelationship.phone" name="PHONE" />
</table>
 
<table id="customerrelationship.customer.agency" name="AGENCE">
<field id="customerrelationship.customer.agency.designation" name="DESIGNATION" />
<field id="customerrelationship.customer.agency.phone1" name="TEL_1" />
<field id="customerrelationship.customer.agency.email" name="EMAIL" />
<field id="customerrelationship.customer.agency.fax" name="FAX" />
<field id="customerrelationship.customer.agency.customer" name="ID_CLIENT" />
<field id="customerrelationship.customer.agency.address" name="ID_ADRESSE" />
</table>
<table id="sales.invoice" name="SAISIE_VENTE_FACTURE">
<field id="sales.invoice.number" name="NUMERO" />
<field id="sales.invoice.date" name="DATE" />
/trunk/OpenConcerto/src/org/openconcerto/erp/config/DSNInstallationUtils.java
161,6 → 161,33
}
}
 
if (!root.contains("DIPLOME_PREPARE")) {
final SQLCreateTable createTableDiplome = new SQLCreateTable(root, "DIPLOME_PREPARE");
createTableDiplome.addVarCharColumn("CODE", 25);
createTableDiplome.addVarCharColumn("NOM", 512);
 
try {
root.getBase().getDataSource().execute(createTableDiplome.asString());
insertUndef(createTableDiplome);
root.refetchTable("DIPLOME_PREPARE");
root.getSchema().updateVersion();
 
final SQLTable table = root.getTable("DIPLOME_PREPARE");
List<Tuple2<String, String>> v = new ArrayList<Tuple2<String, String>>();
v.add(Tuple2.create("03", "Niveau de formation équivalent au CAP (certificat d'aptitude professionnelle) ou au BEP (brevet d'études professionnelles)"));
v.add(Tuple2.create("04", "Formation de niveau du bac (général, technologique ou professionnel), du brevet de technicien (BT) ou du brevet professionnel"));
v.add(Tuple2.create("05", "Formation de niveau bac+2 : licence 2, BTS (brevet de technicien supérieur), DUT (diplôme universitaire de technologie), etc."));
v.add(Tuple2.create("06", "Formation de niveau bac+3 et bac+4 : licence 3, licence professionnelle, master 1, etc."));
v.add(Tuple2.create("07", "Formation de niveau bac+5 : master 2, diplôme d'études approfondies, diplôme d'études supérieures spécialisées, diplôme d'ingénieur, etc."));
v.add(Tuple2.create("08", "Formation de niveau bac+8 : doctorat, habilitation à diriger des recherches, etc. "));
 
insertValues(v, table);
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table " + "DIPLOME_PREPARE", ex);
}
}
 
 
if (!root.contains("TYPE_PREAVIS")) {
final SQLCreateTable createTableMotif = new SQLCreateTable(root, "TYPE_PREAVIS");
createTableMotif.addVarCharColumn("CODE", 25);
1652,6 → 1679,14
root.getSchema().updateVersion();
}
 
if (!tableContrat.contains("ID_DIPLOME_PREPARE")) {
updateContrat = true;
AlterTable alter = new AlterTable(tableContrat);
alter.addForeignColumn("ID_DIPLOME_PREPARE", root.findTable("DIPLOME_PREPARE"));
root.getBase().getDataSource().execute(alter.asString());
root.getSchema().updateVersion();
}
 
if (updateContrat) {
root.refetchTable("CONTRAT_SALARIE");
tableContrat = root.findTable("CONTRAT_SALARIE");
/trunk/OpenConcerto/src/org/openconcerto/erp/config/ComptaPropsConfiguration.java
26,6 → 26,7
import org.openconcerto.erp.core.common.element.SocieteCommonSQLElement;
import org.openconcerto.erp.core.common.element.StyleSQLElement;
import org.openconcerto.erp.core.common.element.TitrePersonnelSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.AgenceSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ClientDepartementSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ComptaContactSQLElement.ContactAdministratifSQLElement;
import org.openconcerto.erp.core.customerrelationship.customer.element.ComptaContactSQLElement.ContactFournisseurSQLElement;
122,6 → 123,7
import org.openconcerto.erp.core.humanresources.payroll.element.CumulsCongesSQLElement;
import org.openconcerto.erp.core.humanresources.payroll.element.CumulsPayeSQLElement;
import org.openconcerto.erp.core.humanresources.payroll.element.DSNNatureSQLElement;
import org.openconcerto.erp.core.humanresources.payroll.element.DiplomePrepareSQLElement;
import org.openconcerto.erp.core.humanresources.payroll.element.FichePayeElementSQLElement;
import org.openconcerto.erp.core.humanresources.payroll.element.FichePayeSQLElement;
import org.openconcerto.erp.core.humanresources.payroll.element.ImpressionRubriqueSQLElement;
176,6 → 178,7
import org.openconcerto.erp.core.sales.product.element.ArticleFournisseurSecondaireSQLElement;
import org.openconcerto.erp.core.sales.product.element.ArticleTarifSQLElement;
import org.openconcerto.erp.core.sales.product.element.CoutRevientSQLElement;
import org.openconcerto.erp.core.sales.product.element.CustomerProductFamilyQtyPriceSQLElement;
import org.openconcerto.erp.core.sales.product.element.CustomerProductQtyPriceSQLElement;
import org.openconcerto.erp.core.sales.product.element.EcoContributionSQLElement;
import org.openconcerto.erp.core.sales.product.element.FamilleArticleSQLElement;
273,7 → 276,9
import org.openconcerto.erp.injector.BonFactureEltSQLInjector;
import org.openconcerto.erp.injector.BonFactureSQLInjector;
import org.openconcerto.erp.injector.BonReceptionFactureFournisseurSQLInjector;
import org.openconcerto.erp.injector.BrEltFactEltSQLInjector;
import org.openconcerto.erp.injector.BrFactureAchatSQLInjector;
import org.openconcerto.erp.injector.CmdEltFactEltSQLInjector;
import org.openconcerto.erp.injector.CommandeBlEltSQLInjector;
import org.openconcerto.erp.injector.CommandeBlSQLInjector;
import org.openconcerto.erp.injector.CommandeBrEltSQLInjector;
786,6 → 791,7
dir.addSQLElement(TypeTauxPasSQLElement.class, root);
dir.addSQLElement(CodeAmenagementPartielSQLElement.class, root);
dir.addSQLElement(CodeSuspensionSQLElement.class, root);
dir.addSQLElement(DiplomePrepareSQLElement.class, root);
 
// ECO
dir.addSQLElement(FamilleEcoContributionSQLElement.class, root);
832,6 → 838,7
dir.addSQLElement(AttachmentSQLElement.class);
 
dir.addSQLElement(CustomerProductQtyPriceSQLElement.class);
dir.addSQLElement(CustomerProductFamilyQtyPriceSQLElement.class);
dir.addSQLElement(EtatStockSQLElement.class);
dir.addSQLElement(EtatStockItemSQLElement.class);
dir.addSQLElement(ArticleTarifSQLElement.class);
854,6 → 861,7
dir.addSQLElement(ContactSalarieSQLElement.class);
dir.addSQLElement(new TitrePersonnelSQLElement());
dir.addSQLElement(new ContactSQLElement());
dir.addSQLElement(new AgenceSQLElement(this.getRootSociete()));
dir.addSQLElement(new SaisieKmItemSQLElement());
dir.addSQLElement(new EcritureSQLElement());
 
1105,6 → 1113,8
new DevisBlEltSQLInjector(rootSociete);
new DevisBlSQLInjector(rootSociete);
new CommandeBlEltSQLInjector(rootSociete);
new CmdEltFactEltSQLInjector(rootSociete);
new BrEltFactEltSQLInjector(rootSociete);
new CommandeBrEltSQLInjector(rootSociete);
new CommandeBlSQLInjector(rootSociete);
new BonFactureSQLInjector(rootSociete);
/trunk/OpenConcerto/src/org/openconcerto/erp/config/DefaultMenuConfiguration.java
96,6 → 96,7
import org.openconcerto.erp.core.reports.stat.action.EvolutionCmdCumulAction;
import org.openconcerto.erp.core.reports.stat.action.EvolutionMargeAction;
import org.openconcerto.erp.core.reports.stat.action.ReportingCommercialAction;
import org.openconcerto.erp.core.reports.stat.action.ReportingCommercialFournisseurAction;
import org.openconcerto.erp.core.reports.stat.action.VenteArticleFamilleGraphAction;
import org.openconcerto.erp.core.reports.stat.action.VenteArticleGraphAction;
import org.openconcerto.erp.core.reports.stat.action.VenteArticleMargeGraphAction;
117,6 → 118,7
import org.openconcerto.erp.core.sales.invoice.action.NouveauSaisieVenteComptoirAction;
import org.openconcerto.erp.core.sales.invoice.action.NouveauSaisieVenteFactureAction;
import org.openconcerto.erp.core.sales.invoice.report.ReportingClientPanel;
import org.openconcerto.erp.core.sales.invoice.report.SituationCompteClientPanel;
import org.openconcerto.erp.core.sales.order.action.ListeDesCommandesClientAction;
import org.openconcerto.erp.core.sales.order.action.ListeDesCommandesClientItemsAction;
import org.openconcerto.erp.core.sales.order.action.ListeDesElementsACommanderClientAction;
391,7 → 393,6
gCustomer.addItem("customer.payment.list");
gCustomer.addItem("customer.payment.followup.list");
gCustomer.addItem("customer.payment.check.pending.list");
gCustomer.addItem("customer.payment.check.deposit.list");
gCustomer.addItem("customer.payment.check.pending.create");
gCustomer.addItem("customer.payment.check.deposit.list");
gCustomer.addItem("customer.credit.check.list");
423,6 → 424,7
group.addItem("order.list.reporting");
group.addItem("sales.list.report");
group.addItem("sales.list.salesman.report");
group.addItem("sales.list.salesman.supplier.report");
group.addItem("sales.product.graph");
group.addItem("sales.product.margin.graph");
group.addItem("sales.product.family.graph");
731,6 → 733,7
mManager.putAction(new EvolutionCmdCumulAction(), "sales.graph.cmd.cumulate");
 
mManager.putAction(new ReportingCommercialAction(conf.getRootSociete()), "sales.list.salesman.report");
mManager.putAction(new ReportingCommercialFournisseurAction(conf), "sales.list.salesman.supplier.report");
 
mManager.putAction(new EvolutionMargeAction(), "sales.margin.graph");
mManager.putAction(new GenReportingVenteAction(false), "sales.list.reporting");
788,6 → 791,15
 
}
}, "customer.payment.report");
mManager.putAction(new AbstractAction("Situation Client") {
@Override
public void actionPerformed(ActionEvent arg0) {
 
PanelFrame frame = new PanelFrame(new SituationCompteClientPanel(conf), "Situation client");
frame.setVisible(true);
 
}
}, "customer.payment.details");
mManager.putAction(new ListeDesEncaissementsAction(), "customer.payment.list");
mManager.putAction(new ListeDesRelancesAction(), "customer.payment.followup.list");
mManager.putAction(new ListeDesChequesAEncaisserAction(), "customer.payment.check.pending.list");
/trunk/OpenConcerto/src/org/openconcerto/erp/config/update/Updater_1_5.java
29,6 → 29,7
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.erp.core.supplychain.stock.element.StockItem;
import org.openconcerto.sql.changer.convert.AddMDFields;
import org.openconcerto.sql.model.AliasedTable;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLField.Properties;
80,6 → 81,24
tableCompte.fetchFields();
}
 
// Champ obsolete sur compte
SQLTable tableTitre = root.getTable("TITRE_PERSONNEL");
if (!tableTitre.contains("OBSOLETE")) {
final AlterTable alter = new AlterTable(tableTitre);
alter.addBooleanColumn("OBSOLETE", Boolean.FALSE, false);
tableTitre.getBase().getDataSource().execute(alter.asString());
tableTitre.getSchema().updateVersion();
tableTitre.fetchFields();
final UpdateBuilder updBuilder = new UpdateBuilder(tableTitre).setObject(tableTitre.getField("OBSOLETE"), Boolean.TRUE);
updBuilder.setWhere(new Where(tableTitre.getField("CODE"), "=", "Mlle"));
tableTitre.getBase().getDataSource().execute(updBuilder.asString());
final UpdateBuilder updBuilder2 = new UpdateBuilder(tableTitre).setObject(tableTitre.getField("CODE"), "M.");
updBuilder2.setWhere(new Where(tableTitre.getField("CODE"), "=", "Mr"));
 
tableTitre.getBase().getDataSource().execute(updBuilder2.asString());
 
}
 
// Transaction du solde
if (!root.contains(COMPTE_CLIENT_TRANSACTION)) {
final SQLCreateTable createTable = new SQLCreateTable(root, COMPTE_CLIENT_TRANSACTION);
231,7 → 250,7
createTable.addVarCharColumn("TAG", 128);
createTable.addIntegerColumn("VERSION", 0);
createTable.addVarCharColumn("HASH", 32);
 
createTable.addBooleanColumn("ENCRYPTED", Boolean.FALSE, false);
try {
root.getBase().getDataSource().execute(createTable.asString());
InstallationPanel.insertUndef(createTable);
267,7 → 286,13
tableAttachment.getSchema().updateVersion();
tableAttachment.fetchFields();
}
 
if (!tableAttachment.contains("ENCRYPTED")) {
final AlterTable alter = new AlterTable(tableAttachment);
alter.addBooleanColumn("ENCRYPTED", Boolean.FALSE, false);
tableAttachment.getBase().getDataSource().execute(alter.asString());
tableAttachment.getSchema().updateVersion();
tableAttachment.fetchFields();
}
List<String> gedTable = Arrays.asList("CLIENT", "MOUVEMENT", "FOURNISSEUR", "ARTICLE", "FACTURE_FOURNISSEUR", "SAISIE_VENTE_FACTURE", "SALARIE");
for (String string : gedTable) {
SQLTable tableGED = root.getTable(string);
409,7 → 434,6
root.getSchema().updateVersion();
UpdateBuilder build = new UpdateBuilder(tableCmdFElt);
build.setObject("RECU", Boolean.FALSE);
build.set("QTE_RECUE", "\"QTE\"*\"QTE_UNITAIRE\"");
 
Where w = Where.createRaw(tableCmdFElt.getField("QTE_RECUE").getQuotedName() + " < (" + tableCmdFElt.getField("QTE").getQuotedName() + "*"
+ tableCmdFElt.getField("QTE_UNITAIRE").getQuotedName() + ")", tableCmdFElt.getField("QTE_UNITAIRE"), tableCmdFElt.getField("QTE"), tableCmdFElt.getField("QTE_RECUE"));
2286,8 → 2310,118
tableEtatStock.getSchema().updateVersion();
tableEtatStock.fetchFields();
}
 
// Création de la table Agence
if (!root.contains("AGENCE")) {
SQLCreateTable createAgence = new SQLCreateTable(root, "AGENCE");
createAgence.addVarCharColumn("DESIGNATION", 256);
createAgence.addVarCharColumn("TEL_1", 256);
createAgence.addVarCharColumn("EMAIL", 256);
createAgence.addVarCharColumn("FAX", 256);
createAgence.addForeignColumn("ID_CLIENT", root.findTable("CLIENT"));
createAgence.addForeignColumn("ID_ADRESSE", root.findTable("ADRESSE"));
 
try {
// test
root.getBase().getDataSource().execute(createAgence.asString());
root.refetchTable("AGENCE");
SQLRowValues rowVals = new SQLRowValues(root.getTable("AGENCE"));
SQLRow rowInserted = rowVals.commit();
SQLTable.setUndefID(root.getSchema(), "AGENCE", rowInserted.getID());
tableDevis.getSchema().updateVersion();
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table AGENCE", ex);
}
}
// Tarification client par famille article
if (root.getTable("TARIF_FAMILLE_ARTICLE_CLIENT") == null) {
final SQLCreateTable createTableQtyTarif = new SQLCreateTable(root, "TARIF_FAMILLE_ARTICLE_CLIENT");
createTableQtyTarif.addForeignColumn("ID_FAMILLE_ARTICLE", root.getTable("FAMILLE_ARTICLE"));
createTableQtyTarif.addForeignColumn("ID_CLIENT", root.getTable("CLIENT"));
createTableQtyTarif.addDecimalColumn("QUANTITE", 16, 3, BigDecimal.ONE, false);
createTableQtyTarif.addDecimalColumn("POURCENT_REMISE", 16, 3, null, true);
// createTableQtyTarif.addDecimalColumn("PRIX_METRIQUE_VT_1", 16, 6, null, true);
try {
root.getBase().getDataSource().execute(createTableQtyTarif.asString());
InstallationPanel.insertUndef(createTableQtyTarif);
root.refetchTable("TARIF_FAMILLE_ARTICLE_CLIENT");
root.getSchema().updateVersion();
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table " + "TARIF_FAMILLE_ARTICLE_CLIENT", ex);
}
}
 
// Tarification client par famille article
if (root.getTable("TARIF_FAMILLE_ARTICLE_CLIENT") == null) {
final SQLCreateTable createTableQtyTarif = new SQLCreateTable(root, "TARIF_FAMILLE_ARTICLE_CLIENT");
createTableQtyTarif.addForeignColumn("ID_FAMILLE_ARTICLE", root.getTable("FAMILLE_ARTICLE"));
createTableQtyTarif.addForeignColumn("ID_CLIENT", root.getTable("CLIENT"));
createTableQtyTarif.addDecimalColumn("QUANTITE", 16, 3, BigDecimal.ONE, false);
createTableQtyTarif.addDecimalColumn("POURCENT_REMISE", 16, 3, null, true);
// createTableQtyTarif.addDecimalColumn("PRIX_METRIQUE_VT_1", 16, 6, null, true);
try {
root.getBase().getDataSource().execute(createTableQtyTarif.asString());
InstallationPanel.insertUndef(createTableQtyTarif);
root.refetchTable("TARIF_FAMILLE_ARTICLE_CLIENT");
root.getSchema().updateVersion();
} catch (SQLException ex) {
throw new IllegalStateException("Erreur lors de la création de la table " + "TARIF_FAMILLE_ARTICLE_CLIENT", ex);
}
}
 
SQLTable tableAvoirC = root.getTable("AVOIR_CLIENT");
if (!tableAvoirC.contains("ID_TAXE_PORT")) {
final AlterTable alterB = new AlterTable(tableAvoirC);
alterB.addForeignColumn("ID_TAXE_PORT", root.getTable("TAXE"));
root.getBase().getDataSource().execute(alterB.asString());
root.refetchTable(tableAvoirC.getName());
root.getSchema().updateVersion();
}
 
SQLTable tableVF = root.getTable("SAISIE_VENTE_FACTURE");
if (!tableVF.contains("ID_FACTURATION_COMMANDE_CLIENT")) {
final AlterTable alter = new AlterTable(tableVF);
final SQLTable tableFacturationCommandeClient = tableVF.getDBRoot().getTable("FACTURATION_COMMANDE_CLIENT");
alter.addForeignColumn("ID_FACTURATION_COMMANDE_CLIENT", tableFacturationCommandeClient);
tableVF.getBase().getDataSource().execute(alter.asString());
tableVF.getSchema().updateVersion();
tableVF.fetchFields();
 
// update ID_FACTURATION_COMMANDE
UpdateBuilder builder = new UpdateBuilder(tableVF);
AliasedTable ref = new AliasedTable(tableFacturationCommandeClient, "tf");
builder.addBackwardVirtualJoin(ref, "ID_SAISIE_VENTE_FACTURE");
builder.setFromVirtualJoinField("ID_FACTURATION_COMMANDE_CLIENT", "tf", tableFacturationCommandeClient.getKey().getName());
tableVF.getBase().getDataSource().execute(builder.asString());
}
if (!root.getTable("NUMEROTATION_AUTO").contains("CODE_LETTRAGE_PARTIEL")) {
final AlterTable alterNumero = new AlterTable(root.getTable("NUMEROTATION_AUTO"));
alterNumero.addVarCharColumn("CODE_LETTRAGE_PARTIEL", 256);
root.getBase().getDataSource().execute(alterNumero.asString());
root.refetchTable("NUMEROTATION_AUTO");
root.getSchema().updateVersion();
}
 
if (!root.getTable("ECRITURE").contains("LETTRAGE_PARTIEL")) {
final AlterTable alterEcriture = new AlterTable(root.getTable("ECRITURE"));
alterEcriture.addVarCharColumn("LETTRAGE_PARTIEL", 256);
root.getBase().getDataSource().execute(alterEcriture.asString());
root.refetchTable("ECRITURE");
root.getSchema().updateVersion();
}
 
SQLTable tableFactureF = root.getTable("FACTURE_FOURNISSEUR");
if (!tableFactureF.contains("ID_AVOIR_FOURNISSEUR_2")) {
final AlterTable alter = new AlterTable(tableFactureF);
final SQLTable tableAvoirF = tableVF.getDBRoot().getTable("AVOIR_FOURNISSEUR");
alter.addForeignColumn("ID_AVOIR_FOURNISSEUR_2", tableAvoirF);
tableFactureF.getBase().getDataSource().execute(alter.asString());
tableFactureF.getSchema().updateVersion();
tableVF.fetchFields();
}
 
}
 
public static void initStock(SQLRow rowArticle, int idDepot) {
 
SQLSelect selStock = new SQLSelect();
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/ModulePackager.java
216,7 → 216,7
final JarEntry e = entries.nextElement();
if (!e.getName().startsWith("META-INF")) {
// use copy-constructor to keep all fields
zip(out, new JarEntry(e), f.getInputStream(e));
zip(out, new JarEntry(e.getName()), f.getInputStream(e));
}
}
} finally {
/trunk/OpenConcerto/src/org/openconcerto/erp/modules/ComponentsContext.java
17,6 → 17,7
import org.openconcerto.sql.element.SQLElementDirectory;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.sql.sqlobject.SQLTextCombo;
import org.openconcerto.sql.view.DropManager;
import org.openconcerto.sql.view.FileDropHandler;
24,6 → 25,7
import org.openconcerto.utils.ListMap;
 
import java.util.Set;
import java.util.function.Supplier;
 
import javax.swing.text.JTextComponent;
 
73,9 → 75,9
}
}
 
public final void putAdditionalField(final String tableName, final String name, final JTextComponent comp) {
public final void putAdditionalTextField(final String tableName, final String name, final Supplier<? extends JTextComponent> comp) {
final SQLElement elem = checkField(tableName, name);
if (elem.putAdditionalField(name, comp)) {
if (elem.putAdditionalTextField(name, comp)) {
this.fields.add(elem, name);
} else {
throw new IllegalStateException("Already added " + name + " in " + elem);
82,9 → 84,9
}
}
 
public final void putAdditionalField(final String tableName, final String name, final SQLTextCombo comp) {
public final void putAdditionalTextCombo(final String tableName, final String name, final Supplier<? extends SQLTextCombo> comp) {
final SQLElement elem = checkField(tableName, name);
if (elem.putAdditionalField(name, comp)) {
if (elem.putAdditionalTextCombo(name, comp)) {
this.fields.add(elem, name);
} else {
throw new IllegalStateException("Already added " + name + " in " + elem);
91,6 → 93,15
}
}
 
public final void putAdditionalCombo(final String tableName, final String name, final Supplier<? extends SQLRequestComboBox> comp) {
final SQLElement elem = checkField(tableName, name);
if (elem.putAdditionalCombo(name, comp)) {
this.fields.add(elem, name);
} else {
throw new IllegalStateException("Already added " + name + " in " + elem);
}
}
 
final ListMap<SQLElement, String> getFields() {
return this.fields;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/action/NouvelleConnexionAction.java
35,6 → 35,9
import org.openconcerto.erp.rights.MenuComboRightEditor;
import org.openconcerto.erp.utils.NXDatabaseAccessor;
import org.openconcerto.map.model.Ville;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.TM;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLBase;
64,6 → 67,7
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.JImage;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.i18n.TranslationManager;
 
import java.awt.Color;
import java.awt.GridBagConstraints;
81,6 → 85,7
import java.util.logging.Level;
 
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
203,6 → 208,7
final String socTitle = comptaPropsConfiguration.getRowSociete() == null ? "" : ", [Société " + comptaPropsConfiguration.getRowSociete().getString("NOM") + "]";
f.setTitle(comptaPropsConfiguration.getAppName() + " " + version + socTitle);
f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
 
}
});
final FutureTask<?> showMainFrame = new FutureTask<Object>(new Runnable() {
275,11 → 281,29
c.fill = GridBagConstraints.BOTH;
 
this.connexionPanel = ConnexionPanel.create(r, image, !Gestion.isMinimalMode());
if (this.connexionPanel == null)
final List<Locale> langs = Arrays.asList(Locale.FRANCE, Locale.CANADA_FRENCH, new Locale("fr", "CH"), new Locale("fr", "BE"), Locale.UK, Locale.CANADA, Locale.US, Locale.GERMANY,
new Locale("de", "CH"), new Locale("es", "ES"), new Locale("pl", "PL"));
if (this.connexionPanel == null) {
final Locale locale = UserProps.getInstance().getLocale();
// for next launch
UserProps.getInstance().setLocale(locale);
// for current run
((PropsConfiguration) Configuration.getInstance()).setLocale(locale);
// for code that will never need more than one Locale concurrently
// (e.g. used by TM singletons in various packages)
Locale.setDefault(locale);
// as explained in Locale.setDefault() javadoc : "be prepared to reinitialize
// locale-sensitive code"
JComponent.setDefaultLocale(locale);
// throw RuntimeException like ResourceBundle.getBundle() at the beginning of this
// method
TranslationManager.createDefaultInstance();
TM.getInstance();
return null;
this.connexionPanel.initLocalization(getClass().getName(), Arrays.asList(Locale.FRANCE, Locale.CANADA_FRENCH, new Locale("fr", "CH"), new Locale("fr", "BE"), Locale.UK, Locale.CANADA,
Locale.US, Locale.GERMANY, new Locale("de", "CH"), new Locale("es", "ES"), new Locale("pl", "PL")));
}
 
this.connexionPanel.initLocalization(getClass().getName(), langs);
 
p.add(this.connexionPanel, c);
final PanelFrame panelFrame = new PanelFrame(p, "Connexion");
panelFrame.setLocationRelativeTo(null);
299,12 → 323,12
@Override
public void run() {
// laisse le temps au logiciel de demarrer
ClasseCompte.loadClasseCompte(comptaConf);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ClasseCompte.loadClasseCompte();
CaisseCotisationSQLElement.getCaisseCotisation();
 
SQLPreferences prefs = SQLPreferences.getMemCached(comptaConf.getRootSociete());
/trunk/OpenConcerto/src/org/openconcerto/erp/action/CreateFrameAbstractAction.java
50,9 → 50,12
final Object name = action.getValue(Action.NAME);
WindowStateManager stateManager = null;
if (name != null) {
stateManager = new WindowStateManager(frame, new File(conf.getConfDir(), "Configuration" + File.separator + "Frame" + File.separator + name.toString() + ".xml"),
true);
if (conf == null) {
System.err.println("Warning: no configuration for action " + action + ", unable to use a window state manager.");
} else {
stateManager = new WindowStateManager(frame, new File(conf.getConfDir(), "Configuration" + File.separator + "Frame" + File.separator + name.toString() + ".xml"), true);
}
} else {
System.err.println("Warning: no action name for action " + action + ", unable to use a window state manager.");
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/BrEltFactEltSQLInjector.java
New file
0,0 → 1,30
/*
* 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.injector;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInjector;
 
public class BrEltFactEltSQLInjector extends SQLInjector {
public BrEltFactEltSQLInjector(final DBRoot root) {
super(root, "BON_RECEPTION_ELEMENT", "FACTURE_FOURNISSEUR_ELEMENT", false);
createDefaultMap();
if (getDestination().contains("ID_COMMANDE_ELEMENT") && getSource().contains("ID_COMMANDE_ELEMENT")) {
map(getSource().getField("ID_COMMANDE_ELEMENT"), getDestination().getField("ID_COMMANDE_ELEMENT"));
}
if (getDestination().contains("ID_BON_RECEPTION_ELEMENT")) {
map(getSource().getKey(), getDestination().getField("ID_BON_RECEPTION_ELEMENT"));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/injector/CmdEltFactEltSQLInjector.java
New file
0,0 → 1,27
/*
* 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.injector;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLInjector;
 
public class CmdEltFactEltSQLInjector extends SQLInjector {
public CmdEltFactEltSQLInjector(final DBRoot root) {
super(root, "COMMANDE_ELEMENT", "FACTURE_FOURNISSEUR_ELEMENT", false);
createDefaultMap();
if (getDestination().contains("ID_COMMANDE_ELEMENT")) {
map(getSource().getKey(), getDestination().getField("ID_COMMANDE_ELEMENT"));
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLElement.java
212,4 → 212,7
return (k == null) ? false : k.equalsIgnoreCase("true");
}
 
public boolean isImage() {
return this.elt.getAttributeValue("type").equalsIgnoreCase("image");
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLTableImage.java
New file
0,0 → 1,193
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.generationDoc;
 
import org.openconcerto.erp.core.edm.Attachment;
import org.openconcerto.erp.core.edm.AttachmentUtils;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.FillMode;
import org.openconcerto.utils.ImageUtils;
import org.openconcerto.utils.StringUtils;
 
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
 
import javax.imageio.ImageIO;
 
import org.jdom2.Element;
 
public class OOXMLTableImage {
 
private float x = 0;
private float y = 0;
private final float width, height;
private int dpi = 300;
 
private final int rowCount;
// #ffffff
private String bgColor = "#ffffff";
 
public final static String EDM_URL = "edm://miniature.png";
// C://Users/Toto.jpg ou edm://miniature.png (prendre nom miniature)
private final String url;
// ID_AFFAIRE.ID_CLIENT
private String fieldPathEDM;
private String edmProvider;
// top,center,bottom
private String vAlign = "center";
// left, center, right
private String hAlign = "center";
 
private OOXMLElement xmlField;
private final SQLRowAccessor row;
 
public OOXMLTableImage(OOXMLElement xmlField, Element e, SQLRowAccessor row) {
this.xmlField = xmlField;
this.row = row;
this.url = e.getAttributeValue("url");
this.fieldPathEDM = e.getAttributeValue("fieldPathEDM");
this.edmProvider = e.getAttributeValue("edmProvider");
this.width = Float.valueOf(e.getAttributeValue("width"));
this.height = Float.valueOf(e.getAttributeValue("height"));
this.rowCount = Integer.valueOf(e.getAttributeValue("rowCount"));
if (e.getAttributeValue("x") != null && !e.getAttributeValue("x").isEmpty()) {
this.x = Integer.valueOf(e.getAttributeValue("x"));
}
if (e.getAttributeValue("y") != null && !e.getAttributeValue("y").isEmpty()) {
this.y = Integer.valueOf(e.getAttributeValue("y"));
}
}
 
private byte[] img = null;
private boolean cachedImg = false;
 
public byte[] getImgBytes() throws IOException {
 
if (this.cachedImg) {
return this.img;
} else {
 
if (this.url.startsWith("edm://")) {
Path p = new Path(this.row.getTable());
final SQLRow r = this.row.asRow();
final SQLRow rowToEdm;
String sourceTableName = r.getTable().getName();
int sourceID = r.getID();
if (this.fieldPathEDM == null || this.fieldPathEDM.isEmpty() || this.fieldPathEDM.equalsIgnoreCase(".")) {
rowToEdm = r;
} else if (this.fieldPathEDM != null && this.fieldPathEDM.equalsIgnoreCase("EDM_PROVIDER")) {
SpreadSheetCellValueProvider provider = SpreadSheetCellValueProviderManager.get(this.edmProvider);
rowToEdm = (SQLRow) provider.getValue(new SpreadSheetCellValueContext(r));
if (rowToEdm == null) {
return null;
} else {
sourceTableName = rowToEdm.getTable().getName();
sourceID = rowToEdm.getID();
}
 
} else {
List<String> fields = StringUtils.fastSplit(this.fieldPathEDM, '.');
if (fields.size() == 1) {
sourceTableName = r.getTable().getForeignTable(fields.get(0)).getName();
sourceID = r.getForeignID(fields.get(0));
} else {
for (String f : fields) {
p = p.add(p.getLast().getField(f));
}
rowToEdm = r.getDistantRow(p);
sourceTableName = rowToEdm.getTable().getName();
sourceID = rowToEdm.getID();
}
}
final SQLTable tableAttachment = this.row.getTable().getTable("ATTACHMENT");
SQLRowValues rowVals = new SQLRowValues(tableAttachment);
rowVals.putNulls(tableAttachment.getFieldsName());
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowVals);
Where where = new Where(tableAttachment.getField("SOURCE_TABLE"), "=", sourceTableName);
where = where.and(new Where(tableAttachment.getField("SOURCE_ID"), "=", sourceID));
where = where.and(new Where(tableAttachment.getField("NAME"), "=", this.url.replaceAll("edm://", "")));
final List<SQLRowValues> rAttachments = fetcher.fetch(where);
if (rAttachments.isEmpty()) {
this.cachedImg = true;
return null;
} else {
final SQLRowValues rowValsAttachment = rAttachments.get(0);
final Attachment a = new Attachment(rowValsAttachment);
final AttachmentUtils u = new AttachmentUtils();
final File f = u.getFile(a);
BufferedImage unscaledImage = ImageIO.read(f);
 
// 1 pouce = 25.4 mmm
float scale = this.dpi / 25.4f;
int maxWidth = (int) (this.width * scale);
int maxHeight = (int) (this.height * scale);
final BufferedImage im = ImageUtils.createQualityResizedImage(unscaledImage, maxWidth, maxHeight, false, new FillMode.ZoomOut(Color.WHITE), true);
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(im, "PNG", output);
output.close();
this.img = output.toByteArray();
this.cachedImg = true;
return this.img;
}
 
} else
 
{
this.img = FileUtils.readBytes(new File(this.url));
this.cachedImg = true;
return this.img;
}
}
}
 
public String getBgColor() {
return this.bgColor;
}
 
public int getDpi() {
return this.dpi;
}
 
public float getX() {
return this.x;
}
 
public float getY() {
return this.y;
}
 
public float getWidth() {
return this.width;
}
 
public float getHeight() {
return this.height;
}
 
public int getRowCount() {
return this.rowCount;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/FormatedGlobalQtyTotalProvider.java
26,11 → 26,11
 
private final boolean shortName, alwaysShowOnZeroQty, pieceName;
 
private static enum Type {
public static enum Type {
NORMAL, SHIPMENT
}
 
private final Type type;
public final Type type;
 
private FormatedGlobalQtyTotalProvider(Type t, boolean shortName) {
this(t, shortName, false, false);
46,7 → 46,7
public Object getValue(SpreadSheetCellValueContext context) {
final SQLRowAccessor row = context.getRow();
final BigDecimal pv = row.getBigDecimal("PV_HT");
if (!alwaysShowOnZeroQty && pv.compareTo(BigDecimal.ZERO) == 0) {
if (!this.alwaysShowOnZeroQty && pv.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
 
61,10 → 61,8
return String.valueOf(qte);
}
String result = "";
if (qte > 0) {
if (qte > 1) {
if (this.alwaysShowOnZeroQty || qte != 0) {
result += qte + " x ";
}
final BigDecimal qteUV = row.getBigDecimal("QTE_UNITAIRE");
 
result += NumericFormat.getQtyDecimalFormat().format(qteUV);
82,7 → 80,7
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit", new FormatedGlobalQtyTotalProvider(Type.NORMAL, false));
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit.deliver.short", new FormatedGlobalQtyTotalProvider(Type.SHIPMENT, true));
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit.deliver", new FormatedGlobalQtyTotalProvider(Type.SHIPMENT, false));
 
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit.deliver.short.with.quantity", new FormatedGlobalQtyTotalProvider(Type.SHIPMENT, true, true, true));
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit.alwaysnamed.short.with.quantity", new FormatedGlobalQtyTotalProvider(Type.NORMAL, true, true, true));
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit.alwaysnamed.short", new FormatedGlobalQtyTotalProvider(Type.NORMAL, true, false, true));
SpreadSheetCellValueProviderManager.put("supplychain.element.qtyunit.alwaysnamed", new FormatedGlobalQtyTotalProvider(Type.NORMAL, false, false, true));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/TotalCommandeClientProvider.java
24,7 → 24,7
public class TotalCommandeClientProvider implements SpreadSheetCellValueProvider {
 
public enum TypeTotalCommandeClientProvider {
HT, TTC;
HT, TTC, TVA;
};
 
private final TypeTotalCommandeClientProvider type;
40,9 → 40,16
for (SQLRowAccessor sqlRowAccessor : rows) {
if (!sqlRowAccessor.isForeignEmpty("ID_COMMANDE_CLIENT")) {
SQLRowAccessor rowCmd = sqlRowAccessor.getForeign("ID_COMMANDE_CLIENT");
total += (this.type == TypeTotalCommandeClientProvider.HT ? rowCmd.getLong("T_HT") : rowCmd.getLong("T_TTC"));
if (this.type == TypeTotalCommandeClientProvider.HT) {
total += rowCmd.getLong("T_HT");
} else if (this.type == TypeTotalCommandeClientProvider.TVA) {
total += rowCmd.getLong("T_TVA");
} else if (this.type == TypeTotalCommandeClientProvider.TTC) {
total += rowCmd.getLong("T_TTC");
}
 
}
}
return new BigDecimal(total).movePointLeft(2);
}
 
49,6 → 56,7
public static void register() {
SpreadSheetCellValueProviderManager.put("sales.account.command.total", new TotalCommandeClientProvider(TypeTotalCommandeClientProvider.HT));
SpreadSheetCellValueProviderManager.put("sales.account.command.total.ttc", new TotalCommandeClientProvider(TypeTotalCommandeClientProvider.TTC));
SpreadSheetCellValueProviderManager.put("sales.account.command.total.tva", new TotalCommandeClientProvider(TypeTotalCommandeClientProvider.TVA));
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/provider/ConditionsReglementDetailsProvider.java
44,15 → 44,15
 
if (ajours == 0 && njour == 0) {
if (foreignRow.getBoolean("COMPTANT") != null && !foreignRow.getBoolean("COMPTANT")) {
r = "Date de facture";
r += " Date de facture";
} else {
r = "Comptant";
r += " Comptant";
}
} else {
 
if (ajours != 0) {
 
r = "à" + ajours + ((ajours > 1) ? " jours" : " jour");
r += " à " + ajours + ((ajours > 1) ? " jours" : " jour");
}
if (njour > 0 && njour < 31) {
r += " le " + njour;
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLTableField.java
43,6 → 43,9
private int idRef;
private String style = "";
 
 
public OOXMLTableField(Element eltField, SQLRowAccessor row, SQLElement sqlElt, int id, int filterId, SQLRow rowLanguage, int idRef, OOXMLCache cache) {
super(eltField, row, sqlElt, id, rowLanguage, cache);
this.type = eltField.getAttributeValue("type");
247,4 → 250,9
 
return this.style;
}
public boolean isImage() {
return this.type.equalsIgnoreCase("image");
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOXMLCache.java
29,6 → 29,7
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.ListMap;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
 
import java.math.BigDecimal;
39,16 → 40,30
import java.util.List;
import java.util.Map;
 
import org.jdom2.Element;
 
public class OOXMLCache {
 
private ITransformer<List<SQLRowAccessor>, List<SQLRowAccessor>> postProcess = null;
private Map<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>> cacheReferent = new HashMap<SQLRowAccessor, Map<SQLTable, List<SQLRowAccessor>>>();
private Map<String, Map<Integer, SQLRowAccessor>> cacheForeign = new HashMap<String, Map<Integer, SQLRowAccessor>>();
private Map<Tuple2<String, SQLRowAccessor>, OOXMLTableImage> cacheImg = new HashMap<>();
 
public void setPostProcess(ITransformer<List<SQLRowAccessor>, List<SQLRowAccessor>> postProcess) {
this.postProcess = postProcess;
}
 
public OOXMLTableImage getOOXMLTableImage(OOXMLElement x, Element e, SQLRowAccessor r) {
Tuple2<String, SQLRowAccessor> key = Tuple2.create(e.getAttributeValue("fieldPathEDM"), r);
if (this.cacheImg.containsKey(key)) {
return this.cacheImg.get(key);
} else {
OOXMLTableImage img = new OOXMLTableImage(x, e, r);
this.cacheImg.put(key, img);
return img;
}
}
 
protected SQLRowAccessor getForeignRow(SQLRowAccessor row, SQLField field) {
Map<Integer, SQLRowAccessor> c = cacheForeign.get(field.getName());
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/AbstractJOOReportsSheet.java
312,6 → 312,25
return new File(outputPDFDirectory, getFileName() + ".pdf");
}
 
public void printDocument(PrinterJob job) {
 
try {
final File f = getDocumentFile();
 
if (!f.exists()) {
generate(false, false, "");
}
 
final Component doc = ComptaPropsConfiguration.getOOConnexion().loadDocument(f, true);
doc.printDocument(job);
doc.close();
 
} catch (Exception e) {
ExceptionHandler.handle("Impossible d'imprimer le document OpenOffice", e);
e.printStackTrace();
}
}
 
public void exportToPdf() {
// Export vers PDF
final File fileOutOO = getDocumentFile();
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/SheetUtils.java
154,9 → 154,18
PdfBoxGraphics2DFontTextDrawer fontTextDrawer = new PdfBoxGraphics2DFontTextDrawerDefaultFonts();
final File dir = new File("Fonts");
if (dir.exists()) {
fontTextDrawer.registerFontFromDirectory(dir);
System.out.println("Using fonts dir : " + dir.getAbsolutePath());
for (File f : dir.listFiles()) {
if (f.isFile() && f.getName().toLowerCase().endsWith(".ttf")) {
System.out.println("Registering font : " + f.getAbsolutePath());
fontTextDrawer.registerFont(f);
}
}
 
} else {
System.out.println("No custom fonts dir found : " + dir.getAbsolutePath());
}
 
// Configure the renderer
ODTRenderer renderer = new ODTRenderer(doc);
renderer.setIgnoreMargins(false);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/gestcomm/RelanceSheet.java
18,6 → 18,7
import org.openconcerto.erp.generationDoc.AbstractJOOReportsSheet;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.users.UserManager;
65,6 → 66,12
}
// Infos societe
map.put("SocieteType", rowSoc.getString("TYPE"));
map.put("SocieteTel", rowSoc.getString("NUM_TEL"));
map.put("SocieteFax", rowSoc.getString("NUM_FAX"));
map.put("SocieteRCS", rowSoc.getString("RCS"));
map.put("SocieteSiret", rowSoc.getString("NUM_SIRET"));
map.put("SocieteAPE", rowSoc.getString("NUM_APE"));
map.put("SocieteCapital", GestionDevise.currencyToString(rowSoc.getBigDecimal("CAPITAL")));
map.put("SocieteNom", rowSoc.getString("NOM"));
map.put("SocieteAdresse", rowSocAdresse.getString("RUE"));
map.put("SocieteCodePostal", rowSocAdresse.getString("CODE_POSTAL"));
137,19 → 144,27
 
SQLSelect sel = new SQLSelect();
sel.addSelect(this.rowRelance.getTable().getKey());
sel.addSelect(this.rowRelance.getTable().getField("DATE"));
sel.setWhere(new Where(this.rowRelance.getTable().getField("ID_SAISIE_VENTE_FACTURE"), "=", this.rowRelance.getInt("ID_SAISIE_VENTE_FACTURE")));
sel.addFieldOrder(this.rowRelance.getTable().getField("DATE"));
@SuppressWarnings("unchecked")
List<Map<String, Number>> listResult = Configuration.getInstance().getBase().getDataSource().execute(sel.asString());
List<SQLRow> listResult = SQLRowListRSH.execute(sel);
 
String oldDateRelance = "";
 
if (listResult != null && listResult.size() > 0) {
Map<String, Number> o = listResult.get(0);
Number n = o.get(this.rowRelance.getTable().getKey().getName());
SQLRow rowOldRelance = this.rowRelance.getTable().getRow(n.intValue());
SQLRow rowOldRelance = listResult.get(0);
Date dOldRelance = (Date) rowOldRelance.getObject("DATE");
map.put("DatePremiereRelance", dateFormat2.format(dOldRelance));
 
for (SQLRow rowOldR : listResult) {
oldDateRelance += dateFormat2.format((Date) rowOldR.getObject("DATE")) + ", ";
}
 
} else {
map.put("DatePremiereRelance", "");
}
map.put("DateAncienneRelance", oldDateRelance);
 
return map;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/OOgenerationXML.java
20,7 → 20,10
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.preferences.DefaultNXProps;
import org.openconcerto.openoffice.LengthUnit;
import org.openconcerto.openoffice.ODFrame;
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.spreadsheet.BytesProducer.ByteArrayProducer;
import org.openconcerto.openoffice.spreadsheet.MutableCell;
import org.openconcerto.openoffice.spreadsheet.Sheet;
import org.openconcerto.openoffice.spreadsheet.SpreadSheet;
56,6 → 59,7
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
 
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
700,10 → 704,28
value = null;
styleOO = null;
}
int tmpCelluleAffect;
 
int tmpCelluleAffect = fill(test ? "A1" : loc, value, sheet, tableField.isTypeReplace(), null, styleOO, test, tableField.isMultilineAuto(), tableField.isKeepingEmptyLines());
// tmpCelluleAffect = Math.max(tmpCelluleAffect,
// tableField.getLine());
if (tableField.isImage()) {
OOXMLTableImage tableImage = this.rowRefCache.getOOXMLTableImage(tableField, e, rowElt);
tmpCelluleAffect = 1;
try {
if (tableImage.getImgBytes() != null) {
MutableCell cell = sheet.getCellAt(test ? "A1" : loc);
if (!test) {
final ODFrame<SpreadSheet> frame = cell.addFrame(tableImage.getX(), tableImage.getY(), tableImage.getWidth(), tableImage.getHeight(), LengthUnit.MM);
frame.addImage(UUID.randomUUID() + ".png", new ByteArrayProducer(tableImage.getImgBytes(), false));
}
tmpCelluleAffect = tableImage.getRowCount();
}
} catch (Exception e1) {
// TODO popup???
e1.printStackTrace();
}
 
} else {
tmpCelluleAffect = fill(test ? "A1" : loc, value, sheet, tableField.isTypeReplace(), null, styleOO, test, tableField.isMultilineAuto(), tableField.isKeepingEmptyLines());
}
if (tableField.getLine() != 1 && (!tableField.isLineOption() || (value != null && value.toString().trim().length() > 0))) {
if (nbCellule >= tableField.getLine()) {
tmpCelluleAffect = tmpCelluleAffect + nbCellule;
795,11 → 817,27
if (result != null) {
Object o = elt.getAttributeValue("sheet");
int sheet = (o == null) ? 0 : Integer.valueOf(o.toString().trim());
if (OOElt.isImage()) {
OOXMLTableImage tableImage = new OOXMLTableImage(OOElt, elt, row);
try {
if (tableImage.getImgBytes() != null) {
MutableCell cell = spreadSheet.getSheet(sheet).getCellAt(elt.getAttributeValue("location"));
final ODFrame<SpreadSheet> frame = cell.addFrame(tableImage.getX(), tableImage.getY(), tableImage.getWidth(), tableImage.getHeight(), LengthUnit.MM);
frame.addImage(UUID.randomUUID() + ".png", new ByteArrayProducer(tableImage.getImgBytes(), false));
 
}
} catch (Exception e1) {
// TODO popup???
e1.printStackTrace();
}
 
} else {
fill(elt.getAttributeValue("location"), result, spreadSheet.getSheet(sheet), OOElt.isTypeReplace(), OOElt.getReplacePattern(), null, false, OOElt.isMultilineAuto(),
OOElt.isKeepingEmptyLines());
}
}
}
}
 
private static boolean isIncluded(int filterID, String foreignTable, int id, String fieldWhere, SQLRowAccessor rowElt) {
 
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtAvoirFournisseur.java
109,12 → 109,14
if (rowFourn.getBoolean("UE")) {
idCompteTVA = taxe.getForeignID("ID_COMPTE_PCE_DED_INTRA");
if (idCompteTVA <= 1) {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_INTRA");
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVAIntraComm");
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVADeductible");
}
}
} else {
idCompteTVA = taxe.getForeignID("ID_COMPTE_PCE_DED");
if (idCompteTVA <= 1) {
idCompteTVA = rowPrefsCompte.getInt("ID_COMPTE_PCE_TVA_ACHAT");
if (idCompteTVA <= 1) {
idCompteTVA = ComptePCESQLElement.getIdComptePceDefault("TVADeductible");
121,6 → 123,7
}
}
}
}
 
this.putValue("ID_COMPTE_PCE", Integer.valueOf(idCompteTVA));
this.putValue("DEBIT", Long.valueOf(0));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementAchat.java
17,6 → 17,8
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProvider;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProviderManager;
import org.openconcerto.erp.model.PrixTTC;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
35,6 → 37,10
 
public class GenerationReglementAchat extends GenerationEcritures {
 
public static final String ID = "accounting.records.order.supplychain.payment";
// Journal Caisse
private static final Integer journalCaisse = new Integer(JournalSQLElement.CAISSES);
private static final SQLTable tablePrefCompte = base.getTable("PREFS_COMPTE");
61,6 → 67,10
 
// "Règlement achat" + SOURCE.getNom() ??
this.nom = "Règlement achat " + rowFournisseur.getString("NOM") + " (" + typeRegRow.getString("NOM") + ")";
AccountingRecordsProvider provider = AccountingRecordsProviderManager.get(ID);
if (provider != null) {
provider.putLabel(regMontantRow, this.mEcritures);
}
 
List<SQLRow> l = regMontantRow.getReferentRows(regMontantRow.getTable().getTable("REGLER_MONTANT_ELEMENT"));
int mvtSource = -1;
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtFactureFournisseur.java
16,6 → 16,8
import org.openconcerto.erp.core.common.ui.TotalCalculator;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProvider;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProviderManager;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
29,7 → 31,7
 
public class GenerationMvtFactureFournisseur extends GenerationEcritures implements Runnable {
 
public static final String ID = "accounting.records.supply.order";
public static final String ID = "accounting.records.supplychain.order";
 
private int idFacture;
private static final String source = "FACTURE_FOURNISSEUR";
65,6 → 67,11
// AccountingRecordsProvider provider = AccountingRecordsProviderManager.get(ID);
// provider.putLabel(saisieRow, this.mEcritures);
this.putValue("NOM", nom);
AccountingRecordsProvider provider = AccountingRecordsProviderManager.get(ID);
if (provider != null) {
provider.putLabel(saisieRow, this.mEcritures);
}
 
this.putValue("ID_JOURNAL", GenerationMvtFactureFournisseur.journal);
this.putValue("ID_MOUVEMENT", new Integer(1));
 
71,13 → 78,17
// on calcule le nouveau numero de mouvement
if (this.idMvt == 1) {
SQLRowValues rowValsPiece = new SQLRowValues(pieceTable);
// provider.putPieceLabel(saisieRow, rowValsPiece);
rowValsPiece.put("NOM", saisieRow.getObject("NUMERO").toString());
if (provider != null) {
provider.putPieceLabel(saisieRow, rowValsPiece);
}
getNewMouvement(GenerationMvtFactureFournisseur.source, this.idFacture, 1, rowValsPiece);
} else {
SQLRowValues rowValsPiece = pieceTable.getTable("MOUVEMENT").getRow(idMvt).getForeign("ID_PIECE").asRowValues();
// provider.putPieceLabel(saisieRow, rowValsPiece);
rowValsPiece.put("NOM", saisieRow.getObject("NUMERO").toString());
if (provider != null) {
provider.putPieceLabel(saisieRow, rowValsPiece);
}
rowValsPiece.update();
 
this.putValue("ID_MOUVEMENT", new Integer(this.idMvt));
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationReglementVenteNG.java
22,6 → 22,9
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement;
import org.openconcerto.erp.core.finance.payment.element.SEPAMandateSQLElement;
import org.openconcerto.erp.core.finance.payment.element.TypeReglementSQLElement;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProvider;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProviderManager;
import org.openconcerto.erp.model.PrixTTC;
import org.openconcerto.erp.preferences.GestionCommercialeGlobalPreferencePanel;
import org.openconcerto.sql.Configuration;
52,6 → 55,8
private static final SQLTable tablePrefCompte = base.getTable("PREFS_COMPTE");
private static final SQLRow rowPrefsCompte = tablePrefCompte.getRow(2);
 
public static final String ID = "accounting.records.invoice.sales.payment";
 
public SQLRow ecrClient = null;
 
public GenerationReglementVenteNG(String label, SQLRow rowClient, PrixTTC ttc, Date d, SQLRow modeReglement, SQLRow source, SQLRow mvtSource) throws SQLException {
81,6 → 86,10
// TODO Nommage des ecritures
 
this.nom = label;
AccountingRecordsProvider provider = AccountingRecordsProviderManager.get(ID);
if (provider != null) {
provider.putLabel(source, this.mEcritures);
}
 
this.putValue("DATE", this.date);
this.putValue("NOM", this.nom);
236,6 → 245,31
this.putValue("CREDIT", Long.valueOf(0));
ajoutEcriture();
 
// FIXME remove getConf
SQLRow rowSoc = ComptaPropsConfiguration.getInstanceCompta().getRowSociete();
if (rowSoc.getTable().contains("TVA_ENCAISSEMENT") && rowSoc.getBoolean("TVA_ENCAISSEMENT")) {
SQLRow rowTaxe = TaxeCache.getCache().getFirstTaxe();
if (rowTaxe.contains("ID_COMPTE_PCE_COLLECTE_ENCAISSEMENT")) {
SQLRowAccessor rowCompteTvaEnc = rowTaxe.getNonEmptyForeign("ID_COMPTE_PCE_COLLECTE_ENCAISSEMENT");
SQLRowAccessor rowCompteTvaCol = rowTaxe.getNonEmptyForeign("ID_COMPTE_PCE_COLLECTE");
if (rowCompteTvaCol != null && rowCompteTvaEnc != null) {
Float taux = rowTaxe.getFloat("TAUX");
 
long tva = ttc.calculLongTVA(taux / 100.0);
this.putValue("ID_COMPTE_PCE", rowCompteTvaCol.getID());
this.putValue("DEBIT", Long.valueOf(tva));
this.putValue("CREDIT", Long.valueOf(0));
ajoutEcriture();
 
this.putValue("ID_COMPTE_PCE", rowCompteTvaEnc.getID());
this.putValue("DEBIT", Long.valueOf(0));
this.putValue("CREDIT", Long.valueOf(tva));
ajoutEcriture();
 
}
}
}
 
List<Integer> pieceIDs = new ArrayList<Integer>();
if (source.getTable().getName().equals("ENCAISSER_MONTANT")) {
List<SQLRow> l = source.getReferentRows(base.getTable("ENCAISSER_MONTANT_ELEMENT"));
299,9 → 333,13
SQLRowValues rowVals = new SQLRowValues(tableMouvement);
rowVals.put("IDSOURCE", row.getID());
rowVals.update(this.idMvt);
if (source.getTable().getName().equalsIgnoreCase("ENCAISSER_MONTANT")) {
 
source.createEmptyUpdateRow().put("ID_MOUVEMENT", this.idMvt).commit();
}
 
}
}
 
private void setDateReglement(SQLRow source, Date d) throws SQLException {
List<SQLRow> sources = new ArrayList<SQLRow>();
460,4 → 498,5
}
 
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtSaisieKm.java
14,6 → 14,8
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProvider;
import org.openconcerto.erp.generationEcritures.provider.AccountingRecordsProviderManager;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
28,6 → 30,8
private int idSaisieKm;
private static final String source = "SAISIE_KM";
 
public static final String ID = "accounting.records.km";
 
public GenerationMvtSaisieKm(int idSaisieKm) {
this.idSaisieKm = idSaisieKm;
}
47,8 → 51,15
this.putValue("ID_MOUVEMENT", new Integer(1));
 
// on calcule le nouveau numero de mouvement
getNewMouvement(GenerationMvtSaisieKm.source, this.idSaisieKm, 1, (labelSaisie.length() == 0 ? "Saisie au km " : labelSaisie));
AccountingRecordsProvider provider = AccountingRecordsProviderManager.get(ID);
SQLRowValues rowValsPiece = new SQLRowValues(pieceTable);
rowValsPiece.put("NOM", (labelSaisie.length() == 0 ? "Saisie au km " : labelSaisie));
if (provider != null) {
provider.putPieceLabel(saisieRow, rowValsPiece);
}
 
getNewMouvement(GenerationMvtSaisieKm.source, this.idSaisieKm, 1, rowValsPiece);
 
// gnération des ecritures
SQLTable tableElt = Configuration.getInstance().getRoot().findTable("SAISIE_KM_ELEMENT");
List<SQLRow> set = saisieRow.getReferentRows(tableElt);
/trunk/OpenConcerto/src/org/openconcerto/erp/generationEcritures/GenerationMvtReglementChequeClient.java
13,9 → 13,10
package org.openconcerto.erp.generationEcritures;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.finance.accounting.element.ComptePCESQLElement;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.erp.core.finance.accounting.element.MouvementSQLElement;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
110,6 → 111,31
this.putValue("CREDIT", new Long(0));
ajoutEcriture();
 
// FIXME remove getConf
SQLRow rowSoc = ComptaPropsConfiguration.getInstanceCompta().getRowSociete();
if (rowSoc.getTable().contains("TVA_ENCAISSEMENT") && rowSoc.getBoolean("TVA_ENCAISSEMENT")) {
SQLRow rowTaxe = TaxeCache.getCache().getFirstTaxe();
if (rowTaxe.contains("ID_COMPTE_PCE_COLLECTE_ENCAISSEMENT")) {
SQLRowAccessor rowCompteTvaEnc = rowTaxe.getNonEmptyForeign("ID_COMPTE_PCE_COLLECTE_ENCAISSEMENT");
SQLRowAccessor rowCompteTvaCol = rowTaxe.getNonEmptyForeign("ID_COMPTE_PCE_COLLECTE");
if (rowCompteTvaCol != null && rowCompteTvaEnc != null) {
Float taux = rowTaxe.getFloat("TAUX");
long ht = Math.round(montant / (1.0 + (taux / 100.0)));
long tva = montant - ht;
this.putValue("ID_COMPTE_PCE", rowCompteTvaCol.getID());
this.putValue("DEBIT", Long.valueOf(tva));
this.putValue("CREDIT", Long.valueOf(0));
ajoutEcriture();
 
this.putValue("ID_COMPTE_PCE", rowCompteTvaEnc.getID());
this.putValue("DEBIT", Long.valueOf(0));
this.putValue("CREDIT", Long.valueOf(tva));
ajoutEcriture();
 
}
}
}
 
List<Integer> pieceIDs = new ArrayList<Integer>();
pieceIDs.add(mouvementTable.getRow(idMvt).getForeignID("ID_PIECE"));
lettrageAuto(pieceIDs, this.date);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/edm/AttachmentUtils.java
17,10 → 17,14
import org.openconcerto.erp.generationDoc.DocumentLocalStorageManager;
import org.openconcerto.erp.storage.StorageEngine;
import org.openconcerto.erp.storage.StorageEngines;
import org.openconcerto.sql.model.SQLInsert;
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.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.Base64;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.sync.SyncClient;
29,22 → 33,80
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.List;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.JOptionPane;
 
public class AttachmentUtils {
 
public void uploadFile(File inFile, SQLRowAccessor rowSource, int idParent) {
try {
String generateBase64Key() throws NoSuchAlgorithmException {
final KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(16 * 8);
final SecretKey k = generator.generateKey();
return Base64.encodeBytes(k.getEncoded(), Base64.DONT_BREAK_LINES);
}
 
SecretKey getSecretKey(String base64key) {
byte[] b = Base64.decode(base64key.getBytes(StandardCharsets.UTF_8));
if (b.length != 16) {
throw new IllegalStateException("key length must be 16 bytes for AES");
}
return new SecretKeySpec(b, "AES");
}
 
public byte[] encrypt(SecretKey secretKey, byte[] in)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
return process(secretKey, in, Cipher.ENCRYPT_MODE);
}
 
public byte[] decrypt(SecretKey secretKey, byte[] in)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
return process(secretKey, in, Cipher.DECRYPT_MODE);
}
 
public byte[] process(SecretKey secretKey, byte[] in, int mode)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
final byte[] nonce = new byte[12];
final byte[] e = secretKey.getEncoded();
for (int i = 0; i < nonce.length; i++) {
nonce[i] = (byte) (e[i] * e[i + 1] + e[i + 2]);
}
GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce);
cipher.init(mode, secretKey, spec);
return cipher.doFinal(in);
}
 
public void uploadFile(File inFile, SQLRowAccessor rowSource, int idParent) throws SQLException {
uploadFile(inFile, rowSource, idParent, null);
}
 
public void uploadFile(File inFile, SQLRowAccessor rowSource, int idParent, String nameInGed) throws SQLException {
 
String encodeKey = fetchEncodedKey(rowSource.getTable().getTable("FWK_SCHEMA_METADATA"));
// Création de la row attachment
SQLRowValues rowValsAttachment = new SQLRowValues(rowSource.getTable().getTable("ATTACHMENT"));
rowValsAttachment.put("SOURCE_TABLE", rowSource.getTable().getName());
rowValsAttachment.put("SOURCE_ID", rowSource.getID());
rowValsAttachment.put("ID_PARENT", idParent);
if (encodeKey != null) {
rowValsAttachment.put("ENCRYPTED", true);
}
 
SQLRow rowAttachment = rowValsAttachment.insert();
int id = rowAttachment.getID();
 
63,39 → 125,36
final ComptaPropsConfiguration config = ComptaPropsConfiguration.getInstanceCompta();
boolean isOnCloud = config.isOnCloud();
 
try {
if (isOnCloud) {
 
String remotePath = subDir;
List<StorageEngine> engines = StorageEngines.getInstance().getActiveEngines();
final List<StorageEngine> engines = StorageEngines.getInstance().getActiveEngines();
File encodedFile = inFile;
if (encodeKey != null) {
encodedFile = File.createTempFile("encrypted", inFile.getName());
final byte[] enc = encrypt(getSecretKey(encodeKey), FileUtils.readBytes(inFile));
Files.write(encodedFile.toPath(), enc);
}
 
for (StorageEngine storageEngine : engines) {
if (storageEngine.isConfigured() && storageEngine.allowAutoStorage()) {
final String path = remotePath;
 
try (FileInputStream in = new FileInputStream(inFile)) {
try (FileInputStream in = new FileInputStream(encodedFile)) {
storageEngine.connect();
final BufferedInputStream inStream = new BufferedInputStream(in);
storageEngine.store(inStream, path, fileWithIDNAme, true);
inStream.close();
storageEngine.disconnect();
} catch (IOException e) {
ExceptionHandler.handle("Impossible de sauvegarder le fichier " + inFile.getAbsolutePath() + " vers " + path + "(" + storageEngine + ")", e);
}
// if (storageEngine instanceof CloudStorageEngine) {
// try {
// storageEngine.connect();
// final BufferedInputStream inStream = new BufferedInputStream(new
// FileInputStream(generatedFile));
// storageEngine.store(inStream, path, generatedFile.getName(), true);
// inStream.close();
// storageEngine.disconnect();
// } catch (IOException e) {
// ExceptionHandler.handle("Impossible de sauvegarder le fichier généré " +
// generatedFile.getAbsolutePath() + " vers " + path + "(" + storageEngine +
// ")", e);
// }
// }
 
}
}
if (encodeKey != null) {
encodedFile.delete();
}
 
} else {
// Upload File
 
104,9 → 163,14
File storagePathFile = new File(dirRoot, subDir);
storagePathFile.mkdirs();
// TODO CHECK IF FILE EXISTS
if (encodeKey == null) {
FileUtils.copyFile(inFile, new File(storagePathFile, fileWithIDNAme));
 
} else {
final File encodedFile = new File(storagePathFile, fileWithIDNAme);
final byte[] enc = encrypt(getSecretKey(encodeKey), FileUtils.readBytes(inFile));
Files.write(encodedFile.toPath(), enc);
}
}
 
// Update rowAttachment
rowValsAttachment = rowAttachment.createEmptyUpdateRow();
113,6 → 177,9
 
// Default is without extension
String fileName = inFile.getName();
if (nameInGed != null) {
rowValsAttachment.put("NAME", nameInGed);
} else {
String name = fileName;
int index = name.lastIndexOf('.');
if (index > 0) {
119,8 → 186,11
name = name.substring(0, index);
}
rowValsAttachment.put("NAME", name);
}
 
rowValsAttachment.put("SOURCE_TABLE", rowSource.getTable().getName());
rowValsAttachment.put("SOURCE_ID", rowSource.getID());
rowValsAttachment.put("ID_PARENT", idParent);
final String mimeType = Files.probeContentType(inFile.toPath());
rowValsAttachment.put("MIMETYPE", mimeType != null ? mimeType : "application/octet-stream");
rowValsAttachment.put("FILENAME", fileName);
127,6 → 197,7
rowValsAttachment.put("FILESIZE", inFile.length());
rowValsAttachment.put("STORAGE_PATH", subDir);
rowValsAttachment.put("STORAGE_FILENAME", fileWithIDNAme);
rowValsAttachment.put("ENCRYPTED", (encodeKey != null));
// TODO THUMBNAIL
// rowVals.put("THUMBNAIL", );
// rowVals.put("THUMBNAIL_WIDTH", );
137,11 → 208,39
rowValsAttachment.commit();
final Attachment a = new Attachment(rowValsAttachment);
updateAttachmentsCountFromAttachment(a);
 
} catch (Exception e) {
e.printStackTrace();
if (rowAttachment != null) {
config.getDirectory().getElement(AttachmentSQLElement.class).archive(rowAttachment.getID());
}
ExceptionHandler.handle("Impossible de sauvegarder le fichier " + inFile.getAbsolutePath(), e);
}
 
}
 
public String fetchEncodedKey(SQLTable table) {
final SQLSelect select = new SQLSelect();
select.addSelect(table.getField("VALUE"));
select.setWhere(new Where(table.getField("NAME"), "=", AttachmentSQLElement.EDM_KEY_METADATA));
final List<?> rows = table.getDBSystemRoot().getDataSource().executeCol(select.asString());
if (rows.size() == 1) {
return rows.get(0).toString();
}
return null;
}
 
public void createKeyOnDatabase(SQLTable table) throws NoSuchAlgorithmException {
final String s = fetchEncodedKey(table);
if (s != null) {
throw new IllegalStateException("key alread exists");
}
 
final SQLInsert insert = new SQLInsert();
insert.add(table.getField("NAME"), AttachmentSQLElement.EDM_KEY_METADATA);
insert.add(table.getField("VALUE"), generateBase64Key());
table.getDBSystemRoot().getDataSource().execute(insert.asString());
}
 
public File getFile(Attachment attachment) {
 
final ComptaPropsConfiguration config = ComptaPropsConfiguration.getInstanceCompta();
202,6 → 301,21
}
}
final File outFile = new File(f, fileName);
if (attachment.isEncrypted() && outFile.length() > 0) {
try {
final byte[] bytes = FileUtils.readBytes(outFile);
final String encodeKey = fetchEncodedKey(config.getRootSociete().getTable("FWK_SCHEMA_METADATA"));
if (encodeKey == null) {
throw new IllegalStateException("missing key");
}
final byte[] decrypted = decrypt(getSecretKey(encodeKey), bytes);
Files.write(outFile.toPath(), decrypted);
} catch (Exception e) {
ExceptionHandler.handle("Impossible de decrypter le fichier\n" + outFile.getAbsolutePath(), e);
return null;
}
 
}
outFile.setReadOnly();
return outFile;
 
208,8 → 322,12
}
 
public void deleteFile(Attachment rowAttachment) throws SQLException, IllegalStateException {
// Delete Row
// Remove from DB first
final ComptaPropsConfiguration config = ComptaPropsConfiguration.getInstanceCompta();
config.getDirectory().getElement(AttachmentSQLElement.class).archive(rowAttachment.getId());
updateAttachmentsCountFromAttachment(rowAttachment);
 
final ComptaPropsConfiguration config = ComptaPropsConfiguration.getInstanceCompta();
if (!rowAttachment.isFolder()) {
boolean isOnCloud = config.isOnCloud();
// Delete File
237,9 → 355,7
}
}
}
// Delete Row
config.getDirectory().getElement(AttachmentSQLElement.class).archive(rowAttachment.getId());
updateAttachmentsCountFromAttachment(rowAttachment);
 
}
 
private void updateAttachmentsCountFromAttachment(Attachment rowAttachment) {
299,6 → 415,10
final String req = "UPDATE " + attachmentTable.getSQLName().quote() + " SET " + attachmentTable.getField("ID_PARENT").getQuotedName() + "=" + folderId + " WHERE "
+ attachmentTable.getKey().getQuotedName() + "=" + a.getId();
attachmentTable.getDBSystemRoot().getDataSource().execute(req);
 
}
 
public static void main(String[] args) throws NoSuchAlgorithmException {
System.err.println("AttachmentUtils.main() key : " + new AttachmentUtils().generateBase64Key());
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/edm/AttachmentSQLElement.java
22,8 → 22,22
 
public class AttachmentSQLElement extends ComptaSQLConfElement {
 
public static final String EDM_KEY_METADATA = "EDM_KEY";
 
public static final String DIRECTORY_PREFS = "EDMdirectory";
 
public static final String ITEM_SOURCE_TABLE = "source.table";
public static final String ITEM_SOURCE_ID = "source.id";
public static final String ITEM_NAME = "name";
public static final String ITEM_MIMETYPE = "mimetype";
public static final String ITEM_FILENAME = "filename";
public static final String ITEM_STORAGE_PATH = "storage.path";
public static final String ITEM_THUMBNAIL = "thumbnail";
public static final String ITEM_THUMBNAIL_WIDTH = "thumbnail.width";
public static final String ITEM_THUMBNAIL_HEIGHT = "thumbnail.height";
public static final String ITEM_TAG = "tag";
public static final String ITEM_PARENT = "parent.id";
 
public AttachmentSQLElement() {
super("ATTACHMENT", "un attachement", "attachements");
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/edm/Attachment.java
29,7 → 29,7
private String sourceTable;
private int sourceId;
private int parentId;
 
private boolean encrypted;
public static final String MIMETYPE_FOLDER = "inode/directory";
 
public Attachment(SQLRowValues rowAttachment) {
43,14 → 43,15
this.sourceTable = rowAttachment.getString("SOURCE_TABLE");
this.sourceId = rowAttachment.getInt("SOURCE_ID");
this.parentId = rowAttachment.getInt("ID_PARENT");
this.encrypted = rowAttachment.getBoolean("ENCRYPTED");
}
 
public int getId() {
return id;
return this.id;
}
 
public String getName() {
return name;
return this.name;
}
 
public void setName(String newName) {
58,35 → 59,35
}
 
public String getMimeType() {
return mimeType;
return this.mimeType;
}
 
public String getFileName() {
return fileName;
return this.fileName;
}
 
public int getFileSize() {
return fileSize;
return this.fileSize;
}
 
public String getStorageFileName() {
return storageFileName;
return this.storageFileName;
}
 
public String getStoragePath() {
return storagePath;
return this.storagePath;
}
 
public String getSourceTable() {
return sourceTable;
return this.sourceTable;
}
 
public int getSourceId() {
return sourceId;
return this.sourceId;
}
 
public int getParentId() {
return parentId;
return this.parentId;
}
 
public boolean isFolder() {
93,6 → 94,10
return this.mimeType.equals(MIMETYPE_FOLDER);
}
 
public boolean isEncrypted() {
return this.encrypted;
}
 
@Override
public String toString() {
return super.toString() + " attachment id:" + this.getId() + " name:" + this.getName();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/edm/AttachmentPanel.java
45,6 → 45,7
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
65,6 → 66,7
public class AttachmentPanel extends JPanel {
 
private final SQLRowAccessor rowSource;
private final Collection<SQLRowAccessor> rowSecondaires;
private List<ListDataListener> listeners = new ArrayList<>();
 
private int idParent = 1;
74,8 → 76,14
private List<FilePanel> filePanels = new ArrayList<>();
 
public AttachmentPanel(SQLRowAccessor rowSource) {
this(rowSource, Collections.emptyList());
}
 
public AttachmentPanel(SQLRowAccessor rowSource, Collection<SQLRowAccessor> rowSecondaires) {
super();
this.rowSource = rowSource;
this.rowSecondaires = rowSecondaires;
 
this.setLayout(new GridBagLayout());
this.parents.add(1);
this.parentsNames.add("Racine");
92,13 → 100,17
}
 
public void fireDataChanged() {
for (ListDataListener listDataListener : listeners) {
for (ListDataListener listDataListener : this.listeners) {
listDataListener.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, 0));
}
}
 
public int getAttachementsSize() {
return this.filePanels.size();
}
 
public void initUI() {
filePanels.clear();
this.filePanels.clear();
this.invalidate();
this.removeAll();
GridBagConstraints c = new DefaultGridBagConstraints();
106,7 → 118,7
// Recupération de la liste des fichiers
 
// TODO requete dans un SwingWorker
final SQLTable tableAttachment = rowSource.getTable().getTable("ATTACHMENT");
final SQLTable tableAttachment = this.rowSource.getTable().getTable("ATTACHMENT");
SQLRowValues rowVals = new SQLRowValues(tableAttachment);
rowVals.putNulls(tableAttachment.getFieldsName());
 
115,7 → 127,13
where = where.and(new Where(tableAttachment.getField("SOURCE_ID"), "=", this.rowSource.getID()));
 
where = where.and(new Where(tableAttachment.getField("ID_PARENT"), "=", this.idParent));
for (SQLRowAccessor rowSecondaire : this.rowSecondaires) {
 
Where whereSec = new Where(tableAttachment.getField("SOURCE_TABLE"), "=", rowSecondaire.getTable().getName());
whereSec = whereSec.and(new Where(tableAttachment.getField("SOURCE_ID"), "=", rowSecondaire.getID()));
 
where = where.or(whereSec);
}
final List<SQLRowValues> rAttachments = fetcher.fetch(where);
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.WEST;
211,7 → 229,7
public void actionPerformed(ActionEvent e) {
AttachmentUtils utils = new AttachmentUtils();
try {
utils.createFolder("Nouveau dossier", rowSource, idParent);
utils.createFolder("Nouveau dossier", AttachmentPanel.this.rowSource, AttachmentPanel.this.idParent);
} catch (SQLException e1) {
JOptionPane.showMessageDialog(null, "Impossible de créer le dossier.", "Erreur", JOptionPane.ERROR_MESSAGE);
}
229,12 → 247,17
fd.setVisible(true);
final String fileName = fd.getFile();
if (fileName != null) {
try {
File inFile = new File(fd.getDirectory(), fileName);
AttachmentUtils utils = new AttachmentUtils();
utils.uploadFile(inFile, rowSource, idParent);
utils.uploadFile(inFile, AttachmentPanel.this.rowSource, AttachmentPanel.this.idParent);
initUI();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(AttachmentPanel.this, "Erreur lors de l'ajout du fichier " + fileName + "(" + ex.getMessage() + ")");
}
}
}
});
 
ScrollablePanel files = new ScrollablePanel() {
350,7 → 373,6
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Transferable t = dtde.getTransferable();
try {
 
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
@SuppressWarnings("unchecked")
List<File> fileList = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
362,10 → 384,15
if (cancelledByUser) {
break;
}
try {
if (!f.isDirectory()) {
utils.uploadFile(f, rowSource, idParent);
utils.uploadFile(f, AttachmentPanel.this.rowSource, AttachmentPanel.this.idParent);
}
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(AttachmentPanel.this, "Erreur lors de l'ajout du fichier " + f.getAbsolutePath() + "(" + ex.getMessage() + ")");
}
}
initUI();
}
} catch (Exception e) {
379,7 → 406,7
}
 
public Set<Attachment> getSelectedAttachments() {
return selectedAttachments;
return this.selectedAttachments;
}
 
public void select(Attachment a) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/shipment/component/BonDeLivraisonSQLComponent.java
391,10 → 391,9
} else {
tableBonItem.setRowCatComptable(null);
}
if (!isFilling()) {
tableBonItem.setClient(rowClient, true);
}
 
tableBonItem.setClient(rowClient, !isFilling());
 
} else {
comboContact.getRequest().setWhere(Where.FALSE);
tableBonItem.setRowCatComptable(null);
409,7 → 408,7
// Commercial
JLabel labelCommercial = new JLabel(getLabelFor("ID_COMMERCIAL"));
labelCommercial.setHorizontalAlignment(SwingConstants.RIGHT);
 
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx++;
c.weightx = 0;
this.add(labelCommercial, c);
1086,9 → 1085,17
private void updateStock(int id) throws SQLException {
 
SQLPreferences prefs = new SQLPreferences(getTable().getDBRoot());
if (!prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_FACT, true)) {
 
// Check if tr from bl or cmd pour DS
boolean stockWithBL = !prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_FACT, true);
if (getTable().getForeignTable("ID_CLIENT").contains("NOTE_2018")) {
SQLRow row = getTable().getRow(id);
List<SQLRow> trCmd = row.getReferentRows(getTable().getTable("TR_COMMANDE_CLIENT"));
if (!trCmd.isEmpty()) {
stockWithBL = true;
}
}
if (stockWithBL) {
SQLRow row = getTable().getRow(id);
StockItemsUpdater stockUpdater = new StockItemsUpdater(new StockLabel() {
@Override
public String getLabel(SQLRowAccessor rowOrigin, SQLRowAccessor rowElt) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/credit/component/AvoirClientSQLComponent.java
118,8 → 118,6
private ElementComboBox selectContact;
private JLabel labelCompteServ;
private ISQLCompteSelector compteSelService;
private static final SQLTable TABLE_PREFS_COMPTE = Configuration.getInstance().getBase().getTable("PREFS_COMPTE");
private static final SQLRow ROW_PREFS_COMPTE = TABLE_PREFS_COMPTE.getRow(2);
private final boolean displayDpt;
private final ElementComboBox comboDpt = new ElementComboBox();
 
194,10 → 192,9
boxTarif.setValue(foreignRow.getID());
}
}
if (!isFilling()) {
AvoirClientSQLComponent.this.table.setClient(row, true);
}
 
AvoirClientSQLComponent.this.table.setClient(row, !isFilling());
 
} else {
table.setRowCatComptable(null);
selectContact.getRequest().setWhere(Where.FALSE);
221,7 → 218,8
 
 
// Selection du compte de service
int idCompteVenteService = ROW_PREFS_COMPTE.getInt("ID_COMPTE_PCE_VENTE_SERVICE");
final SQLRow prefs = getTable().getDBRoot().getTable("PREFS_COMPTE").getTable().getRow(2);
int idCompteVenteService = prefs.getInt("ID_COMPTE_PCE_VENTE_SERVICE");
if (idCompteVenteService <= 1) {
try {
idCompteVenteService = ComptePCESQLElement.getIdComptePceDefault("VentesServices");
654,20 → 652,38
JLabel labelPortHT = new JLabel(getLabelFor("PORT_HT"));
labelPortHT.setHorizontalAlignment(SwingConstants.RIGHT);
cFrais.gridy++;
// panelPortEtRemise.add(labelPortHT, cFrais);
panelPortEtRemise.add(labelPortHT, cFrais);
cFrais.gridx++;
DefaultGridBagConstraints.lockMinimumSize(textPortHT);
// panelPortEtRemise.add(textPortHT, cFrais);
panelPortEtRemise.add(textPortHT, cFrais);
 
JLabel labelTaxeHT = new JLabel(getLabelFor("ID_TAXE_PORT"));
labelTaxeHT.setHorizontalAlignment(SwingConstants.RIGHT);
cFrais.gridx = 1;
cFrais.gridy++;
panelPortEtRemise.add(labelTaxeHT, cFrais);
cFrais.gridx++;
SQLRequestComboBox boxTaxePort = new SQLRequestComboBox(false, 8);
panelPortEtRemise.add(boxTaxePort, cFrais);
this.addView(boxTaxePort, "ID_TAXE_PORT", REQ);
 
boxTaxePort.addValueListener(new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
totalTTC.updateTotal();
}
});
 
// Remise
JLabel labelRemiseHT = new JLabel(getLabelFor("REMISE_HT"));
labelRemiseHT.setHorizontalAlignment(SwingConstants.RIGHT);
cFrais.gridy++;
cFrais.gridx = 1;
// panelPortEtRemise.add(labelRemiseHT, cFrais);
panelPortEtRemise.add(labelRemiseHT, cFrais);
cFrais.gridx++;
DefaultGridBagConstraints.lockMinimumSize(textRemiseHT);
// panelPortEtRemise.add(textRemiseHT, cFrais);
panelPortEtRemise.add(textRemiseHT, cFrais);
cFrais.gridy++;
 
c.gridx++;
699,7 → 715,7
JTextField poids = new JTextField();
if (getTable().getFieldsName().contains("T_POIDS"))
addSQLObject(poids, "T_POIDS");
this.totalTTC = new TotalPanel(this.table, fieldEco, fieldHT, fieldTVA, fieldTTC, textPortHT, textRemiseHT, fieldService, null, fieldDevise, poids, null);
this.totalTTC = new TotalPanel(this.table, fieldEco, fieldHT, fieldTVA, fieldTTC, textPortHT, textRemiseHT, fieldService, null, fieldDevise, poids, null, boxTaxePort, null);
totalTTC.setOpaque(false);
c.gridx++;
c.gridy = 0;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/component/CommandeClientSQLComponent.java
25,6 → 25,7
import org.openconcerto.erp.core.customerrelationship.customer.ui.AdresseType;
import org.openconcerto.erp.core.customerrelationship.customer.ui.CategorieComptableChoiceUI;
import org.openconcerto.erp.core.finance.tax.model.TaxeCache;
import org.openconcerto.erp.core.sales.order.element.CommandeClientSQLElement;
import org.openconcerto.erp.core.sales.order.report.CommandeClientXmlSheet;
import org.openconcerto.erp.core.sales.order.ui.CommandeClientItemTable;
import org.openconcerto.erp.core.sales.order.ui.EtatCommandeClient;
62,7 → 63,6
import org.openconcerto.ui.TitledSeparator;
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.Color;
import java.awt.GridBagConstraints;
72,6 → 72,7
import java.sql.SQLException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import javax.swing.JLabel;
256,9 → 257,7
// }
// table.setTarif(foreignRow, true);
}
if (!isFilling()) {
table.setClient(row, true);
}
table.setClient(row, !isFilling());
 
} else {
if (!isFilling()) {
552,8 → 551,20
pane.add("Facturation", this.tableFacturationItem);
if (prefs.getBoolean(GestionCommercialeGlobalPreferencePanel.CHIFFRAGE_COMMANDE_CLIENT, false)) {
this.tableChiffrageItem = new ChiffrageCommandeTable(this);
this.tableChiffrageItem.getRowValuesTable().setEditable(((CommandeClientSQLElement) getElement()).isChiffrageEditableInUI());
pane.add("Chiffrage", this.tableChiffrageItem);
}
if (this.getTable().contains("INFOS_DEVIS")) {
JPanel panelInfosDevis = new JPanel(new GridBagLayout());
DefaultGridBagConstraints cI = new DefaultGridBagConstraints();
cI.weightx = 1;
cI.weighty = 1;
cI.fill = GridBagConstraints.BOTH;
ITextArea infosDevis = new ITextArea();
panelInfosDevis.add(new JScrollPane(infosDevis), cI);
this.addView(infosDevis, "INFOS_DEVIS");
pane.add("Informations devis", panelInfosDevis);
}
this.add(pane, c);
 
DeviseField textPortHT = new DeviseField(5);
747,6 → 758,8
textPoidsTotal.setText(String.valueOf(CommandeClientSQLComponent.this.table.getPoidsTotal()));
}
});
 
this.addView(this.table.getRowValuesTable(), "");
DefaultGridBagConstraints.lockMinimumSize(comboClient);
DefaultGridBagConstraints.lockMinimumSize(comboCommercial);
DefaultGridBagConstraints.lockMinimumSize(comboDevis);
1006,4 → 1019,50
this.table.setDateDevise(r.getDate("DATE").getTime());
}
}
 
/**
* Création d'une commande à partir d'un devis existant
*
* @param idCommande
*
*/
public void loadCommandeExistant(final int idCommande) {
 
final SQLElement commande =getElement();
final SQLElement commandeElt = getElement().getDirectory().getElement("COMMANDE_CLIENT_ELEMENT");
 
// On duplique la commande
if (idCommande > 1) {
final SQLRow row = getTable().getRow(idCommande);
final SQLRowValues rowVals = new SQLRowValues(getTable());
rowVals.put("ID_CLIENT", row.getInt("ID_CLIENT"));
if (row.getObject("ID_TARIF") != null && !row.isForeignEmpty("ID_TARIF")) {
rowVals.put("ID_TARIF", row.getInt("ID_TARIF"));
}
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(getElement().getClass()));
 
this.select(rowVals);
}
 
// On duplique les elements des commandes
final List<SQLRow> myListItem = getTable().getRow(idCommande).getReferentRows(commandeElt.getTable());
 
if (myListItem.size() != 0) {
this.table.getModel().clearRows();
 
for (final SQLRow rowElt : myListItem) {
 
final SQLRowValues rowVals = rowElt.createUpdateRow();
rowVals.clearPrimaryKeys();
this.table.getModel().addRow(rowVals);
final int rowIndex = this.table.getModel().getRowCount() - 1;
this.table.getModel().fireTableModelModified(rowIndex);
}
} else {
this.table.getModel().clearRows();
}
this.table.getModel().fireTableDataChanged();
this.table.repaint();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/CommandeClientSQLElement.java
52,6 → 52,7
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanel;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction;
245,6 → 246,10
mouseSheetXmlListeListener.setGenerateHeader(true);
mouseSheetXmlListeListener.setShowHeader(true);
 
// Dupliquer
RowAction cloneAction = getCloneAction();
allowedActions.add(cloneAction);
 
allowedActions.add(bonAction);
allowedActions.add(factureAction);
allowedActions.add(acompteAction);
254,6 → 259,16
getRowActions().addAll(allowedActions);
}
 
private boolean chiffrageEditableInUI = true;
 
public void setChiffrageEditableInUI(boolean chiffrageEditableInUI) {
this.chiffrageEditableInUI = chiffrageEditableInUI;
}
 
public boolean isChiffrageEditableInUI() {
return this.chiffrageEditableInUI;
}
 
@Override
protected void setupLinks(SQLElementLinksSetup links) {
super.setupLinks(links);
725,7 → 740,26
}
}
 
public RowAction getCloneAction() {
return new RowAction(new AbstractAction() {
 
public void actionPerformed(ActionEvent e) {
SQLRowAccessor selectedRow = IListe.get(e).getSelectedRow();
 
EditFrame editFrame = new EditFrame(CommandeClientSQLElement.this, EditPanel.CREATION);
 
((CommandeClientSQLComponent) editFrame.getSQLComponent()).loadCommandeExistant(selectedRow.getID());
editFrame.setVisible(true);
}
}, true, "sales.quote.clone") {
@Override
public boolean enabledFor(java.util.List<org.openconcerto.sql.model.SQLRowValues> selection) {
return (selection != null && selection.size() == 1);
}
};
}
 
@Override
protected String createCode() {
return "sales.order";
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/FacturationCommandeClientSQLElement.java
27,6 → 27,7
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.graph.Path;
import org.openconcerto.sql.view.EditFrame;
import org.openconcerto.sql.view.EditPanelListener;
43,6 → 44,7
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
117,6 → 119,11
public void inserted(int id) {
try {
sel.createEmptyUpdateRow().put("ID_SAISIE_VENTE_FACTURE", id).commit();
SQLTable tableFacture = getForeignElement("ID_SAISIE_VENTE_FACTURE").getTable();
SQLRowValues rowValsFact = new SQLRowValues(tableFacture);
rowValsFact.put(tableFacture.getKey().getName(), id);
rowValsFact.put("ID_FACTURATION_COMMANDE_CLIENT", sel.getID());
rowValsFact.commit();
} catch (SQLException e) {
ExceptionHandler.handle("Erreur lors de l'affectation de la facture", e);
}
223,7 → 230,7
res.init();
res.getColumn(getTable().getField("POURCENT")).setRenderer(new DeviseTableCellRenderer());
res.getColumn(getTable().getField("TYPE_FACTURE")).setRenderer(new TypeFactureCommandeCellRenderer());
final BaseSQLTableModelColumn pourcentFact = new BaseSQLTableModelColumn("Montant facturé", BigDecimal.class) {
final BaseSQLTableModelColumn pourcentFact = new BaseSQLTableModelColumn("Montant à facturer", BigDecimal.class) {
 
@Override
protected Object show_(SQLRowAccessor r) {
241,6 → 248,31
};
pourcentFact.setRenderer(new DeviseTableCellRenderer());
res.getColumns().add(pourcentFact);
 
final BaseSQLTableModelColumn montantFact = new BaseSQLTableModelColumn("Montant facturé", BigDecimal.class) {
 
@Override
protected Object show_(SQLRowAccessor r) {
Collection<? extends SQLRowAccessor> rows = r.getReferentRows(getForeignElement("ID_SAISIE_VENTE_FACTURE").getTable());
long ht = 0;
for (SQLRowAccessor sqlRowAccessor : rows) {
ht += sqlRowAccessor.getLong("T_TTC");
}
 
return new BigDecimal(ht).movePointLeft(2);
}
 
@Override
public Set<FieldPath> getPaths() {
Path p = new Path(getTable());
Path p2 = p.add(p.getFirst().getField("ID_COMMANDE_CLIENT"));
Path p3 = new Path(getTable());
p3 = p3.add(getTable().getForeignTable("ID_SAISIE_VENTE_FACTURE").getField("ID_FACTURATION_COMMANDE_CLIENT"));
return CollectionUtils.createSet(new FieldPath(p, "POURCENT"), new FieldPath(p2, "T_TTC"), new FieldPath(p3, "T_TTC"), new FieldPath(p2, "T_HT"), new FieldPath(p3, "T_HT"));
}
};
montantFact.setRenderer(new DeviseTableCellRenderer());
res.getColumns().add(montantFact);
super._initTableSource(res);
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/order/element/CommandeClientElementSQLElement.java
171,6 → 171,10
final SQLTable tableCmdElt = tableStock.getTable("COMMANDE_ELEMENT");
selCmdElt.addSelectStar(tableCmdElt);
Where w = new Where(tableCmdElt.getField("RECU_FORCED"), "=", Boolean.FALSE).and(new Where(tableCmdElt.getField("RECU"), "=", Boolean.FALSE));
w = w.and(Where.createRaw(
tableCmdElt.getField("QTE_RECUE").getQuotedName() + " < (" + tableCmdElt.getField("QTE").getQuotedName() + "*" + tableCmdElt.getField("QTE_UNITAIRE").getQuotedName() + ")",
tableCmdElt.getField("QTE_UNITAIRE"), tableCmdElt.getField("QTE"), tableCmdElt.getField("QTE_RECUE")));
 
selCmdElt.setWhere(w);
List<SQLRow> res = SQLRowListRSH.execute(selCmdElt);
if (res != null && res.size() > 0) {
193,6 → 197,10
final SQLTable tableCmdElt = tableStock.getTable("COMMANDE_CLIENT_ELEMENT");
selCmdElt.addSelectStar(tableCmdElt);
Where w = new Where(tableCmdElt.getField("LIVRE_FORCED"), "=", Boolean.FALSE).and(new Where(tableCmdElt.getField("LIVRE"), "=", Boolean.FALSE));
w = w.and(Where.createRaw(
tableCmdElt.getField("QTE_LIVREE").getQuotedName() + " < (" + tableCmdElt.getField("QTE").getQuotedName() + "*" + tableCmdElt.getField("QTE_UNITAIRE").getQuotedName() + ")",
tableCmdElt.getField("QTE_UNITAIRE"), tableCmdElt.getField("QTE"), tableCmdElt.getField("QTE_LIVREE")));
 
selCmdElt.setWhere(w);
List<SQLRow> res = SQLRowListRSH.execute(selCmdElt);
if (res != null && res.size() > 0) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/account/VenteFactureSituationSQLComponent.java
207,9 → 207,11
 
@Override
public void update(DocumentEvent e) {
if (!isFilling()) {
Acompte a = acompteField.getValue();
table.calculPourcentage(a, TypeCalcul.CALCUL_FACTURABLE);
}
}
 
};
acompteField.getDocument().addDocumentListener(listenerAcompteField);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/component/SaisieVenteFactureSQLComponent.java
161,9 → 161,7
tableFacture.setRowCatComptable(null);
}
 
if (!isFilling()) {
tableFacture.setClient(rowCli, true);
}
SaisieVenteFactureSQLComponent.this.tableFacture.setClient(rowCli, !isFilling());
 
if (getMode() == SQLComponent.Mode.INSERTION || !isFilling()) {
SQLElement sqleltModeRegl = Configuration.getInstance().getDirectory().getElement("MODE_REGLEMENT");
301,7 → 299,7
public void propertyChange(PropertyChangeEvent evt) {
if (!isFilling() && dateSaisie.getValue() != null) {
 
final String nextNumero = NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, dateSaisie.getValue(), defaultNum);
final String nextNumero = NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), dateSaisie.getValue(), defaultNum);
 
if (textNumeroUnique.getText().trim().length() > 0 && !nextNumero.equalsIgnoreCase(textNumeroUnique.getText())) {
 
1415,11 → 1413,10
rowFacture = getTable().getRow(idSaisieVF);
// incrémentation du numéro auto
final SQLRow rowNum = comboNumAuto == null ? this.tableNum.getRow(2) : comboNumAuto.getSelectedRow();
if (NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, rowFacture.getDate("DATE").getTime(), rowNum)
.equalsIgnoreCase(this.textNumeroUnique.getText().trim())) {
if (NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), rowFacture.getDate("DATE").getTime(), rowNum).equalsIgnoreCase(this.textNumeroUnique.getText().trim())) {
SQLRowValues rowVals = rowNum.createEmptyUpdateRow();
 
String labelNumberFor = NumerotationAutoSQLElement.getLabelNumberFor(SaisieVenteFactureSQLElement.class);
String labelNumberFor = NumerotationAutoSQLElement.getLabelNumberFor(getElement().getClass());
int val = rowNum.getInt(labelNumberFor);
val++;
rowVals.put(labelNumberFor, Integer.valueOf(val));
1608,9 → 1605,9
SQLRowValues rowVals = new SQLRowValues(fact.getTable());
rowVals.put("ID_CLIENT", row.getInt("ID_CLIENT"));
if (getTable().contains("ID_NUMEROTATION_AUTO")) {
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new Date(), row.getForeign("ID_NUMEROTATION_AUTO")));
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new Date(), row.getForeign("ID_NUMEROTATION_AUTO")));
} else {
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new Date()));
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new Date()));
}
rowVals.put("NOM", row.getObject("NOM"));
this.select(rowVals);
1648,7 → 1645,7
SQLRowValues rowVals = new SQLRowValues(fact.getTable());
rowVals.put("ID_CLIENT", row.getInt("ID_CLIENT"));
rowVals.put("ID_AFFAIRE", row.getInt("ID_AFFAIRE"));
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new Date()));
rowVals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new Date()));
rowVals.put("NOM", "Acompte de " + GestionDevise.currencyToString(acompte) + "€");
this.select(rowVals);
}
1808,9 → 1805,9
final ComptaPropsConfiguration comptaPropsConfiguration = ((ComptaPropsConfiguration) Configuration.getInstance());
if (getTable().contains("ID_NUMEROTATION_AUTO")) {
vals.put("ID_NUMEROTATION_AUTO", this.defaultNum.getID());
vals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new Date(), vals.getForeign("ID_NUMEROTATION_AUTO")));
vals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new Date(), vals.getForeign("ID_NUMEROTATION_AUTO")));
} else {
vals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new Date()));
vals.put("NUMERO", NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new Date()));
}
int idCompteVenteProduit = rowPrefsCompte.getInt("ID_COMPTE_PCE_VENTE_PRODUIT");
if (idCompteVenteProduit <= 1) {
1852,7 → 1849,7
public void setDefaults() {
this.resetValue();
 
this.textNumeroUnique.setText(NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new java.util.Date(), defaultNum));
this.textNumeroUnique.setText(NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new java.util.Date(), defaultNum));
this.tableFacture.getModel().clearRows();
}
 
1870,7 → 1867,7
public void setPrevisonnelle(boolean b) {
this.checkPrevisionnelle.setSelected(b);
if (!b) {
this.textNumeroUnique.setText(NumerotationAutoSQLElement.getNextNumero(SaisieVenteFactureSQLElement.class, new Date()));
this.textNumeroUnique.setText(NumerotationAutoSQLElement.getNextNumero(getElement().getClass(), new Date()));
}
}
 
1916,6 → 1913,15
SQLPreferences prefs = SQLPreferences.getMemCached(getTable().getDBRoot());
if (prefs.getBoolean(GestionArticleGlobalPreferencePanel.STOCK_FACT, true)) {
SQLRow row = getTable().getRow(id);
 
// Check if tr from bl or cmd pour DS
if (getTable().getForeignTable("ID_CLIENT").contains("NOTE_2018")) {
List<SQLRow> trCmd = row.getReferentRows(getTable().getTable("TR_COMMANDE_CLIENT"));
if (!trCmd.isEmpty()) {
return;
}
}
 
StockItemsUpdater stockUpdater = new StockItemsUpdater(new StockLabel() {
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/element/EcheanceClientSQLElement.java
25,6 → 25,7
import org.openconcerto.erp.core.finance.payment.element.EncaisserMontantSQLElement;
import org.openconcerto.erp.core.sales.invoice.action.ImportReglementSage;
import org.openconcerto.erp.core.sales.invoice.report.MailRelanceCreator;
import org.openconcerto.erp.core.sales.invoice.report.SituationCompteClientPanel;
import org.openconcerto.erp.core.sales.invoice.report.VenteFactureXmlSheet;
import org.openconcerto.erp.rights.ComptaUserRight;
import org.openconcerto.sql.Configuration;
62,6 → 63,7
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.EmailComposer;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.PanelFrame;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.ExceptionHandler;
213,7 → 215,18
}, true);
action.setPredicate(IListeEvent.createTotalRowCountPredicate(0, Integer.MAX_VALUE));
getRowActions().add(action);
 
PredicateRowAction actionSituation = new PredicateRowAction(new AbstractAction("Générer une situationde compte") {
 
@Override
public void actionPerformed(ActionEvent e) {
PanelFrame frame = new PanelFrame(new SituationCompteClientPanel(ComptaPropsConfiguration.getInstanceCompta()), "Situation client");
frame.setVisible(true);
}
}, true);
actionSituation.setPredicate(IListeEvent.createSelectionCountPredicate(0, Integer.MAX_VALUE));
getRowActions().add(actionSituation);
}
 
if (UserRightsManager.getCurrentUserRights().haveRight(ComptaUserRight.MENU)) {
RowAction actionCancel = new RowAction(new AbstractAction("Annuler la régularisation en comptabilité") {
550,6 → 563,7
SQLRow rowMvtSource = getTable().getTable("MOUVEMENT").getRow(idMvtSource);
 
if (!rowMvtSource.getString("SOURCE").equalsIgnoreCase("SAISIE_VENTE_FACTURE")) {
JOptionPane.showMessageDialog(null, "Impossible de relancer un échéance qui n'est pas issue d'une facture.");
return;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/report/SituationCompteXmlSheet.java
New file
0,0 → 1,203
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.invoice.report;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml;
import org.openconcerto.erp.preferences.PrinterNXProps;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;
 
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class SituationCompteXmlSheet extends AbstractListeSheetXml {
 
private final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
private SQLElement eltEch;
private SQLElement eltVf;
private ComptaPropsConfiguration conf;
 
public SituationCompteXmlSheet(ComptaPropsConfiguration conf, SQLRow rowClient) {
super(rowClient);
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter");
this.eltEch = conf.getDirectory().getElement("ECHEANCE_CLIENT");
this.conf = conf;
}
 
@Override
protected String getStoragePathP() {
return "Autres";
}
 
public String getDefaultTemplateId() {
return "SituationCompte";
}
 
private Date d = null;
 
@Override
public String getName() {
if (this.d == null) {
this.d = new Date();
}
return "SituationCompte-" + this.d.getTime();
}
 
protected void createListeValues() {
 
// On récupére les échéances en cours
final SQLTable echTable = eltEch.getTable();
SQLRowValues rowVals = new SQLRowValues(echTable);
rowVals.putNulls("DATE", "MONTANT");
rowVals.putRowValues("ID_SAISIE_VENTE_FACTURE").putNulls("NUMERO", "NET_A_PAYER", "DATE", "NOM");
Where w = new Where(echTable.getField("REGLE"), "=", Boolean.FALSE);
w = w.and(new Where(echTable.getField("REG_COMPTA"), "=", Boolean.FALSE));
w = w.and(new Where(echTable.getField("ID_CLIENT"), "=", row.getID()));
 
SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowVals);
fetcher.addSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
 
@Override
public SQLSelect transformChecked(SQLSelect input) {
input.addFieldOrder(echTable.getField("DATE"));
 
return input;
}
}, 0);
List<SQLRowValues> result = fetcher.fetch(w);
 
List<Map<String, Object>> listValues = new ArrayList<Map<String, Object>>();
Map<Integer, String> styleValues = new HashMap<Integer, String>();
BigDecimal totalRegle = BigDecimal.ZERO;
BigDecimal totalEch = BigDecimal.ZERO;
BigDecimal totalEchPasse = BigDecimal.ZERO;
Calendar today = Calendar.getInstance();
for (SQLRowValues sqlRow : result) {
Map<String, Object> mValues = new HashMap<String, Object>();
final Calendar dateEch = sqlRow.getDate("DATE");
mValues.put("DATE_ECHEANCE", dateFormat.format(dateEch.getTime()));
final BigDecimal montantDu = new BigDecimal(sqlRow.getLong("MONTANT"));
mValues.put("DU", montantDu);
 
totalEch = totalEch.add(montantDu);
 
SQLRowAccessor rowFact = sqlRow.getNonEmptyForeign("ID_SAISIE_VENTE_FACTURE");
final BigDecimal regle;
if (rowFact != null) {
mValues.put("PIECE", rowFact.getString("NUMERO"));
mValues.put("LIBELLE", rowFact.getString("NOM"));
mValues.put("DATE", dateFormat.format(rowFact.getDate("DATE").getTime()));
final BigDecimal montantFact = new BigDecimal(rowFact.getLong("NET_A_PAYER"));
regle = montantFact.subtract(montantDu);
mValues.put("DU", montantFact);
mValues.put("REGLE", montantFact.subtract(montantDu));
mValues.put("SOLDE", montantDu);
 
} else {
regle = BigDecimal.ZERO;
mValues.put("SOLDE", montantDu);
}
if (dateEch.before(today)) {
totalEchPasse = totalEchPasse.add(montantDu);
styleValues.put(listValues.size(), "Normal");
} else {
styleValues.put(listValues.size(), "Titre 1");
}
totalRegle = totalRegle.add(regle);
 
// SQLRow rowClient = sqlRow.getForeignRow("ID_CLIENT");
 
listValues.add(mValues);
 
// List<SQLRow> enc = sqlRow.getReferentRows(eltEncElt.getTable());
//
// for (SQLRow sqlRow2 : enc) {
// Map<String, Object> mValuesEnc = new HashMap<String, Object>();
// SQLRow rowEnc = sqlRow2.getForeignRow("ID_ENCAISSER_MONTANT");
// SQLRow rowMdr = rowEnc.getForeignRow("ID_MODE_REGLEMENT");
// mValuesEnc.put("NUMERO_FACTURE", "");
// mValuesEnc.put("REFERENCE", rowMdr.getString("NOM"));
// mValuesEnc.put("DATE", dateFormat.format(rowEnc.getDate("DATE").getTime()));
// mValuesEnc.put("NOM_CLIENT", "");
// mValuesEnc.put("CODE_CLIENT", "");
// mValuesEnc.put("TELEPHONE", "");
// mValuesEnc.put("MODE_REGLEMENT",
// rowMdr.getForeignRow("ID_TYPE_REGLEMENT").getString("NOM"));
// mValuesEnc.put("MONTANT",
// GestionDevise.currencyToString(sqlRow2.getLong("MONTANT_REGLE")));
// styleValues.put(listValues.size(), "Titre 1");
// listValues.add(mValuesEnc);
//
// }
// if (enc != null && enc.size() > 0) {
// Map<String, Object> mValuesEnc = new HashMap<String, Object>();
// mValuesEnc.put("DATE", dateFormat.format(sqlRow.getDate("DATE").getTime()));
// mValuesEnc.put("MODE_REGLEMENT", "Restant à régler");
// mValuesEnc.put("MONTANT", GestionDevise.currencyToString(sqlRow.getLong("MONTANT")));
// styleValues.put(listValues.size(), "Titre 1");
// listValues.add(mValuesEnc);
// }
 
}
 
SQLRow rowSoc = conf.getRowSociete();
SQLRow adrSoc = rowSoc.getForeign("ID_ADRESSE_COMMON");
 
Map<String, Object> sheetVals = new HashMap<String, Object>();
 
sheetVals.put("TOTAL_REGLE", totalRegle);
sheetVals.put("TOTAL_ECHEANCE", totalEch);
sheetVals.put("TOTAL_FUTUR", totalEch.subtract(totalEchPasse));
sheetVals.put("TOTAL_PASSE", totalEchPasse);
 
sheetVals.put("NOM_CLIENT", row.getString("NOM"));
sheetVals.put("DATE", new Date());
sheetVals.put("CODE_CLIENT", row.getString("CODE"));
sheetVals.put("TELEPHONE", row.getString("TEL"));
SQLRow rowAdrClient = row.getForeign("ID_ADRESSE");
sheetVals.put("ADRESSE", rowAdrClient.getString("RUE"));
sheetVals.put("VILLE", rowAdrClient.getString("CODE_POSTAL") + " " + rowAdrClient.getString("VILLE"));
 
sheetVals.put("SOCIETE_NOM", rowSoc.getString("NOM"));
sheetVals.put("SOCIETE_TEL", rowSoc.getString("NUM_TEL"));
sheetVals.put("SOCIETE_SIRET", rowSoc.getString("NUM_SIRET"));
sheetVals.put("SOCIETE_APE", rowSoc.getString("NUM_APE"));
sheetVals.put("SOCIETE_NII", rowSoc.getString("NUM_NII"));
sheetVals.put("SOCIETE_BIC", rowSoc.getString("BIC"));
sheetVals.put("SOCIETE_IBAN", rowSoc.getString("IBAN"));
sheetVals.put("SOCIETE_MAIL", rowSoc.getString("MAIL"));
 
sheetVals.put("SOCIETE_ADRESSE", adrSoc.getString("RUE"));
sheetVals.put("SOCIETE_VILLE", adrSoc.getString("CODE_POSTAL") + " " + adrSoc.getString("VILLE"));
this.mapAllSheetValues.put(0, sheetVals);
this.listAllSheetValues.put(0, listValues);
this.styleAllSheetValues.put(0, styleValues);
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/report/VenteFactureXmlSheet.java
23,6 → 23,7
public class VenteFactureXmlSheet extends AbstractSheetXMLWithDate {
 
public static final String TEMPLATE_ID = "VenteFacture";
public static final String TEMPLATE_SITUATION_SUFFIX = "Situation";
public static final String TEMPLATE_PROPERTY_NAME = "LocationFacture";
 
@Override
46,9 → 47,14
@Override
public SQLRow getRowLanguage() {
SQLRow rowClient = this.row.getForeignRow("ID_CLIENT");
 
if (rowClient.getTable().contains("ID_LANGUE")) {
return rowClient.getForeignRow("ID_LANGUE");
if (!rowClient.isForeignEmpty("ID_LANGUE")) {
return rowClient.getForeign("ID_LANGUE");
} else {
return null;
}
} else {
return super.getRowLanguage();
}
}
68,7 → 74,7
} else if (row.getBoolean("ACOMPTE")) {
type = "Acompte";
} else if (row.getBoolean("PARTIAL") || row.getBoolean("SOLDE")) {
type = "Situation";
type = TEMPLATE_SITUATION_SUFFIX;
} else {
type = null;
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/report/SituationCompteClientPanel.java
New file
0,0 → 1,118
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.invoice.report;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.EmailComposer;
import org.openconcerto.ui.JLabelBold;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.FileUtils;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
 
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
 
public class SituationCompteClientPanel extends JPanel {
 
public SituationCompteClientPanel(ComptaPropsConfiguration conf) {
super(new GridBagLayout());
 
JLabelBold title = new JLabelBold("Génération d'une situation de compte d'un client");
 
final ElementComboBox box = new ElementComboBox(true);
SQLElement element = Configuration.getInstance().getDirectory().getElement("CLIENT");
ComboSQLRequest comboRequest = element.getComboRequest(true);
// comboRequest.setUndefLabel("Tous");
box.init(element, comboRequest);
 
GridBagConstraints c = new DefaultGridBagConstraints();
c.gridwidth = 1;
c.weightx = 0;
this.add(title, c);
c.gridx++;
c.gridwidth = 1;
c.weightx = 1;
this.add(box, c);
 
final JCheckBox boxMail = new JCheckBox("Envoie par mail");
c.gridx++;
c.weightx = 0;
this.add(boxMail, c);
 
final JButton buttonValid = new JButton(new AbstractAction("Valider") {
 
@Override
public void actionPerformed(ActionEvent e) {
 
final SQLRow selectedClient = box.getSelectedRow();
new Thread() {
public void run() {
 
try {
SituationCompteXmlSheet sheet = new SituationCompteXmlSheet(conf, selectedClient);
File pdf = sheet.getOrCreatePDFDocumentFile(true);
if (boxMail.isSelected()) {
sheet.createDocument();
// sheet.showPrintAndExport(false, false, false);
 
String mail = selectedClient.getString("MAIL");
 
try {
EmailComposer.getInstance().compose(mail, "", "", pdf);
} catch (Exception exn) {
ExceptionHandler.handle(null, "Impossible de créer le courriel", exn);
}
} else {
FileUtils.openFile(pdf);
}
} catch (Exception e) {
ExceptionHandler.handle("Une erreur est survenue lors de la création du document", e);
}
};
}.start();
 
}
});
 
c.gridy++;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.EAST;
c.weightx = 0;
this.add(buttonValid, c);
 
// Listener enabled/disabled button
buttonValid.setEnabled(false);
box.addModelListener("wantedID", new PropertyChangeListener() {
 
@Override
public void propertyChange(PropertyChangeEvent arg0) {
buttonValid.setEnabled(box.getWantedID() != SQLRow.NONEXISTANT_ID && box.getWantedID() != box.getRequest().getPrimaryTable().getUndefinedID());
}
});
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/report/ReportingStockXmlSheet.java
13,8 → 13,9
package org.openconcerto.erp.core.sales.invoice.report;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.erp.generationDoc.AbstractListeSheetXml;
import org.openconcerto.erp.preferences.PrinterNXProps;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRow;
23,11 → 24,15
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.TableRef;
import org.openconcerto.sql.model.Where;
import org.openconcerto.utils.cc.ITransformer;
 
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
42,16 → 47,20
 
public static final String TEMPLATE_ID = "EtatStocks";
public static final String TEMPLATE_PROPERTY_NAME = DEFAULT_PROPERTY_NAME;
 
private int intIDDepot = DepotStockSQLElement.DEFAULT_ID;
private boolean bTousLesDepots = false;
private Date date;
private SQLElement eltArticle = Configuration.getInstance().getDirectory().getElement("ARTICLE");
private SQLElement eltStock = Configuration.getInstance().getDirectory().getElement("STOCK");
 
public ReportingStockXmlSheet(boolean fournisseur) {
super();
this.printer = PrinterNXProps.getInstance().getStringProperty("BonPrinter");
 
public ReportingStockXmlSheet(ComptaPropsConfiguration conf, Integer intIDDepot, boolean bTousLesDepots) {
this.eltArticle = conf.getDirectory().getElement("ARTICLE");
this.eltStock = conf.getDirectory().getElement("STOCK");
if (intIDDepot != null) {
this.intIDDepot = intIDDepot;
}
this.bTousLesDepots = bTousLesDepots;
}
 
@Override
public String getStoragePathP() {
73,17 → 82,33
 
protected void createListeValues() {
 
final SQLTable tableArt = eltArticle.getTable();
SQLRowValues rowVals = new SQLRowValues(tableArt);
rowVals.put("ID_FOURNISSEUR", null);
rowVals.put("ID_FAMILLE_ARTICLE", null);
rowVals.put("CODE", null);
rowVals.put("NOM", null);
rowVals.put("PA_HT", null);
rowVals.put("PV_HT", null);
rowVals.putRowValues("ID_STOCK").putNulls("QTE_REEL");
final SQLTable tableArt = this.eltArticle.getTable();
SQLRowValues rowvArticle = new SQLRowValues(tableArt);
rowvArticle.put("ID_FOURNISSEUR", null);
rowvArticle.put("ID_FAMILLE_ARTICLE", null);
rowvArticle.put("CODE", null);
rowvArticle.put("NOM", null);
rowvArticle.put("PA_HT", null);
rowvArticle.put("PV_HT", null);
 
SQLRowValuesListFetcher fetch = SQLRowValuesListFetcher.create(rowVals);
SQLRowValues rowvStock = new SQLRowValues(this.eltStock.getTable());
rowvStock.put("QTE_REEL", null).put("ID_ARTICLE", rowvArticle);
 
SQLRowValuesListFetcher fetch = SQLRowValuesListFetcher.create(rowvArticle);
 
if (!this.bTousLesDepots) {
fetch.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
@Override
public SQLSelect transformChecked(SQLSelect input) {
TableRef join = input.getAlias(ReportingStockXmlSheet.this.eltArticle.getTable().getTable("STOCK"));
 
input.setWhere(new Where(join.getField("ID_DEPOT_STOCK"), "=", ReportingStockXmlSheet.this.intIDDepot));
System.out.println(input.toString());
return input;
}
});
}
 
List<SQLRowValues> values = fetch.fetch();
 
final SQLTable tableF = tableArt.getTable("FAMILLE_ARTICLE");
119,7 → 144,11
Line lineTotal = new Line("Total", "", BigDecimal.ZERO, 0F);
final HashMap<Integer, String> style = new HashMap<Integer, String>();
for (SQLRowValues vals : values) {
Float qte = vals.getForeign("ID_STOCK").getFloat("QTE_REEL");
Collection<SQLRowValues> stocks = vals.getReferentRows(this.eltStock.getTable());
Float qte = 0f;
for (SQLRowValues stock : stocks) {
qte += stock.getFloat("QTE_REEL");
}
BigDecimal ha = BigDecimal.ZERO;
if (qte > 0) {
final BigDecimal puHA = vals.getBigDecimal("PA_HT");
213,7 → 242,7
style.put(style.keySet().size(), "Titre 1");
 
final Map<String, Object> valuesSheet = new HashMap<String, Object>();
valuesSheet.put("DATE", "Au " + dateFormat.format(new Date()));
valuesSheet.put("DATE", "Au " + this.dateFormat.format(new Date()));
//
this.listAllSheetValues.put(0, listValues);
 
239,23 → 268,23
}
 
public Float getQte() {
return qte;
return this.qte;
}
 
public String getCodeArt() {
return codeArt;
return this.codeArt;
}
 
public BigDecimal getPuHA() {
return puHA;
return this.puHA;
}
 
public String getNomArt() {
return nomArt;
return this.nomArt;
}
 
public BigDecimal getTotalHA() {
return totalHA;
return this.totalHA;
}
 
public void add(Line l) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/ImportReglementSage.java
170,7 → 170,7
 
SQLRow rowEncaisser = rowValsEncaisser.commit();
 
this.encaisserSQLElement.regleFacture(rowEncaisser);
this.encaisserSQLElement.regleFacture(rowEncaisser, null, false);
 
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/action/GenEtatStockAction.java
13,11 → 13,19
package org.openconcerto.erp.core.sales.invoice.action;
 
import org.openconcerto.erp.core.sales.invoice.report.ReportingStockXmlSheet;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.sales.invoice.ui.RapportEtatDeStockDepotSelectionPanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.ui.FrameUtil;
import org.openconcerto.ui.state.WindowStateManager;
import org.openconcerto.utils.FileUtils;
 
import java.awt.Dimension;
import java.io.File;
 
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
 
public class GenEtatStockAction extends AbstractAction {
public GenEtatStockAction() {
27,17 → 35,23
public void actionPerformed(java.awt.event.ActionEvent e) {
final Thread thread = new Thread(new Runnable() {
public void run() {
try {
 
ReportingStockXmlSheet sheet = new ReportingStockXmlSheet(false);
// Création de la fenêtre de popup de séléction du dépot.
JFrame frame = new JFrame();
frame.setTitle("Sélection des dépôts.");
frame.setPreferredSize(new Dimension(500, 130));
frame.setLocationRelativeTo(null); // la fenêtre est centrée à l'écran
 
sheet.createDocumentAsynchronous().get();
sheet.openDocument(false);
WindowStateManager stateManager;
stateManager = new WindowStateManager(frame,
new File(Configuration.getInstance().getConfDir(), "Configuration" + File.separator + "Frame" + File.separator + FileUtils.sanitize("RapportEtatDeStockPanel") + ".xml"));
 
} catch (Exception e) {
ExceptionHandler.handle("Erreur de traitement", e);
frame.getContentPane().add(new RapportEtatDeStockDepotSelectionPanel((ComptaPropsConfiguration) Configuration.getInstance()));
 
FrameUtil.showPacked(frame);
stateManager.loadState();
}
}
 
});
thread.start();
};
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/ui/RapportEtatDeStockDepotSelectionPanel.java
New file
0,0 → 1,152
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.sales.invoice.ui;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.sales.invoice.report.ReportingStockXmlSheet;
import org.openconcerto.erp.core.supplychain.stock.element.DepotStockSQLElement;
import org.openconcerto.sql.request.ComboSQLRequest;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
import org.openconcerto.ui.component.InteractionMode;
import org.openconcerto.utils.ExceptionHandler;
 
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
 
public class RapportEtatDeStockDepotSelectionPanel extends JPanel {
 
JPanel pnlMain = new JPanel();
JPanel pnlBottom = new JPanel();
JLabel labDepots = new JLabel("Dépôts");
JButton butReport = new JButton("Générer le rapport");
JCheckBox chkTous = new JCheckBox("Séléctionner tous les dépôts");
 
SQLRequestComboBox sqlreqDepots = new SQLRequestComboBox(false, 20);
 
public RapportEtatDeStockDepotSelectionPanel(ComptaPropsConfiguration conf) {
GridBagLayout layThis = new GridBagLayout();
this.setLayout(layThis);
 
GridBagLayout layMain = new GridBagLayout();
this.pnlMain.setLayout(layMain);
 
GridBagLayout layBottom = new GridBagLayout();
this.pnlBottom.setLayout(layBottom);
 
GridBagConstraints gbcThis = new GridBagConstraints();
gbcThis.weightx = 1;
gbcThis.weighty = 1;
gbcThis.gridheight = 1;
gbcThis.gridwidth = 1;
gbcThis.fill = GridBagConstraints.BOTH;
 
GridBagConstraints gbcBottom = new GridBagConstraints();
gbcBottom.weightx = 1;
gbcBottom.weighty = 1;
gbcBottom.gridheight = 1;
gbcBottom.gridwidth = 2;
gbcBottom.fill = GridBagConstraints.BOTH;
 
GridBagConstraints gbcDefault = new GridBagConstraints();
gbcDefault.weightx = 1;
gbcDefault.gridheight = 1;
gbcDefault.gridwidth = 1;
gbcDefault.insets = new Insets(0, 4, 4, 4);
gbcDefault.fill = GridBagConstraints.HORIZONTAL;
 
GridBagConstraints gbcButton = new GridBagConstraints();
gbcButton.weightx = 1;
gbcButton.weighty = 1;
gbcButton.gridheight = 1;
gbcButton.gridwidth = 1;
gbcButton.insets = new Insets(0, 4, 4, 4);
gbcButton.anchor = GridBagConstraints.SOUTHEAST;
 
this.setBackground(Color.DARK_GRAY);
this.add(this.pnlMain, gbcThis);
 
// Label.
gbcDefault.gridx = 0;
gbcDefault.gridy = 0;
this.pnlMain.add(this.labDepots, gbcDefault);
this.labDepots.setHorizontalAlignment(SwingConstants.RIGHT);
 
// SQLRequestComboBox.
List<String> fields = new ArrayList<>();
fields.add("NOM");
ComboSQLRequest request = new ComboSQLRequest(conf.getDirectory().getElement("DEPOT_STOCK").getTable(), fields, null, conf.getDirectory());
 
gbcDefault.gridx = 1;
gbcDefault.gridy = 0;
this.sqlreqDepots.uiInit(request);
this.sqlreqDepots.setValue(DepotStockSQLElement.DEFAULT_ID);
this.pnlMain.add(this.sqlreqDepots, gbcDefault);
 
// CheckBox.
gbcDefault.gridx = 1;
gbcDefault.gridy = 1;
this.chkTous.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (RapportEtatDeStockDepotSelectionPanel.this.chkTous.isSelected()) {
RapportEtatDeStockDepotSelectionPanel.this.sqlreqDepots.setEnabled(InteractionMode.DISABLED);
} else {
RapportEtatDeStockDepotSelectionPanel.this.sqlreqDepots.setEnabled(InteractionMode.READ_WRITE);
}
}
});
 
this.pnlMain.add(this.chkTous, gbcDefault);
 
// Ajout du panel du bas.
gbcBottom.gridx = 0;
gbcBottom.gridy = 2;
this.pnlMain.add(this.pnlBottom, gbcBottom);
 
// Button.
gbcButton.gridx = 0;
gbcButton.gridy = 0;
this.butReport.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Integer intIDDepot = RapportEtatDeStockDepotSelectionPanel.this.sqlreqDepots.getValue();
boolean bTousLesDepots = RapportEtatDeStockDepotSelectionPanel.this.chkTous.isSelected();
 
try {
ReportingStockXmlSheet sheet = new ReportingStockXmlSheet(conf, intIDDepot, bTousLesDepots);
sheet.createDocumentAsynchronous().get();
sheet.openDocument(false);
 
} catch (Exception excep) {
ExceptionHandler.handle("Erreur de traitement", excep);
}
}
});
 
this.pnlBottom.add(this.butReport, gbcButton);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/invoice/ui/ListeDesEcheancesClientsPanel.java
54,7 → 54,6
public class ListeDesEcheancesClientsPanel extends JPanel {
 
private ListPanelEcheancesClients panelEcheances;
private EditFrame editEncaisse = null;
private EditFrame editRelance = null;
private JButton relancer;
private JButton encaisser;
192,10 → 191,7
 
}
SQLElement encaisseElt = Configuration.getInstance().getDirectory().getElement("ENCAISSER_MONTANT");
if (ListeDesEcheancesClientsPanel.this.editEncaisse == null) {
ListeDesEcheancesClientsPanel.this.editEncaisse = new EditFrame(encaisseElt);
ListeDesEcheancesClientsPanel.this.editEncaisse.setIconImages(Gestion.getFrameIcon());
}
EditFrame editEncaisse = new EditFrame(encaisseElt);
 
SQLRowValues rowVals = new SQLRowValues(encaisseElt.getTable());
if (idClient > -1) {
207,60 → 203,23
rowVals.put("ID_COMPTE_PCE_TIERS", idCptTiers);
}
 
final EncaisserMontantSQLComponent sqlComponent = (EncaisserMontantSQLComponent) ListeDesEcheancesClientsPanel.this.editEncaisse.getSQLComponent();
final EncaisserMontantSQLComponent sqlComponent = (EncaisserMontantSQLComponent) editEncaisse.getSQLComponent();
 
sqlComponent.resetValue();
sqlComponent.select(rowVals);
sqlComponent.loadEcheancesFromRows(selectedRows);
ListeDesEcheancesClientsPanel.this.editEncaisse.setTitle("Encaissement de factures clients");
ListeDesEcheancesClientsPanel.this.editEncaisse.pack();
ListeDesEcheancesClientsPanel.this.editEncaisse.setVisible(true);
editEncaisse.setTitle("Encaissement de factures clients");
editEncaisse.pack();
editEncaisse.setVisible(true);
}
});
 
// Gestion de la souris
this.panelEcheances.getJTable().addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent mE) {
if (mE.getButton() == MouseEvent.BUTTON1) {
// Mise à jour de l'echeance sur la frame de reglement
// si cette derniere est cree
final SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete();
final SQLRowValues selectedRow = panelEcheances.getListe().getSelectedRow();
final SQLRow row = selectedRow.asRow();
if (row == null) {
JOptionPane.showMessageDialog(ListeDesEcheancesClientsPanel.this, "Selection", "Merci de sélectionner une ligne", JOptionPane.PLAIN_MESSAGE);
return;
}
if (ListeDesEcheancesClientsPanel.this.editEncaisse != null) {
final SQLRowValues rowVals = new SQLRowValues(base.getTable("ENCAISSER_MONTANT"));
rowVals.put("ID_ECHEANCE_CLIENT", row.getID());
 
ListeDesEcheancesClientsPanel.this.editEncaisse.getSQLComponent().select(rowVals);
ListeDesEcheancesClientsPanel.this.editEncaisse.pack();
}
}
 
}
});
 
liste.addIListener(new IListener() {
public void selectionId(int id, int field) {
if (id > 1) {
final SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete();
final SQLTable tableEch = base.getTable("ECHEANCE_CLIENT");
final SQLRow rowEch = tableEch.getRow(id);
final int idMvtSource = MouvementSQLElement.getSourceId(rowEch.getInt("ID_MOUVEMENT"));
final SQLRow rowMvtSource = base.getTable("MOUVEMENT").getRow(idMvtSource);
 
ListeDesEcheancesClientsPanel.this.relancer.setEnabled(rowMvtSource.getString("SOURCE").equalsIgnoreCase("SAISIE_VENTE_FACTURE"));
ListeDesEcheancesClientsPanel.this.encaisser.setEnabled(true);
} else {
ListeDesEcheancesClientsPanel.this.relancer.setEnabled(false);
ListeDesEcheancesClientsPanel.this.encaisser.setEnabled(false);
ListeDesEcheancesClientsPanel.this.relancer.setEnabled(id > 1);
ListeDesEcheancesClientsPanel.this.encaisser.setEnabled(id > 1);
}
 
}
});
this.relancer.setEnabled(false);
this.encaisser.setEnabled(false);
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/quote/component/DevisSQLComponent.java
436,10 → 436,9
final SQLRow rowClient = getTable().getForeignTable("ID_CLIENT").getRow(wantedID);
int idClient = rowClient.getID();
comboContact.getRequest().setWhere(new Where(contactElement.getTable().getField("ID_CLIENT"), "=", idClient));
if (!isFilling()) {
table.setClient(rowClient, true);
}
 
table.setClient(rowClient, !isFilling());
 
} else {
comboContact.getRequest().setWhere(Where.FALSE);
if (!isFilling()) {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/ReferenceArticleSQLElement.java
212,6 → 212,8
l.add("PV_HT");
l.add("ID_TAXE");
l.add("PV_TTC");
l.add("ID_COMPTE_PCE");
l.add("ID_COMPTE_PCE_ACHAT");
l.add("ID_FAMILLE_ARTICLE");
l.add("ID_FOURNISSEUR");
l.add("POIDS");
226,6 → 228,7
if (b != null && b.booleanValue()) {
l.add("SERVICE");
}
 
return l;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/element/CustomerProductFamilyQtyPriceSQLElement.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.erp.core.sales.product.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.DBRoot;
 
import java.util.ArrayList;
import java.util.List;
 
public class CustomerProductFamilyQtyPriceSQLElement extends ComptaSQLConfElement {
public static final String ELEMENT_CODE = "sales.customer.product.family.qty.price";
 
public CustomerProductFamilyQtyPriceSQLElement() {
super("TARIF_FAMILLE_ARTICLE_CLIENT");
}
 
@Override
protected String createCode() {
return ELEMENT_CODE;
}
 
@Override
protected List<String> getListFields() {
final List<String> l = new ArrayList<>(2);
l.add("ID_FAMILLE_ARTICLE");
l.add("QUANTITE");
return l;
}
 
@Override
protected List<String> getComboFields() {
final List<String> l = new ArrayList<>(1);
l.add("QUANTITE");
return l;
}
 
@Override
public SQLComponent createComponent() {
return null;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/action/TransfertStockPanel.java
20,7 → 20,9
import org.openconcerto.erp.core.supplychain.stock.element.StockItem.TypeStockMouvement;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
81,7 → 83,6
final SQLRequestComboBox comboStockArrive = new SQLRequestComboBox();
comboStockArrive.uiInit(stockElt.createComboRequest());
 
JLabel qteReel = new JLabel("Quantité", SwingConstants.RIGHT);
final NumericTextField fieldReel = new NumericTextField();
 
fieldReel.getDocument().addDocumentListener(new SimpleDocumentListener() {
88,8 → 89,7
 
@Override
public void update(DocumentEvent e) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
updateButtons(buttonUpdate, comboArticle, comboStockDepart, comboStockArrive, fieldReel);
}
});
 
97,8 → 97,7
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
updateButtons(buttonUpdate, comboArticle, comboStockDepart, comboStockArrive, fieldReel);
}
});
 
106,8 → 105,7
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
updateButtons(buttonUpdate, comboArticle, comboStockDepart, comboStockArrive, fieldReel);
}
});
 
115,17 → 113,16
 
@Override
public void propertyChange(PropertyChangeEvent evt) {
buttonUpdate.setEnabled(
fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null && comboStockDepart.getSelectedRow() != null);
updateButtons(buttonUpdate, comboArticle, comboStockDepart, comboStockArrive, fieldReel);
}
});
 
GridBagConstraints c = new DefaultGridBagConstraints();
 
c.gridx = 0;
this.add(new JLabel("Intitulé"), c);
final JTextField label = new JTextField();
c.gridx++;
c.gridwidth = 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(label, c);
label.setText(defaultLabel);
132,72 → 129,49
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 1;
c.weightx = 0;
this.add(new JLabel("Date", SwingConstants.RIGHT), c);
final JDate date = new JDate(true);
c.gridx++;
c.weightx = 0;
this.add(date, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(new JLabel("Article", SwingConstants.RIGHT), c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
c.gridx++;
this.add(comboArticle, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(new JLabel("Départ", SwingConstants.RIGHT), c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
c.gridx++;
this.add(comboStockDepart, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
 
this.add(new JLabel("Arrivée", SwingConstants.RIGHT), c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
c.gridx++;
this.add(comboStockArrive, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(qteReel, c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(new JLabel("Quantité", SwingConstants.RIGHT), c);
c.gridx++;
this.add(fieldReel, c);
 
c.gridy++;
c.gridx = 0;
c.gridwidth = 2;
c.weightx = 0;
this.add(qteReel, c);
c.gridx += 2;
c.gridwidth = 1;
c.weightx = 1;
this.add(fieldReel, c);
 
c.gridy++;
c.gridx = 0;
JButton buttonCancel = new JButton("Annuler");
JPanel pButton = new JPanel();
pButton.add(buttonCancel);
pButton.add(buttonUpdate);
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.EAST;
c.gridwidth = 2;
c.anchor = GridBagConstraints.SOUTHEAST;
c.weightx = 0;
c.fill = GridBagConstraints.NONE;
this.add(pButton, c);
212,19 → 186,19
 
@Override
public void actionPerformed(ActionEvent e) {
 
buttonUpdate.setEnabled(false);
BigDecimal qteReel = fieldReel.getValue();
 
List<String> multipleRequestsHundred = new ArrayList<String>(100);
boolean usePrice = mvtStockTable.contains("PRICE");
List<StockItem> stockItems = new ArrayList<StockItem>();
final Date dateValue = date.getValue();
 
final SQLRow selectedRowArticle = comboArticle.getSelectedRow();
 
final SQLRow selectedRowDepotDepart = comboStockDepart.getSelectedRow();
final SQLRow selectedRowDepotArrivee = comboStockArrive.getSelectedRow();
try {
SQLUtils.executeAtomic(selectedRowDepotDepart.getTable().getDBSystemRoot().getDataSource(), new ConnectionHandlerNoSetup<Object, SQLException>() {
@Override
public Object handle(SQLDataSource ds) throws SQLException {
{
// DEPART
final SQLRowAccessor rowStockDepart = ProductComponent.findOrCreateStock(selectedRowArticle, selectedRowDepotDepart);
233,12 → 207,7
SQLRowValues rowVals = new SQLRowValues(mvtStockTable.getTable("STOCK"));
rowVals.put("ID_ARTICLE", selectedRowArticle.getID());
rowVals.put("ID_DEPOT_STOCK", selectedRowDepotDepart.getID());
try {
rowVals.commit();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
selectedRowArticle.fetchValues();
item = new StockItem(selectedRowArticle, rowStockDepart);
}
245,28 → 214,22
stockItems.add(item);
double diff = -qteReel.doubleValue();
item.updateQty(diff, TypeStockMouvement.REEL);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), true, usePrice));
 
multipleRequestsHundred
.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), true, usePrice));
item.updateQty(diff, TypeStockMouvement.THEORIQUE);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), false, usePrice));
 
multipleRequestsHundred
.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), false, usePrice));
multipleRequestsHundred.add(item.getUpdateRequest());
}
// ARRIVEE
{
final SQLRowAccessor rowStockArrivee = ProductComponent.findOrCreateStock(selectedRowArticle, selectedRowDepotArrivee);
 
StockItem item = new StockItem(selectedRowArticle, rowStockArrivee);
if (!item.isStockInit()) {
SQLRowValues rowVals = new SQLRowValues(mvtStockTable.getTable("STOCK"));
rowVals.put("ID_ARTICLE", selectedRowArticle.getID());
rowVals.put("ID_DEPOT_STOCK", selectedRowDepotArrivee.getID());
try {
rowVals.commit();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
selectedRowArticle.fetchValues();
item = new StockItem(selectedRowArticle, rowStockArrivee);
}
273,16 → 236,14
stockItems.add(item);
double diff = qteReel.doubleValue();
item.updateQty(diff, TypeStockMouvement.REEL);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), true, usePrice));
 
multipleRequestsHundred
.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), true, usePrice));
item.updateQty(diff, TypeStockMouvement.THEORIQUE);
multipleRequestsHundred.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), false, usePrice));
 
multipleRequestsHundred
.add(getMvtRequest(dateValue, BigDecimal.ZERO, diff, item, getLabel(label.getText(), selectedRowDepotDepart, selectedRowDepotArrivee), false, usePrice));
multipleRequestsHundred.add(item.getUpdateRequest());
}
 
try {
 
final int size = multipleRequestsHundred.size();
List<? extends ResultSetHandler> handlers = new ArrayList<ResultSetHandler>(size);
for (int i = 0; i < size; i++) {
290,28 → 251,18
}
SQLUtils.executeMultiple(instance.getRoot().getDBSystemRoot(), multipleRequestsHundred, handlers);
 
} catch (SQLException e1) {
ExceptionHandler.handle("Stock update error", e1);
}
 
final DBRoot root = mvtStockTable.getDBRoot();
if (root.contains("ARTICLE_ELEMENT")) {
// List<StockItem> stockItems = new ArrayList<StockItem>();
// for (SQLRowAccessor sqlRowAccessor2 : stocks) {
// final SQLRow asRow = sqlRowAccessor2.asRow();
// asRow.fetchValues();
// stockItems.add(new StockItem(asRow));
// }
// Mise à jour des stocks des nomenclatures
ComposedItemStockUpdater comp = new ComposedItemStockUpdater(root, stockItems);
try {
comp.update();
}
return null;
}
});
} catch (SQLException e1) {
e1.printStackTrace();
ExceptionHandler.handle("Stock update error", e1);
}
}
 
// liste.getModel().updateAll();
((JFrame) SwingUtilities.getRoot(TransfertStockPanel.this)).dispose();
}
});
318,14 → 269,12
}
 
private String getLabel(String label, SQLRowAccessor fromDepot, SQLRowAccessor toDepot) {
 
return label + " de " + fromDepot.getString("NOM") + " vers " + toDepot.getString("NOM");
 
}
 
private String getMvtRequest(Date time, BigDecimal prc, double qteFinal, StockItem item, String label, boolean reel, boolean usePrice) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String mvtStockQuery = "INSERT INTO " + mvtStockTableQuoted + " (\"QTE\",\"DATE\",\"ID_ARTICLE\",\"ID_STOCK\",\"NOM\",\"REEL\",\"ORDRE\"";
String mvtStockQuery = "INSERT INTO " + this.mvtStockTableQuoted + " (\"QTE\",\"DATE\",\"ID_ARTICLE\",\"ID_STOCK\",\"NOM\",\"REEL\",\"ORDRE\"";
 
if (usePrice && prc != null) {
mvtStockQuery += ",\"PRICE\"";
332,7 → 281,7
}
 
mvtStockQuery += ") VALUES(" + qteFinal + ",'" + dateFormat.format(time) + "'," + item.getArticle().getID() + "," + item.stock.getID() + ",'" + label + "'," + reel
+ ", (SELECT (MAX(\"ORDRE\")+1) FROM " + mvtStockTableQuoted + ")";
+ ", (SELECT (MAX(\"ORDRE\")+1) FROM " + this.mvtStockTableQuoted + ")";
if (usePrice && prc != null) {
mvtStockQuery += "," + prc.setScale(6, RoundingMode.HALF_UP).toString();
}
339,4 → 288,10
mvtStockQuery += ")";
return mvtStockQuery;
}
 
private void updateButtons(final JButton buttonUpdate, final SQLRequestComboBox comboArticle, final SQLRequestComboBox comboStockDepart, final SQLRequestComboBox comboStockArrive,
final NumericTextField fieldReel) {
buttonUpdate.setEnabled(fieldReel.getText().trim().length() > 0 && comboArticle.getSelectedRow() != null && comboStockArrive.getSelectedRow() != null
&& comboStockDepart.getSelectedRow() != null && comboStockArrive.getSelectedRow().getID() != comboStockDepart.getSelectedRow().getID());
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/ui/CustomerProductFamilyQtyPriceListTable.java
New file
0,0 → 1,120
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
 
package org.openconcerto.erp.core.sales.product.ui;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.view.list.RowValuesTable;
import org.openconcerto.sql.view.list.RowValuesTableControlPanel;
import org.openconcerto.sql.view.list.RowValuesTableModel;
import org.openconcerto.sql.view.list.RowValuesTablePanel;
import org.openconcerto.sql.view.list.RowValuesTableRenderer;
import org.openconcerto.sql.view.list.SQLTableElement;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.table.PercentTableCellRenderer;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.math.BigDecimal;
import java.util.List;
import java.util.Vector;
 
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
 
public class CustomerProductFamilyQtyPriceListTable extends RowValuesTablePanel {
 
public CustomerProductFamilyQtyPriceListTable() {
 
init();
uiInit();
}
 
/**
*
*/
protected void init() {
 
final SQLElement e = getSQLElement();
 
final List<SQLTableElement> list = new Vector<SQLTableElement>();
 
final SQLTableElement tableElementFamille = new SQLTableElement(e.getTable().getField("ID_FAMILLE_ARTICLE"));
list.add(tableElementFamille);
 
// final SQLTableElement eQuantity = new SQLTableElement(e.getTable().getField("QUANTITE"))
// {
// @Override
// protected Object getDefaultNullValue() {
// return BigDecimal.ONE;
// }
// };
// list.add(eQuantity);
 
SQLTableElement eltPourcent = new SQLTableElement(e.getTable().getField("POURCENT_REMISE"));
list.add(eltPourcent);
 
this.model = new RowValuesTableModel(e, list, e.getTable().getField("ID_FAMILLE_ARTICLE"), false, this.defaultRowVals);
 
this.table = new RowValuesTable(this.model, null);
 
eltPourcent.setRenderer(new PercentTableCellRenderer());
 
}
 
public SQLElement getSQLElement() {
return Configuration.getInstance().getDirectory().getElement("TARIF_FAMILLE_ARTICLE_CLIENT");
}
 
public void insertFrom(String field, SQLRowValues row) {
this.table.insertFrom(field, row);
}
 
protected void uiInit() {
// Ui init
this.setLayout(new GridBagLayout());
this.setOpaque(false);
final GridBagConstraints c = new DefaultGridBagConstraints();
c.weightx = 1;
c.gridx = 0;
final JPanel control = new RowValuesTableControlPanel(this.table);
control.setOpaque(false);
this.add(control, c);
 
c.gridy++;
c.fill = GridBagConstraints.BOTH;
c.weighty = 1;
c.weightx = 1;
JScrollPane comp = new JScrollPane(this.table);
comp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
this.add(comp, c);
this.table.setDefaultRenderer(Long.class, new RowValuesTableRenderer());
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/ProductComponent.java
134,12 → 134,16
return null;
}
 
public static ProductComponent createFromRowArticle(SQLRowAccessor rowArticle, SQLRowAccessor rowValsSource) {
public static ProductComponent createFromRowArticle(SQLRowAccessor rowArticle, BigDecimal qty, SQLRowAccessor rowValsSource) {
SQLRowAccessor rowStock = getStock(rowArticle, rowArticle, rowValsSource);
 
return new ProductComponent(rowArticle, BigDecimal.ONE, rowValsSource, rowStock);
return new ProductComponent(rowArticle, qty, rowValsSource, rowStock);
}
 
public static ProductComponent createFromRowArticle(SQLRowAccessor rowArticle, SQLRowAccessor rowValsSource) {
return createFromRowArticle(rowArticle, BigDecimal.ONE, rowValsSource);
}
 
public static ProductComponent createFrom(SQLRowAccessor rowVals) {
return createFrom(rowVals, 1, rowVals);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/model/ProductHelper.java
320,7 → 320,9
for (ProductComponent productParent : source) {
 
final SQLRowAccessor foreignArticle = childRowValues.getForeign("ID_ARTICLE");
ProductComponent childComponent = ProductComponent.createFromRowArticle(foreignArticle, productParent.getSource());
int childQ = childRowValues.getInt("QTE");
BigDecimal childqD = childRowValues.getBigDecimal("QTE_UNITAIRE");
ProductComponent childComponent = ProductComponent.createFromRowArticle(foreignArticle, childqD.multiply(new BigDecimal(childQ)), productParent.getSource());
 
// parentsArticleIDs.remove(foreignArticleParent.getID());
// Calcul de la quantité qte_unit * qte * qteMergedParent
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/product/component/ReferenceArticleSQLComponent.java
89,36 → 89,36
 
public class ReferenceArticleSQLComponent extends BaseSQLComponent {
 
private JTextField textPVHT, textPVTTC, textPAHT;
private JTextField textMetrique1VT, textMetrique1HA;
protected JTextField textPVHT, textPVTTC, textPAHT;
protected JTextField textMetrique1VT, textMetrique1HA;
 
private final JCheckBox boxService = new JCheckBox(getLabelFor("SERVICE"));
private final JCheckBox checkObs = new JCheckBox(getLabelFor("OBSOLETE"));
private JTextField textNom, textCode;
private JTextField textPoids;
private JTextField textValMetrique1, textValMetrique2, textValMetrique3;
private DocumentListener htDocListener, ttcDocListener, detailsListener;
private PropertyChangeListener propertyChangeListener;
private PropertyChangeListener taxeListener;
private final ElementComboBox comboSelTaxe = new ElementComboBox(false, 10);
private final ElementComboBox comboSelModeVente = new ElementComboBox(false, 25);
private JLabel labelMetriqueHA1 = new JLabel(getLabelFor("PRIX_METRIQUE_HA_1"), SwingConstants.RIGHT);
private JLabel labelMetriqueVT1 = new JLabel(getLabelFor("PRIX_METRIQUE_VT_1"), SwingConstants.RIGHT);
protected final JCheckBox boxService = new JCheckBox(getLabelFor("SERVICE"));
protected final JCheckBox checkObs = new JCheckBox(getLabelFor("OBSOLETE"));
protected JTextField textNom, textCode;
protected JTextField textPoids;
protected JTextField textValMetrique1, textValMetrique2, textValMetrique3;
protected DocumentListener htDocListener, ttcDocListener, detailsListener;
protected PropertyChangeListener propertyChangeListener;
protected PropertyChangeListener taxeListener;
protected final ElementComboBox comboSelTaxe = new ElementComboBox(false, 10);
protected final ElementComboBox comboSelModeVente = new ElementComboBox(false, 25);
protected JLabel labelMetriqueHA1 = new JLabel(getLabelFor("PRIX_METRIQUE_HA_1"), SwingConstants.RIGHT);
protected JLabel labelMetriqueVT1 = new JLabel(getLabelFor("PRIX_METRIQUE_VT_1"), SwingConstants.RIGHT);
 
private ArticleDesignationTable tableDes = new ArticleDesignationTable();
private ArticleCodeClientTable tableCodeClient = new ArticleCodeClientTable();
private ArticleTarifTable tableTarifVente = new ArticleTarifTable(this);
private ArticleCategorieComptableTable tableCatComptable = new ArticleCategorieComptableTable();
private SupplierPriceListTable tableFourSec = new SupplierPriceListTable();
protected ArticleDesignationTable tableDes = new ArticleDesignationTable();
protected ArticleCodeClientTable tableCodeClient = new ArticleCodeClientTable();
protected ArticleTarifTable tableTarifVente = new ArticleTarifTable(this);
protected ArticleCategorieComptableTable tableCatComptable = new ArticleCategorieComptableTable();
protected SupplierPriceListTable tableFourSec = new SupplierPriceListTable();
 
private ProductQtyPriceListTable tableTarifQteVente = new ProductQtyPriceListTable(this);
private ProductItemListTable tableBom;
private final JTextField textMarge = new JTextField(10);
private final JLabel labelMarge = new JLabel("% ");
private ElementComboBox boxCR;
private JCheckBox boxMargeWithCR;
protected ProductQtyPriceListTable tableTarifQteVente = new ProductQtyPriceListTable(this);
protected ProductItemListTable tableBom;
protected final JTextField textMarge = new JTextField(10);
protected final JLabel labelMarge = new JLabel("% ");
protected ElementComboBox boxCR;
protected JCheckBox boxMargeWithCR;
 
private DocumentListener pieceHAArticle = new SimpleDocumentListener() {
protected DocumentListener pieceHAArticle = new SimpleDocumentListener() {
 
@Override
public void update(DocumentEvent e) {
129,7 → 129,7
}
 
};
private DocumentListener pieceVTArticle = new SimpleDocumentListener() {
protected DocumentListener pieceVTArticle = new SimpleDocumentListener() {
 
@Override
public void update(DocumentEvent e) {
140,7 → 140,7
 
};
 
private DocumentListener listenerMargeTextMarge = new SimpleDocumentListener() {
protected DocumentListener listenerMargeTextMarge = new SimpleDocumentListener() {
@Override
public void update(DocumentEvent e) {
ReferenceArticleSQLComponent.this.textPVHT.getDocument().removeDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextVT);
150,7 → 150,7
 
};
 
private DocumentListener listenerMargeTextVT = new SimpleDocumentListener() {
protected DocumentListener listenerMargeTextVT = new SimpleDocumentListener() {
@Override
public void update(DocumentEvent e) {
ReferenceArticleSQLComponent.this.textMarge.getDocument().removeDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextMarge);
196,7 → 196,7
}
};
 
private DocumentListener listenerMargeTextHA = new SimpleDocumentListener() {
protected DocumentListener listenerMargeTextHA = new SimpleDocumentListener() {
@Override
public void update(DocumentEvent e) {
ReferenceArticleSQLComponent.this.textPVHT.getDocument().removeDocumentListener(ReferenceArticleSQLComponent.this.listenerMargeTextVT);
205,7 → 205,7
}
};
 
private void updateVtFromMarge() {
public void updateVtFromMarge() {
if (this.textPAHT.getText().trim().length() > 0) {
 
BigDecimal ha = StringUtils.getBigDecimalFromUserText(this.textPAHT.getText());
474,7 → 474,7
this.comboSelModeVente.setValue(ReferenceArticleSQLElement.A_LA_PIECE);
}
 
private Component createInfosPanel() {
protected Component createInfosPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
586,7 → 586,7
return panel;
}
 
private Component createDescriptifPanel() {
protected Component createDescriptifPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
666,7 → 666,7
return panel;
}
 
private Component createDesignationPanel() {
protected Component createDesignationPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
744,7 → 744,7
return panel;
}
 
private Component createCodeClientPanel() {
protected Component createCodeClientPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
760,7 → 760,7
return panel;
}
 
private Component createStockPanel() {
protected Component createStockPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
830,7 → 830,7
return panel;
}
 
private Component createComptaPanel() {
protected Component createComptaPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
872,10 → 872,10
return panel;
}
 
private SQLRowValues rowValuesDefaultCodeFournisseur;
private CodeFournisseurItemTable codeFournisseurTable;
protected SQLRowValues rowValuesDefaultCodeFournisseur;
protected CodeFournisseurItemTable codeFournisseurTable;
 
private Component createAchatPanel() {
protected Component createAchatPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
1003,7 → 1003,7
 
}
 
private JPanel createExportationPanel() {
protected JPanel createExportationPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
1043,7 → 1043,7
return panel;
}
 
private JPanel createTarifPanel() {
protected JPanel createTarifPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
1127,7 → 1127,7
return panel;
}
 
private JPanel createCategorieComptablePanel() {
protected JPanel createCategorieComptablePanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
1204,7 → 1204,7
return panel;
}
 
private JPanel createBOMpanel() {
protected JPanel createBOMpanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
1255,7 → 1255,7
 
}
 
private void updatePricesNomenclature(final JCheckBox checkAutoPrice, final JCheckBox checkAutoPriceHA) {
protected void updatePricesNomenclature(final JCheckBox checkAutoPrice, final JCheckBox checkAutoPriceHA) {
final Boolean vtAuto = checkAutoPrice.isSelected();
final Boolean haAuto = checkAutoPriceHA.isSelected();
if (vtAuto || haAuto) {
1271,7 → 1271,7
}
}
 
private JPanel createTarifQtePanel() {
protected JPanel createTarifQtePanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints c = new DefaultGridBagConstraints();
1563,7 → 1563,7
 
}
 
private void setListenerModeVenteActive(boolean b) {
protected void setListenerModeVenteActive(boolean b) {
if (b) {
this.comboSelModeVente.addValueListener(this.propertyChangeListener);
} else {
1575,7 → 1575,7
* @param c
* @param props
*/
private void addModeVenteAvance(GridBagConstraints c) {
protected void addModeVenteAvance(GridBagConstraints c) {
DefaultProps props = DefaultNXProps.getInstance();
JSeparator sep = new JSeparator();
JLabel labelDetails = new JLabel("Article détaillé", SwingConstants.RIGHT);
1769,7 → 1769,7
*
* @param id id du mode de vente
*/
private void selectModeVente(int id) {
protected void selectModeVente(int id) {
 
this.labelMetriqueHA1.setEnabled(true);
this.labelMetriqueVT1.setEnabled(true);
1850,7 → 1850,7
return rowVals;
}
 
private void setTextHT() {
protected void setTextHT() {
if (!isFilling()) {
this.textPVHT.getDocument().removeDocumentListener(this.htDocListener);
final BigDecimal ttc = StringUtils.getBigDecimalFromUserText(this.textPVTTC.getText());
1867,7 → 1867,7
}
}
 
private void setTextTTC() {
protected void setTextTTC() {
if (!isFilling()) {
this.textPVTTC.getDocument().removeDocumentListener(this.ttcDocListener);
final BigDecimal ht = StringUtils.getBigDecimalFromUserText(this.textPVHT.getText());
1887,7 → 1887,7
/**
* calcul du prix achat et vente ainsi que le poids total pour la piece
*/
private void updatePiece() {
protected void updatePiece() {
if (this.comboSelModeVente.getSelectedId() > 1 && this.comboSelModeVente.getSelectedId() != ReferenceArticleSQLElement.A_LA_PIECE) {
SQLRowValues rowVals = getDetailsRowValues();
float poidsTot = ReferenceArticleSQLElement.getPoidsFromDetails(rowVals);
1924,7 → 1924,7
return rowVals;
}
 
private void put(SQLRowValues rowVals, JTextField comp) {
protected void put(SQLRowValues rowVals, JTextField comp) {
Float f = (comp.getText() == null || comp.getText().trim().length() == 0) ? 0.0F : Float.valueOf(comp.getText());
rowVals.put(this.getView(comp).getField().getName(), f);
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/ui/CaisseControler.java
537,11 → 537,30
TicketItem item = new TicketItem(article, a.getQty().multiply(new BigDecimal(-1)));
this.t.addItem(item);
}
// Annulation de chaque paiement
final List<Paiement> typesAdded = new ArrayList<>();
for (Paiement p : ticket.getPaiements()) {
final Paiement paiement = new Paiement(p.getType());
paiement.setMontantInCents(-1 * p.getMontantInCents());
this.t.addPaiement(paiement);
typesAdded.add(p);
}
// On complete avec les autres types
final List<Paiement> types = new ArrayList<>();
types.add(new Paiement(Paiement.CB));
types.add(new Paiement(Paiement.CHEQUE));
types.add(new Paiement(Paiement.ESPECES));
for (Paiement paiement : types) {
boolean typeFound = false;
for (Paiement p : typesAdded) {
if (paiement.getType() == p.getType()) {
typeFound = true;
}
}
if (!typeFound) {
this.t.addPaiement(paiement);
}
}
 
this.caisseFrame.showCaisse();
fire();
/trunk/OpenConcerto/src/org/openconcerto/erp/core/sales/pos/io/BarcodeReader.java
16,6 → 16,7
import org.openconcerto.erp.core.sales.pos.ui.BarcodeListener;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.component.ITextArea;
import org.openconcerto.utils.StringUtils;
 
import java.awt.Dimension;
import java.awt.GridBagConstraints;
61,16 → 62,16
this.timer = null;
this.task = null;
this.maxInterKeyDelay = maxInterKeyDelay;
mapCharacterFR.put((int) '&', "1");
mapCharacterFR.put((int) 'é', "2");
mapCharacterFR.put((int) '"', "3");
mapCharacterFR.put((int) '\'', "4");
mapCharacterFR.put((int) '(', "5");
mapCharacterFR.put((int) '-', "6");
mapCharacterFR.put((int) 'è', "7");
mapCharacterFR.put((int) '_', "8");
mapCharacterFR.put((int) 'ç', "9");
mapCharacterFR.put((int) 'à', "0");
this.mapCharacterFR.put((int) '&', "1");
this.mapCharacterFR.put((int) 'é', "2");
this.mapCharacterFR.put((int) '"', "3");
this.mapCharacterFR.put((int) '\'', "4");
this.mapCharacterFR.put((int) '(', "5");
this.mapCharacterFR.put((int) '-', "6");
this.mapCharacterFR.put((int) 'è', "7");
this.mapCharacterFR.put((int) '_', "8");
this.mapCharacterFR.put((int) 'ç', "9");
this.mapCharacterFR.put((int) 'à', "0");
}
 
public synchronized void removeBarcodeListener(BarcodeListener l) {
102,7 → 103,7
// init avant que les listeners s'en servent
this.timer = new Timer(getClass().getName(), true);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
System.err.println("BarcodeReader start : scan delay " + maxInterKeyDelay + " ms");
System.err.println("BarcodeReader start : scan delay " + this.maxInterKeyDelay + " ms");
}
}
 
120,9 → 121,9
 
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (!enable)
if (!this.enable) {
return false;
 
}
if (this.task != null)
this.task.cancel();
 
133,10 → 134,10
int keyCode = e.getKeyCode();
 
final long delay = t - this.firstTime;
if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE || (delay > maxInterKeyDelay && keyCode != KeyEvent.VK_SHIFT)) {
if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE || (delay > this.maxInterKeyDelay && keyCode != KeyEvent.VK_SHIFT)) {
// touche normale
if (this.debug) {
System.err.println("TOuche normale " + keyCode);
System.err.println("Touche normale " + keyCode);
}
this.eve.add(e);
redispatch();
151,6 → 152,11
if (this.debug) {
System.err.println("SHIFT " + keyCode);
}
} else if (keyChar == ']') {
this.value += keyChar;
if (this.debug) {
System.err.println("]");
}
} else if (keyChar == '*' || keyChar == '$' || keyChar == '+' || keyChar == '/' || keyChar == '%' || keyChar == ' ') {
this.value += keyChar;
if (this.debug) {
159,7 → 165,7
} else if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9 || keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z) {
// from KeyEvent : same as ASCII
if (this.debug) {
System.err.println("[0-9] [A-Z] " + keyCode);
System.err.println("[0-9] [A-Z] " + keyCode + " : " + keyChar);
}
this.value += (char) keyCode;
} else if (keyCode == KeyEvent.VK_ENTER && this.value.length() >= MIN_BARCODE_LENGTH) {
170,20 → 176,27
this.value = this.value.trim();
fire(this.value);
reset();
} else if (mapCharacterFR.containsKey((int) keyChar)) {
} else if (this.mapCharacterFR.containsKey((int) keyChar)) {
if (this.debug) {
System.err.println("MAP DEFAULT FR CHAR " + keyChar + " WITH " + mapCharacterFR.get((int) keyChar));
System.err.println("MAP DEFAULT FR CHAR " + keyChar + " WITH " + this.mapCharacterFR.get((int) keyChar));
}
this.value += mapCharacterFR.get((int) keyChar);
this.value += this.mapCharacterFR.get((int) keyChar);
} else if (Character.isLetter(keyChar) || Character.isDigit(keyChar)) {
this.value += keyChar;
if (this.debug) {
System.err.println("LETTER OR DIGIT " + keyChar);
}
} else if (keyChar == 29) {
this.value += '\u001D';
if (this.debug) {
System.err.println("<GS>");
}
} else if (keyChar == KeyEvent.CHAR_UNDEFINED) {
System.err.println("CHAR_UNDEFINED");
} else {
// Caractere non code barre
if (this.debug) {
System.err.println("CHAR NON CODE BARRE " + e);
System.err.println("CHAR NON CODE BARRE keyCode:" + keyCode + " keyChar:" + keyChar);
}
redispatch();
}
196,12 → 209,13
redispatchLater();
}
};
this.timer.schedule(this.task, maxInterKeyDelay);
this.timer.schedule(this.task, this.maxInterKeyDelay);
}
// si pas d'evenement, pas de temps associé
assert !this.eve.isEmpty() || this.firstTime == -1;
}
return true;
 
}
 
private void redispatchLater() {
231,7 → 245,7
}
 
public Map<Integer, String> getMapCharacterFR() {
return mapCharacterFR;
return this.mapCharacterFR;
}
 
public void setDebug(boolean debug) {
289,6 → 303,7
@Override
public void barcodeRead(String code) {
t1.append("Barcode OK : '" + code + "'\n");
t1.append("Hex: " + StringUtils.bytesToHexString(code.getBytes()));
}
});
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/AbstractAchatArticleItemTable.java
161,17 → 161,15
}
 
SQLTableElement tableElementArticle = new SQLTableElement(e.getTable().getField("ID_ARTICLE"), true, true, true) {
 
@Override
public boolean isCellEditable(SQLRowValues vals, int rowIndex, int columnIndex) {
boolean b = super.isCellEditable(vals, rowIndex, columnIndex);
if (vals.getTable().contains("ID_COMMANDE_ELEMENT")) {
boolean noCmdElt = vals.getObject("ID_COMMANDE_ELEMENT") == null || vals.isForeignEmpty("ID_COMMANDE_ELEMENT");
return b && noCmdElt;
} else {
return b;
 
return b && !isFromTranferred(vals);
 
}
 
}
};
list.add(tableElementArticle);
 
207,12 → 205,7
@Override
public boolean isCellEditable(SQLRowValues vals, int rowIndex, int columnIndex) {
boolean b = super.isCellEditable(vals, rowIndex, columnIndex);
if (vals.getTable().contains("ID_COMMANDE_ELEMENT")) {
boolean noCmdElt = vals.getObject("ID_COMMANDE_ELEMENT") == null || vals.isForeignEmpty("ID_COMMANDE_ELEMENT");
return b && noCmdElt;
} else {
return b;
}
return b && !isFromTranferred(vals);
 
}
};
222,12 → 215,7
@Override
public boolean isCellEditable(SQLRowValues vals, int rowIndex, int columnIndex) {
boolean b = super.isCellEditable(vals, rowIndex, columnIndex);
if (vals.getTable().contains("ID_COMMANDE_ELEMENT")) {
boolean noCmdElt = vals.getObject("ID_COMMANDE_ELEMENT") == null || vals.isForeignEmpty("ID_COMMANDE_ELEMENT");
return b && noCmdElt;
} else {
return b;
}
return b && !isFromTranferred(vals);
 
}
};
336,6 → 324,13
list.add(tableCmdElt);
}
 
if (e.getTable().contains("ID_BON_RECEPTION_ELEMENT")) {
SQLTableElement tableBrElt = null;
tableBrElt = new SQLTableElement(e.getTable().getField("ID_BON_RECEPTION_ELEMENT"));
tableBrElt.setEditable(false);
list.add(tableBrElt);
}
 
if (e.getTable().getFieldsName().contains("QTE_ORIGINE")) {
final SQLTableElement tableQteO = new SQLTableElement(e.getTable().getField("QTE_ORIGINE"));
tableQteO.setEditable(false);
511,7 → 506,7
this.defaultRowVals.put("ID_DEPOT_STOCK", depotDefault);
}
 
final RowValuesTableModel model = new RowValuesTableModel(e, list, e.getTable().getField("NOM"), false, this.defaultRowVals) {
final RowValuesTableModel model = new RowValuesTableModel(e, list, e.getTable().getField("QTE"), false, this.defaultRowVals) {
@Override
public void commitData() {
super.commitData(true);
529,7 → 524,14
this.table.getClearCloneTableElement().add("RECU_FORCED");
} else if (getSQLElement().getTable().getName().equals("BON_RECEPTION_ELEMENT")) {
this.table.getClearCloneTableElement().add("ID_COMMANDE_ELEMENT");
} else if (getSQLElement().getTable().getName().equals("FACTURE_FOURNISSEUR_ELEMENT")) {
if (getSQLElement().getTable().contains("ID_COMMANDE_ELEMENT")) {
this.table.getClearCloneTableElement().add("ID_COMMANDE_ELEMENT");
}
if (getSQLElement().getTable().contains("ID_BON_RECEPTION_ELEMENT")) {
this.table.getClearCloneTableElement().add("ID_BON_RECEPTION_ELEMENT");
}
}
 
table.addMouseListener(new MouseAdapter() {
@Override
886,6 → 888,10
setColumnVisible(model.getColumnForField("ID_COMMANDE_ELEMENT"), false);
}
 
if (e.getTable().contains("ID_BON_RECEPTION_ELEMENT")) {
setColumnVisible(model.getColumnForField("ID_BON_RECEPTION_ELEMENT"), false);
}
 
// Gestion des unités de vente
final boolean gestionUV = prefs.getBoolean(GestionArticleGlobalPreferencePanel.UNITE_VENTE, true);
setColumnVisible(model.getColumnForField("QTE_UNITAIRE"), gestionUV);
1425,4 → 1431,19
}
}
 
private final List<String> trFields = Arrays.asList("ID_COMMANDE_ELEMENT", "ID_BON_RECEPTION_ELEMENT");
 
private boolean isFromTranferred(SQLRowValues vals) {
 
for (String trField : this.trFields) {
if (vals.getTable().contains(trField)) {
boolean noCmdElt = vals.getObject(trField) == null || vals.isForeignEmpty(trField);
if (!noCmdElt) {
return true;
}
}
}
return false;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/TotalPanel.java
172,7 → 172,6
GridBagConstraints c = new DefaultGridBagConstraints();
 
c.gridheight = 1;
c.weighty = 0;
c.fill = GridBagConstraints.HORIZONTAL;
 
// Collone 1 : Selection
302,7 → 301,6
c.gridx = 3;
c.gridy = 0;
c.gridheight = GridBagConstraints.REMAINDER;
c.weighty = 1;
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0;
this.add(createSeparator(), c);
309,7 → 307,6
 
c.gridheight = 1;
c.fill = GridBagConstraints.HORIZONTAL;
c.weighty = 0;
c.gridx++;
this.add(new JLabelBold(TM.tr("TotalPanel.global")), c); //$NON-NLS-1$
c.gridy++;
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/IListTotalPanel.java
41,6 → 41,8
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
93,9 → 95,16
}
 
public IListTotalPanel(IListe l, final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, String title) {
this(l, listField, filters, null, title);
this(l, listField, filters, null, title, false);
}
 
public IListTotalPanel(IListe l, final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, final List<Tuple2<SQLField, ?>> filtersNot,
String title) {
this(l, listField, filters, filtersNot, title, false);
}
 
private final boolean onSelection;
 
/**
*
* @param l
103,11 → 112,11
* @param filters filtre ex : Tuple((SQLField)NATEXIER,(Boolean)FALSE)
*/
public IListTotalPanel(IListe l, final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, final List<Tuple2<SQLField, ?>> filtersNot,
String title) {
String title, boolean onSelection) {
super(new GridBagLayout());
this.list = l;
this.setOpaque(false);
 
this.onSelection = onSelection;
GridBagConstraints c = new DefaultGridBagConstraints();
c.gridx = GridBagConstraints.RELATIVE;
c.weightx = 0;
143,16 → 152,25
c.gridy++;
}
 
this.list.addListener(new TableModelListener() {
if (this.onSelection) {
this.list.getJTable().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
 
private Object getValueAt(final ListSQLLine line, final SQLTableModelColumn col, final List<SQLTableModelColumn> columns) {
final int indexOf = columns.indexOf(col);
final Object res = line.getValueAt(indexOf);
if (res == null)
throw new IllegalStateException("Null value for " + col + " in " + line);
return res;
@Override
public void valueChanged(ListSelectionEvent e) {
 
final List<ListSQLLine> listLines = list.getSelectedLines();
for (Tuple2<? extends SQLTableModelColumn, Type> field : listField) {
if (field.get1() == Type.COUNT) {
map.get(field.get0()).setText(String.valueOf(listLines.size()));
}
}
computeValues(listField, filters, filtersNot, listLines);
}
});
} else {
 
this.list.addListener(new TableModelListener() {
 
@Override
public void tableChanged(TableModelEvent e) {
final TableModel model = (TableModel) e.getSource();
162,17 → 180,48
else
sqlModel = (ITableModel) ((TableSorter) model).getTableModel();
 
Map<SQLTableModelColumn, BigDecimal> mapTotal = new HashMap<SQLTableModelColumn, BigDecimal>();
Map<SQLTableModelColumn, Double> mapPourcent = new HashMap<SQLTableModelColumn, Double>();
Map<SQLTableModelColumn, Integer> mapPourcentSize = new HashMap<SQLTableModelColumn, Integer>();
final List<ListSQLLine> listLines = new ArrayList<>();
for (int i = 0; i < sqlModel.getRowCount(); i++) {
listLines.add(sqlModel.getRow(i));
}
for (Tuple2<? extends SQLTableModelColumn, Type> field : listField) {
if (field.get1() == Type.COUNT) {
map.get(field.get0()).setText(String.valueOf(model.getRowCount()));
}
}
computeValues(listField, filters, filtersNot, listLines);
}
 
for (int i = 0; i < model.getRowCount(); i++) {
final ListSQLLine line = sqlModel.getRow(i);
});
}
}
 
public void fireUpdated() {
for (PropertyChangeListener l : this.loadingListener.getListeners(PropertyChangeListener.class)) {
l.propertyChange(null);
}
}
 
public void addListener(PropertyChangeListener l) {
this.loadingListener.add(PropertyChangeListener.class, l);
}
 
private Object getValueAt(final ListSQLLine line, final SQLTableModelColumn col, final List<SQLTableModelColumn> columns) {
final int indexOf = columns.indexOf(col);
final Object res = line.getValueAt(indexOf);
if (res == null)
throw new IllegalStateException("Null value for " + col + " in " + line);
return res;
}
 
private void computeValues(final List<Tuple2<? extends SQLTableModelColumn, Type>> listField, final List<Tuple2<SQLField, ?>> filters, final List<Tuple2<SQLField, ?>> filtersNot,
final List<ListSQLLine> listLines) {
Map<SQLTableModelColumn, BigDecimal> mapTotal = new HashMap<SQLTableModelColumn, BigDecimal>();
Map<SQLTableModelColumn, Double> mapPourcent = new HashMap<SQLTableModelColumn, Double>();
Map<SQLTableModelColumn, Integer> mapPourcentSize = new HashMap<SQLTableModelColumn, Integer>();
 
for (ListSQLLine line : listLines) {
 
final SQLRowValues rowAt = line.getRow();
final List<SQLTableModelColumn> columns = line.getColumns().getColumns();
 
297,17 → 346,4
}
fireUpdated();
}
});
}
 
public void fireUpdated() {
for (PropertyChangeListener l : this.loadingListener.getListeners(PropertyChangeListener.class)) {
l.propertyChange(null);
}
}
 
public void addListener(PropertyChangeListener l) {
this.loadingListener.add(PropertyChangeListener.class, l);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/AbstractVenteArticleItemTable.java
36,6 → 36,8
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.FieldPath;
import org.openconcerto.sql.model.SQLBackgroundTableCache;
import org.openconcerto.sql.model.SQLBackgroundTableCacheItem;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
1738,6 → 1740,7
}
 
Collection<? extends SQLRowAccessor> cacheRemise = null;
Collection<? extends SQLRowAccessor> cacheRemiseFamille = null;
 
protected BigDecimal getTarifRemiseClient(SQLRowAccessor article, BigDecimal pv) {
if (cacheRemise != null) {
1756,19 → 1759,60
}
 
protected Acompte getRemiseClient(SQLRowAccessor article) {
Acompte remise = new Acompte(BigDecimal.ZERO, BigDecimal.ZERO);
Acompte remise = null;
if (this.cacheRemiseFamille != null) {
if (getRowClient() != null && !getRowClient().isUndefined() && article != null && !article.isUndefined()) {
if (article.getForeign("ID_FAMILLE_ARTICLE") != null && !article.isForeignEmpty("ID_FAMILLE_ARTICLE")) {
Integer fID = article.getForeignID("ID_FAMILLE_ARTICLE");
 
remise = getRemiseFamille(fID);
// TODO faire une fonction recursive avec un test pour eviter les boucles
if (remise == null) {
SQLBackgroundTableCacheItem cacheTableFamille = SQLBackgroundTableCache.getInstance().getCacheForTable(article.getTable().getForeignTable("ID_FAMILLE_ARTICLE"));
SQLRow rowFamille = cacheTableFamille.getRowFromId(fID);
if (rowFamille != null && rowFamille.getObject("ID_FAMILLE_ARTICLE_PERE") != null && !rowFamille.isForeignEmpty("ID_FAMILLE_ARTICLE_PERE")) {
Integer fIDPere = rowFamille.getForeignID("ID_FAMILLE_ARTICLE_PERE");
remise = getRemiseFamille(fIDPere);
if (remise == null) {
SQLRow rowFamille2 = cacheTableFamille.getRowFromId(fIDPere);
if (rowFamille2 != null && rowFamille2.getObject("ID_FAMILLE_ARTICLE_PERE") != null && !rowFamille2.isForeignEmpty("ID_FAMILLE_ARTICLE_PERE")) {
Integer fIDPere2 = rowFamille2.getForeignID("ID_FAMILLE_ARTICLE_PERE");
remise = getRemiseFamille(fIDPere2);
}
}
}
 
}
}
}
}
if (this.cacheRemise != null) {
if (getRowClient() != null && !getRowClient().isUndefined() && article != null && !article.isUndefined()) {
for (SQLRowAccessor sqlRowAccessor : this.cacheRemise) {
if (!sqlRowAccessor.isForeignEmpty("ID_ARTICLE") && sqlRowAccessor.getForeignID("ID_ARTICLE") == article.getID()) {
BigDecimal r = sqlRowAccessor.getBigDecimal("POURCENT_REMISE");
if (remise != null) {
remise = new Acompte(r, null);
break;
}
}
}
}
if (remise == null) {
return new Acompte(BigDecimal.ZERO, BigDecimal.ZERO);
} else {
return remise;
}
}
 
private Acompte getRemiseFamille(int fID) {
Acompte remise = null;
for (SQLRowAccessor sqlRowAccessor : this.cacheRemiseFamille) {
if (!sqlRowAccessor.isForeignEmpty("ID_FAMILLE_ARTICLE") && sqlRowAccessor.getForeignID("ID_FAMILLE_ARTICLE") == fID) {
BigDecimal r = sqlRowAccessor.getBigDecimal("POURCENT_REMISE");
remise = new Acompte(r, null);
break;
}
}
return remise;
}
 
1919,7 → 1963,8
super.setClient(rowClient, ask);
if (getRowClient() != null && !getRowClient().isUndefined()) {
this.cacheRemise = getRowClient().getReferentRows(getSQLElement().getTable().getTable("TARIF_ARTICLE_CLIENT"));
if (ask && this.cacheRemise.size() > 0 && getRowValuesTable().getRowCount() > 0
this.cacheRemiseFamille = getRowClient().getReferentRows(getSQLElement().getTable().getTable("TARIF_FAMILLE_ARTICLE_CLIENT"));
if (ask && (!this.cacheRemise.isEmpty() || !this.cacheRemiseFamille.isEmpty()) && getRowValuesTable().getRowCount() > 0
&& JOptionPane.showConfirmDialog(null, "Appliquer les remises associées au client sur les lignes déjà présentes?") == JOptionPane.YES_OPTION) {
int nbRows = this.table.getRowCount();
for (int i = 0; i < nbRows; i++) {
1943,6 → 1988,7
}
} else {
this.cacheRemise = null;
this.cacheRemiseFamille = null;
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/ui/TotalCalculator.java
572,7 → 572,9
if (compteArticle != null && !compteArticle.isUndefined()) {
cpt = compteArticle;
} else {
SQLRowAccessor familleArticle = article.getForeign("ID_FAMILLE_ARTICLE");
final SQLBackgroundTableCacheItem cacheForTableFamille = SQLBackgroundTableCache.getInstance().getCacheForTable(article.getTable().getForeignTable("ID_FAMILLE_ARTICLE"));
 
SQLRowAccessor familleArticle = cacheForTableFamille.getRowFromId(article.getForeignID("ID_FAMILLE_ARTICLE"));
Set<SQLRowAccessor> unique = new HashSet<SQLRowAccessor>();
while (familleArticle != null && !familleArticle.isUndefined() && !unique.contains(familleArticle)) {
 
584,7 → 586,7
break;
}
}
familleArticle = familleArticle.getForeign("ID_FAMILLE_ARTICLE_PERE");
familleArticle = cacheForTableFamille.getRowFromId(familleArticle.getForeignID("ID_FAMILLE_ARTICLE_PERE"));
}
}
} else {
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/element/NumerotationAutoSQLElement.java
361,6 → 361,13
return getNextCodeLetrrage(s);
}
 
public final String getNextCodeLettragePartiel() {
SQLRow rowNum = this.getTable().getRow(2);
final String string = rowNum.getString("CODE_LETTRAGE_PARTIEL");
String s = (string == null) ? "" : string.trim().toLowerCase();
return getNextCodeLettragePartiel(s);
}
 
public static final String getNextCodeLetrrage(String code) {
code = code.trim();
if (code == null || code.length() == 0) {
394,7 → 401,41
 
}
 
public static final String getNextCodeLettragePartiel(String code) {
code = code.trim();
if (code == null || code.length() == 0) {
return "aaa";
} else {
char[] charArray = code.toCharArray();
char c = 'a';
int i = charArray.length - 1;
while (i >= 0 && (c = charArray[i]) == 'z') {
i--;
}
if (i >= 0) {
c++;
charArray[i] = c;
for (int j = i + 1; j < charArray.length; j++) {
charArray[j] = 'a';
}
code = String.valueOf(charArray);
} else {
// On ajoute une lettre
final StringBuffer buf = new StringBuffer(code.length() + 1);
final int nb = code.length() + 1;
for (int j = 0; j < nb; j++) {
buf.append('a');
}
code = buf.toString();
}
 
return code;
}
 
}
 
private static boolean isNumeroExist(SQLElement element, int num) {
 
if (num < 0) {
return true;
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/common/element/TitrePersonnelSQLElement.java
16,6 → 16,8
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.ComboSQLRequest;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
33,6 → 35,12
}
 
@Override
protected void _initComboRequest(ComboSQLRequest req) {
super._initComboRequest(req);
req.setWhere(new Where(getTable().getField("OBSOLETE"), "=", Boolean.FALSE));
}
@Override
public boolean isShared() {
return true;
}
42,6 → 50,7
l.add("CODE");
l.add("NOM");
l.add("SEXE_M");
l.add("OBSOLETE");
return l;
}
 
/trunk/OpenConcerto/src/org/openconcerto/erp/core/reports/stat/action/ReportingCommercialFournisseurAction.java
New file
0,0 → 1,43
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.core.reports.stat.action;
 
import org.openconcerto.erp.action.CreateFrameAbstractAction;
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.common.ui.PanelFrame;
import org.openconcerto.erp.core.customerrelationship.customer.report.ReportingCommercialFournisseurPanel;
import org.openconcerto.sql.model.DBRoot;
 
import javax.swing.Action;
import javax.swing.JFrame;
 
public class ReportingCommercialFournisseurAction extends CreateFrameAbstractAction {
 
private static final String TITLE = "CA par commercial/fournisseur";
 
private DBRoot root;
 
public ReportingCommercialFournisseurAction(ComptaPropsConfiguration conf) {
super();
this.root = conf.getRootSociete();
this.putValue(Action.NAME, TITLE);
this.mustLoadState = false;
}
 
public JFrame createFrame() {
final PanelFrame panelFrame = new PanelFrame(new ReportingCommercialFournisseurPanel(this.root), TITLE);
panelFrame.setResizable(false);
return panelFrame;
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/core/reports/history/ui/HistoriqueClientFrame.java
56,6 → 56,7
mapList.put("Echéances", Arrays.asList("ECHEANCE_CLIENT"));
mapList.put("Relances", Arrays.asList("RELANCE"));
mapList.put("Devis", Arrays.asList("DEVIS"));
mapList.put("Commandes", Arrays.asList("COMMANDE_CLIENT"));
mapList.put("Avoirs", Arrays.asList("AVOIR_CLIENT"));
mapList.put("Articles facturés", Arrays.asList("SAISIE_VENTE_FACTURE_ELEMENT"));
mapList.put("Articles proposés", Arrays.asList("DEVIS_ELEMENT"));
/trunk/OpenConcerto/src/org/openconcerto/erp/core/supplychain/purchase/importer/FacturXExporter.java
13,16 → 13,25
package org.openconcerto.erp.core.supplychain.purchase.importer;
 
import org.openconcerto.erp.core.finance.payment.element.ModeDeReglementSQLElement;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
 
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
 
import org.jdom2.Document;
import org.jdom2.Element;
34,18 → 43,27
* FacturX export (EN 16931 format)
*/
public class FacturXExporter {
 
private class Tax {
// Taux, ex pour 20% : 20.00
BigDecimal rate;
final BigDecimal rate;
// Montant de la TVA
BigDecimal amount;
BigDecimal amount = BigDecimal.ZERO;
 
// montant HT sur lequel s'applique la TVA
BigDecimal basisAmount;
BigDecimal basisAmount = BigDecimal.ZERO;
 
public Tax(BigDecimal rate) {
this.rate = rate;
}
 
public void add(BigDecimal taxAmount,
 
BigDecimal basisAmount) {
this.amount = this.amount.add(taxAmount);
this.basisAmount = this.basisAmount.add(basisAmount);
}
}
 
public static Namespace QDT_NS = Namespace.getNamespace("qdt", "urn:un:unece:uncefact:data:standard:QualifiedDataType:100");
public static Namespace RAM_NS = Namespace.getNamespace("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100");
public static Namespace RSM_NS = Namespace.getNamespace("rsm", "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100");
56,26 → 74,55
 
FacturXExporter ex = new FacturXExporter();
System.err.println("FacturXExporter.main() " + ex.checkEAN13("5987854125989"));
String xml = ex.createXMLFrom(null, 1);
System.out.println(xml);
// String xml = ex.createXMLFrom(null, 1);
// System.out.println(xml);
}
 
public String createXMLFrom(DBRoot row, int invoiceId) {
DecimalFormat formatAmount = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
 
List<Tax> taxes = new ArrayList<>();
Tax t1 = new Tax();
t1.rate = new BigDecimal("20.0");
t1.amount = new BigDecimal("40.0");
t1.basisAmount = new BigDecimal("200.0");
taxes.add(t1);
private boolean useCommonClient = false;
 
DecimalFormat format = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
public String createXMLFrom(DBRoot dbRoot, int invoiceId, SQLRow societeRow) {
 
SQLTable factureTable = dbRoot.getTable("SAISIE_VENTE_FACTURE");
SQLRowValues rowValsToFetch = new SQLRowValues(factureTable);
rowValsToFetch.putNulls("NUMERO", "DATE", "NOM", "T_TVA", "T_HT", "T_TTC", "NET_A_PAYER");
rowValsToFetch.putRowValues("ID_MODE_REGLEMENT").putNulls("COMPTANT", "AJOURS", "LENJOUR", "DATE_FACTURE", "FIN_MOIS").putRowValues("ID_TYPE_REGLEMENT").putNulls("NOM");
SQLRowValues putRowValuesClient = rowValsToFetch.putRowValues("ID_CLIENT");
putRowValuesClient.putNulls("NOM", "RESPONSABLE", "SIRET", "NUMERO_TVA", "MAIL", "TEL");
if (putRowValuesClient.getTable().contains("ID_CLIENT")) {
this.useCommonClient = true;
putRowValuesClient.putRowValues("ID_CLIENT").putNulls("NOM", "RESPONSABLE", "SIRET", "NUMERO_TVA", "MAIL", "TEL").putRowValues("ID_ADRESSE").putNulls("RUE", "VILLE", "CODE_POSTAL",
"PAYS");
}
putRowValuesClient.putRowValues("ID_ADRESSE").putNulls("RUE", "VILLE", "CODE_POSTAL", "PAYS");
putRowValuesClient.putRowValues("ID_ADRESSE_F").putNulls("RUE", "VILLE", "CODE_POSTAL", "PAYS");
rowValsToFetch.putRowValues("ID_ADRESSE").putNulls("RUE", "VILLE", "CODE_POSTAL", "PAYS");
 
SQLTable factureItemtable = dbRoot.getTable("SAISIE_VENTE_FACTURE_ELEMENT");
SQLRowValues rowValsItemsToFetch = new SQLRowValues(factureItemtable);
 
rowValsItemsToFetch.putNulls("NIVEAU", "CODE", "NOM", "QTE", "QTE_UNITAIRE", "PV_HT", "T_PV_HT", "T_PV_TTC").putRowValues("ID_TAXE").put("TAUX", null);
rowValsItemsToFetch.put("ID_SAISIE_VENTE_FACTURE", rowValsToFetch);
List<SQLRowValues> factures = SQLRowValuesListFetcher.create(rowValsToFetch).fetch(new Where(factureTable.getKey(), "=", invoiceId));
SQLRowValues facture = factures.get(0);
 
Collection<? extends SQLRowAccessor> factureItems = facture.getReferentRows(factureItemtable.getField("ID_SAISIE_VENTE_FACTURE"));
 
Map<Integer, Tax> taxes = new HashMap<>();
 
// Tax t1 = new Tax();
// t1.rate = new BigDecimal("20.0");
// t1.amount = new BigDecimal("40.0");
// t1.basisAmount = new BigDecimal("200.0");
// taxes.add(t1);
 
DecimalFormat fQty = new DecimalFormat("#0.########", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
String invoiceNumber = "-";
Date invoiceDate = new Date();
String regNote = "SARL au capital de 50 000 EUR";
String legNote = "RCS MAVILLE 123 456 789";
int nbLines = 4;
String invoiceNumber = facture.getString("NUMERO");
Date invoiceDate = facture.getDate("DATE").getTime();
String regNote = societeRow.getString("TYPE") + " au capital de " + societeRow.getObject("CAPITAL") + " €";
String legNote = societeRow.getString("RCS");
int nbLines = factureItems.size();
 
final Document doc = new Document();
Element root = new Element("CrossIndustryInvoice", RSM_NS);
132,21 → 179,40
 
// SupplyChainTradeTransaction
Element eSupplyChainTradeTransaction = new Element("SupplyChainTradeTransaction", RSM_NS);
for (int i = 0; i < nbLines; i++) {
String productCode = "a";
String productName = "b";
int lineID = 1;
for (SQLRowAccessor rowItem : factureItems) {
String productCode = rowItem.getString("CODE");
String productName = rowItem.getString("NOM").trim().length() == 0 ? "Ligne" : rowItem.getString("NOM");
 
BigDecimal pHT = new BigDecimal("12.46");
BigDecimal tax = new BigDecimal("0.20");
BigDecimal pTTC = new BigDecimal("14.95");
BigDecimal qte = new BigDecimal("10.0");
BigDecimal totalHTLigne = new BigDecimal("124.60");
final BigDecimal pHT, pTTC, totalHTLigne, totalTTCLigne;
SQLRowAccessor taxeItem = rowItem.getForeign("ID_TAXE");
BigDecimal taxValue = new BigDecimal(taxeItem.getFloat("TAUX")).setScale(2);
if (rowItem.getInt("NIVEAU") != 1) {
pHT = BigDecimal.ZERO;
pTTC = BigDecimal.ZERO;
totalHTLigne = BigDecimal.ZERO;
totalTTCLigne = BigDecimal.ZERO;
} else {
pHT = rowItem.getBigDecimal("PV_HT");
pTTC = pHT.multiply(taxValue.add(BigDecimal.ONE));
totalHTLigne = rowItem.getBigDecimal("T_PV_HT");
totalTTCLigne = rowItem.getBigDecimal("T_PV_TTC");
}
 
int idTaxe = taxeItem.getID();
if (!taxes.containsKey(idTaxe)) {
Tax t = new Tax(taxValue);
taxes.put(idTaxe, t);
}
taxes.get(idTaxe).add(totalTTCLigne.subtract(totalHTLigne), totalHTLigne);
BigDecimal qte = new BigDecimal(rowItem.getInt("QTE")).multiply(rowItem.getBigDecimal("QTE_UNITAIRE"));
 
Element eLineItem = new Element("IncludedSupplyChainTradeLineItem", RAM_NS);
 
// AssociatedDocumentLineDocument
Element eAssociatedDocumentLineDocument = new Element("AssociatedDocumentLineDocument", RAM_NS);
Element eLineID = new Element("LineID", RAM_NS);
eLineID.setText(String.valueOf(i + 1));
eLineID.setText(String.valueOf(lineID++));
eAssociatedDocumentLineDocument.addContent(eLineID);
eLineItem.addContent(eAssociatedDocumentLineDocument);
// SpecifiedTradeProduct
176,11 → 242,11
// Prix unitaire TTC
Element eGrossPriceProductTradePrice = new Element("GrossPriceProductTradePrice", RAM_NS);
Element eChargeAmount = new Element("ChargeAmount", RAM_NS);
eChargeAmount.setText(format.format(pTTC));
eChargeAmount.setText(formatAmount.format(pTTC));
eGrossPriceProductTradePrice.addContent(eChargeAmount);
Element eAppliedTradeAllowanceCharge = new Element("AppliedTradeAllowanceCharge", RAM_NS);
Element eChargeIndicator = new Element("ChargeIndicator", RAM_NS);
Element eIndicator = new Element("ChargeIndicator", UDT_NS);
Element eIndicator = new Element("Indicator", UDT_NS);
// pas de remise
eIndicator.setText("false");
eChargeIndicator.addContent(eIndicator);
188,17 → 254,17
 
Element eActualAmount = new Element("ActualAmount", RAM_NS);
// Montant de TVA (unitaire)
eActualAmount.setText(format.format(pTTC.subtract(pHT)));
eActualAmount.setText(formatAmount.format(pTTC.subtract(pHT)));
 
eAppliedTradeAllowanceCharge.addContent(eActualAmount);
 
eGrossPriceProductTradePrice.addContent(eAppliedTradeAllowanceCharge);
// eGrossPriceProductTradePrice.addContent(eAppliedTradeAllowanceCharge);
 
eSpecifiedLineTradeAgreement.addContent(eGrossPriceProductTradePrice);
// Prix unitaire HT
Element eNetPriceProductTradePrice = new Element("NetPriceProductTradePrice", RAM_NS);
Element eChargeAmountHT = new Element("ChargeAmount", RAM_NS);
eChargeAmountHT.setText(format.format(pHT));
eChargeAmountHT.setText(formatAmount.format(pHT));
 
eNetPriceProductTradePrice.addContent(eChargeAmountHT);
eSpecifiedLineTradeAgreement.addContent(eNetPriceProductTradePrice);
240,7 → 306,7
 
Element eRateApplicablePercent = new Element("RateApplicablePercent", RAM_NS);
// 20% -> 20.0
eRateApplicablePercent.setText(format.format(tax.multiply(new BigDecimal(100))));
eRateApplicablePercent.setText(formatAmount.format(taxValue));
eApplicableTradeTaxt.addContent(eRateApplicablePercent);
 
eSpecifiedLineTradeSettlement.addContent(eApplicableTradeTaxt);
248,7 → 314,7
Element eSpecifiedTradeSettlementLineMonetarySummation = new Element("SpecifiedTradeSettlementLineMonetarySummation", RAM_NS);
// Total HT
Element eLineTotalAmount = new Element("LineTotalAmount", RAM_NS);
eLineTotalAmount.setText(format.format(totalHTLigne));
eLineTotalAmount.setText(formatAmount.format(totalHTLigne));
eSpecifiedTradeSettlementLineMonetarySummation.addContent(eLineTotalAmount);
eSpecifiedLineTradeSettlement.addContent(eSpecifiedTradeSettlementLineMonetarySummation);
 
257,12 → 323,11
eSupplyChainTradeTransaction.addContent(eLineItem);
}
 
addApplicableHeader(eSupplyChainTradeTransaction, taxes);
root.addContent(ed);
addApplicableHeader(societeRow, facture, eSupplyChainTradeTransaction, taxes.values());
 
ed.addContent(eSupplyChainTradeTransaction);
root.addContent(eSupplyChainTradeTransaction);
 
root.addContent(ed);
 
final XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.setFormat(Format.getPrettyFormat());
return xmlOutput.outputString(doc);
273,22 → 338,25
parent.addContent(element);
}
 
private void addApplicableHeader(Element eSupplyChainTradeTransaction, List<Tax> taxes) {
private void addApplicableHeader(SQLRowAccessor rowSociete, SQLRowAccessor rowFacture, Element eSupplyChainTradeTransaction, Collection<Tax> taxes) {
//
// ApplicableHeaderTradeAgreement
//
final Element eApplicableHeaderTradeAgreement = new Element("ApplicableHeaderTradeAgreement", RAM_NS);
addSupplierInfo(eApplicableHeaderTradeAgreement);
addBuyerInfo(eApplicableHeaderTradeAgreement);
addSupplierInfo(eApplicableHeaderTradeAgreement, rowSociete);
addBuyerInfo(eApplicableHeaderTradeAgreement, rowFacture);
 
String orderRef = "";
String contractRef = "";
// Date de livraison, facultative
Date effectiveDeliveryDate = new Date(65454654);
String invoiceNumber = "FA-2017-0010";
Date effectiveDeliveryDate = rowFacture.getDate("DATE").getTime();
String invoiceNumber = rowFacture.getString("NUMERO");
String currencyCode = "EUR";
String dueDescription = "30% d'acompte, solde à 30 j";
Date dueDate = new Date(65455654);
SQLRowAccessor foreignMdr = rowFacture.getForeign("ID_MODE_REGLEMENT");
int ajours = foreignMdr.getInt("AJOURS");
int lenjour = foreignMdr.getInt("LENJOUR");
String dueDescription = (ajours > 0 ? "A " + ajours : "") + (lenjour > 0 ? " le " + lenjour : "");
Date dueDate = ModeDeReglementSQLElement.calculDate(foreignMdr, rowFacture.getDate("DATE").getTime());
 
final Element eBuyerOrderReferencedDocument = new Element("BuyerOrderReferencedDocument", RAM_NS);
addValue(eBuyerOrderReferencedDocument, new Element("IssuerAssignedID", RAM_NS), orderRef);
330,6 → 398,7
addValue(eApplicableHeaderTradeSettlement, new Element("PaymentReference", RAM_NS), invoiceNumber);
addValue(eApplicableHeaderTradeSettlement, new Element("InvoiceCurrencyCode", RAM_NS), currencyCode);
final Element aSpecifiedTradeSettlementPaymentMeans = new Element("SpecifiedTradeSettlementPaymentMeans", RAM_NS);
addValue(aSpecifiedTradeSettlementPaymentMeans, new Element("TypeCode", RAM_NS), "57");
 
// <ram:TypeCode>30</ram:TypeCode>
// <ram:Information>Virement sur compte Banque Fiducial</ram:Information>
380,7 → 449,38
eApplicableHeaderTradeSettlement.addContent(eSpecifiedTradePaymentTerms);
 
final Element eSpecifiedTradeSettlementHeaderMonetarySummation = new Element("SpecifiedTradeSettlementHeaderMonetarySummation", RAM_NS);
final Element eTotalHT = new Element("LineTotalAmount", RAM_NS);
eTotalHT.setText(this.formatAmount.format(new BigDecimal(rowFacture.getLong("T_HT")).movePointLeft(2)));
eSpecifiedTradeSettlementHeaderMonetarySummation.addContent(eTotalHT);
 
final Element eTotalBaseTVA = new Element("TaxBasisTotalAmount", RAM_NS);
 
BigDecimal totalBaseTVA = BigDecimal.ZERO;
for (Tax tax : taxes) {
totalBaseTVA = totalBaseTVA.add(tax.basisAmount);
}
eTotalBaseTVA.setText(this.formatAmount.format(totalBaseTVA));
eSpecifiedTradeSettlementHeaderMonetarySummation.addContent(eTotalBaseTVA);
 
final Element eTotalTVA = new Element("TaxTotalAmount", RAM_NS);
eTotalTVA.setAttribute("currencyID", "EUR");
eTotalTVA.setText(this.formatAmount.format(new BigDecimal(rowFacture.getLong("T_TVA")).movePointLeft(2)));
eSpecifiedTradeSettlementHeaderMonetarySummation.addContent(eTotalTVA);
 
final Element eTotalTTC = new Element("GrandTotalAmount", RAM_NS);
BigDecimal totalTTC = new BigDecimal(rowFacture.getLong("T_TTC")).movePointLeft(2);
eTotalTTC.setText(this.formatAmount.format(totalTTC));
eSpecifiedTradeSettlementHeaderMonetarySummation.addContent(eTotalTTC);
 
final Element eTotalPrepaid = new Element("TotalPrepaidAmount", RAM_NS);
BigDecimal netApayer = new BigDecimal(rowFacture.getLong("NET_A_PAYER")).movePointLeft(2);
eTotalPrepaid.setText(this.formatAmount.format(totalTTC.subtract(netApayer)));
eSpecifiedTradeSettlementHeaderMonetarySummation.addContent(eTotalPrepaid);
 
final Element eTotalDue = new Element("DuePayableAmount", RAM_NS);
eTotalDue.setText(this.formatAmount.format(netApayer));
eSpecifiedTradeSettlementHeaderMonetarySummation.addContent(eTotalDue);
 
// Total HT
// <ram:LineTotalAmount>624.90</ram:LineTotalAmount>
// Total HT sur leque est appliqué la TVA
400,20 → 500,35
 
}
 
private void addBuyerInfo(final Element eApplicableHeaderTradeAgreement) {
private void addBuyerInfo(final Element eApplicableHeaderTradeAgreement, final SQLRowAccessor rowFacture) {
 
SQLRowAccessor client = rowFacture.getForeign("ID_CLIENT");
SQLRowAccessor clientGestion = client;
if (this.useCommonClient) {
client = client.getForeign("ID_CLIENT");
}
final SQLRowAccessor adr;
if (!rowFacture.isForeignEmpty("ID_ADRESSE")) {
adr = rowFacture.getForeign("ID_ADRESSE");
} else if (!clientGestion.isForeignEmpty("ID_ADRESSE_F")) {
adr = clientGestion.getForeign("ID_ADRESSE_F");
} else {
adr = client.getForeign("ID_ADRESSE");
}
 
// Acheteur
String buyerName = "Ma jolie boutique";
String buyerSIRET = "78787878400035";
String buyerVAT = "FR19787878784";
String buyerContactName = "Alexandre Payet";
String buyerPhone = "+33 4 72 07 08 67";
String buyerEmail = "alexandre.payet@majolieboutique.net";
String buyerAddrL1 = "35 rue de la République";
String buyerName = client.getString("NOM");
String buyerSIRET = client.getString("SIRET");
String buyerVAT = client.getString("NUMERO_TVA");
String buyerContactName = client.getString("RESPONSABLE");
String buyerPhone = client.getString("TEL");
String buyerEmail = client.getString("MAIL");
String buyerAddrL1 = adr.getString("RUE");
String buyerAddrL2 = "";
String buyerAddrL3 = "";
String buyerPostalCode = "69001";
String buyerCity = "Lyon";
String buyerCountryCode = "FR";
String buyerPostalCode = adr.getString("CODE_POSTAL");
String buyerCity = adr.getString("VILLE");
String buyerCountryCode = resolveCountryCode(adr.getString("PAYS"));
 
final Element eBuyerTradeParty = new Element("BuyerTradeParty", RAM_NS);
this.addValue(eBuyerTradeParty, new Element("Name", RAM_NS), buyerName);
439,19 → 554,20
eBuyerTradeParty.addContent(eDefinedTradeContact);
// Adresse postale
final Element ePostalTradeAddress = new Element("PostalTradeAddress", RAM_NS);
addValue(ePostalTradeAddress, new Element("LineOne>", RAM_NS), buyerAddrL1);
addValue(ePostalTradeAddress, new Element("PostcodeCode", RAM_NS), buyerPostalCode);
addValue(ePostalTradeAddress, new Element("LineOne", RAM_NS), buyerAddrL1);
if (buyerAddrL2 != null && !buyerAddrL2.trim().isEmpty()) {
addValue(ePostalTradeAddress, new Element("LineTwo>", RAM_NS), buyerAddrL2);
addValue(ePostalTradeAddress, new Element("LineTwo", RAM_NS), buyerAddrL2);
}
if (buyerAddrL3 != null && !buyerAddrL3.trim().isEmpty()) {
addValue(ePostalTradeAddress, new Element("LineThree>", RAM_NS), buyerAddrL3);
addValue(ePostalTradeAddress, new Element("LineThree", RAM_NS), buyerAddrL3);
}
addValue(ePostalTradeAddress, new Element("PostcodeCode>", RAM_NS), buyerPostalCode);
addValue(ePostalTradeAddress, new Element("CityName>", RAM_NS), buyerCity);
addValue(ePostalTradeAddress, new Element("CountryID>", RAM_NS), buyerCountryCode);
addValue(ePostalTradeAddress, new Element("CityName", RAM_NS), buyerCity);
addValue(ePostalTradeAddress, new Element("CountryID", RAM_NS), buyerCountryCode);
 
eBuyerTradeParty.addContent(ePostalTradeAddress);
 
if (buyerVAT != null && buyerVAT.trim().length() > 0) {
// TVA
final Element eSpecifiedTaxRegistration = new Element("SpecifiedTaxRegistration", RAM_NS);
final Element eSpecifiedTaxRegistrationId = new Element("ID", RAM_NS);
459,23 → 575,24
eSpecifiedTaxRegistrationId.setText(buyerVAT);
eSpecifiedTaxRegistration.addContent(eSpecifiedTaxRegistrationId);
eBuyerTradeParty.addContent(eSpecifiedTaxRegistration);
 
}
eApplicableHeaderTradeAgreement.addContent(eBuyerTradeParty);
}
 
private void addSupplierInfo(final Element eApplicableHeaderTradeAgreement) {
String supplierName = "Au bon moulin";
String supplierSIRET = "121321321321";
String supplierContactName = "Tony Dubois";
String supplierContactPhone = "+33 4 72 07 08 56";
String supplierContactEmail = "tony.dubois@aubonmoulin.fr";
String supplierAddrL1 = "3 rue du pont";
private void addSupplierInfo(final Element eApplicableHeaderTradeAgreement, SQLRowAccessor rowSociete) {
String supplierName = rowSociete.getString("NOM");
String supplierSIRET = rowSociete.getString("NUM_SIRET");
String supplierContactName = "";
String supplierContactPhone = rowSociete.getStri